Compare commits
22 Commits
f8fbb3bc4e
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5261f4788 | ||
|
|
e2fbe19d84 | ||
|
|
fe95902a1d | ||
|
|
4d50585cc1 | ||
|
|
ed2fa02d2d | ||
|
|
c405b578ab | ||
|
|
e448951153 | ||
|
|
aa9747be6a | ||
|
|
6817b9b29e | ||
|
|
2a090d02a3 | ||
|
|
1f93815d25 | ||
|
|
d5e812581f | ||
|
|
bdb50989f9 | ||
|
|
e9811ae42b | ||
|
|
95174f8e9c | ||
|
|
b355884260 | ||
|
|
39bef3a351 | ||
|
|
3648e740a0 | ||
|
|
6624110192 | ||
|
|
667f6d997e | ||
|
|
e1aaa0b39f | ||
|
|
98be72fece |
60
StatusManager.gd
Normal file
60
StatusManager.gd
Normal file
@@ -0,0 +1,60 @@
|
||||
class_name StatusManager
|
||||
extends RefCounted
|
||||
|
||||
var _device
|
||||
|
||||
func _init(device):
|
||||
_device = device
|
||||
Callable(_emit_initial_ports).call_deferred()
|
||||
|
||||
|
||||
func _emit_initial_ports() -> void:
|
||||
"""Вывод начального состояния через существующий сигнал UDPBroadcast"""
|
||||
# Просто устанавливаем текущие значения (это вызовет update_isa_ports)
|
||||
var current_106 = _device.get_isa_port(0x106)
|
||||
var current_108 = _device.get_isa_port(0x108)
|
||||
var current_10A = _device.get_isa_port(0x10A)
|
||||
|
||||
# Триггерим обновление через установку тех же значений
|
||||
_device.set_isa_port(0x106, current_106)
|
||||
_device.set_isa_port(0x108, current_108)
|
||||
_device.set_isa_port(0x10A, current_10A)
|
||||
|
||||
# Универсальные методы для работы с битовыми полями
|
||||
func set_status_field(port: int, value: int, bit_mask: int, shift: int = 0) -> void:
|
||||
var current_value = _device.get_isa_port(port)
|
||||
var masked_value = (value & bit_mask) << shift
|
||||
var clear_mask = ~(bit_mask << shift) & 0xFF
|
||||
var new_value = (current_value & clear_mask) | masked_value
|
||||
_device.set_isa_port(port, new_value)
|
||||
|
||||
func get_status_field(port: int, bit_mask: int, shift: int = 0) -> int:
|
||||
return (_device.get_isa_port(port) >> shift) & bit_mask
|
||||
|
||||
# Специфичные методы для каждого статуса
|
||||
func set_dou2_status(status: int) -> void:
|
||||
set_status_field(0x106, status, 0b111, 0)
|
||||
|
||||
func get_dou2_status() -> int:
|
||||
return get_status_field(0x106, 0b111, 0)
|
||||
|
||||
func set_att1_status(status: int) -> void:
|
||||
set_status_field(0x10A, status, 0b111, 0)
|
||||
|
||||
func set_att2_status(status: int) -> void:
|
||||
set_status_field(0x106, status, 0b111, 3)
|
||||
|
||||
func get_att2_status() -> int:
|
||||
return get_status_field(0x106, 0b111, 3)
|
||||
|
||||
func set_dou3_status(status: int) -> void:
|
||||
set_status_field(0x108, status, 0b111, 0)
|
||||
|
||||
func get_dou3_status() -> int:
|
||||
return get_status_field(0x108, 0b111, 0)
|
||||
|
||||
func set_att3_status(status: int) -> void:
|
||||
set_status_field(0x108, status, 0b111, 3)
|
||||
|
||||
func get_att3_status() -> int:
|
||||
return get_status_field(0x108, 0b111, 3)
|
||||
1
StatusManager.gd.uid
Normal file
1
StatusManager.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ddgp4l3kdjwg2
|
||||
136
config/default_data.json
Normal file
136
config/default_data.json
Normal file
@@ -0,0 +1,136 @@
|
||||
{
|
||||
"default_data": {
|
||||
"ПРД-Н1": {
|
||||
"temperature_ukp": [20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31],
|
||||
"power_ukp": [1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011],
|
||||
"sockets": [true, true, true, true, true],
|
||||
"dkm": [false, false, false, false, false, false, false],
|
||||
"dou2": [false, false, false, false, false, false, false],
|
||||
"dou3": [false, false, false, false, false, false, false],
|
||||
"att2": [false, false, false, false, false, false, false, false],
|
||||
"att3": [false, false, false, false, false, false, false, false],
|
||||
"ip": [false, false, false, false, false, false, false, false]
|
||||
},
|
||||
"ПРД-В1": {
|
||||
"temperature_ukp": [20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31],
|
||||
"power_ukp": [1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011],
|
||||
"sockets": [true, true, true, true, true],
|
||||
"dkm": [false, false, false, false, false, false, false],
|
||||
"dou2": [false, false, false, false, false, false, false],
|
||||
"dou3": [false, false, false, false, false, false, false],
|
||||
"att2": [false, false, false, false, false, false, false, false],
|
||||
"att3": [false, false, false, false, false, false, false, false],
|
||||
"ip": [false, false, false, false, false, false, false, false]
|
||||
},
|
||||
"ПРД-К1": {
|
||||
"temperature_ukp": [20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32],
|
||||
"power_ukp": [1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012],
|
||||
"sockets": [true, true, true, true, true],
|
||||
"dkm": [false, false, false, false, false, false, false],
|
||||
"dou2": [false, false, false, false, false, false, false],
|
||||
"dou3": [false, false, false, false, false, false, false],
|
||||
"att2": [false, false, false, false, false, false, false, false],
|
||||
"att3": [false, false, false, false, false, false, false, false],
|
||||
"ip": [false, false, false, false, false, false, false, false]
|
||||
},
|
||||
"ПРД-Н2": {
|
||||
"temperature_ukp": [20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31],
|
||||
"power_ukp": [1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011],
|
||||
"sockets": [false, false, false, false, false],
|
||||
"dkm": [false, false, false, false, false, false, false],
|
||||
"dou2": [false, false, false, false, false, false, false],
|
||||
"dou3": [false, false, false, false, false, false, false],
|
||||
"att2": [false, false, false, false, false, false, false, false],
|
||||
"att3": [false, false, false, false, false, false, false, false],
|
||||
"ip": [false, false, false, false, false, false, false, false]
|
||||
},
|
||||
"ПРД-В2": {
|
||||
"temperature_ukp": [20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31],
|
||||
"power_ukp": [1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011],
|
||||
"sockets": [false, false, false, false, false],
|
||||
"dkm": [false, false, false, false, false, false, false],
|
||||
"dou2": [false, false, false, false, false, false, false],
|
||||
"dou3": [false, false, false, false, false, false, false],
|
||||
"att2": [false, false, false, false, false, false, false, false],
|
||||
"att3": [false, false, false, false, false, false, false, false],
|
||||
"ip": [false, false, false, false, false, false, false, false]
|
||||
},
|
||||
"ПРД-К2": {
|
||||
"temperature_ukp": [20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32],
|
||||
"power_ukp": [1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012],
|
||||
"sockets": [false, false, false, false, false],
|
||||
"dkm": [false, false, false, false, false, false, false],
|
||||
"dou2": [false, false, false, false, false, false, false],
|
||||
"dou3": [false, false, false, false, false, false, false],
|
||||
"att2": [false, false, false, false, false, false, false, false],
|
||||
"att3": [false, false, false, false, false, false, false, false],
|
||||
"ip": [false, false, false, false, false, false, false, false]
|
||||
},
|
||||
"ПРД-Н3": {
|
||||
"temperature_ukp": [20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31],
|
||||
"power_ukp": [1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011],
|
||||
"sockets": [false, false, false, false, false],
|
||||
"dkm": [false, false, false, false, false, false, false],
|
||||
"dou2": [false, false, false, false, false, false, false],
|
||||
"dou3": [false, false, false, false, false, false, false],
|
||||
"att2": [false, false, false, false, false, false, false, false],
|
||||
"att3": [false, false, false, false, false, false, false, false],
|
||||
"ip": [false, false, false, false, false, false, false, false]
|
||||
},
|
||||
"ПРД-В3": {
|
||||
"temperature_ukp": [20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31],
|
||||
"power_ukp": [1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011],
|
||||
"sockets": [false, false, false, false, false],
|
||||
"dkm": [false, false, false, false, false, false, false],
|
||||
"dou2": [false, false, false, false, false, false, false],
|
||||
"dou3": [false, false, false, false, false, false, false],
|
||||
"att2": [false, false, false, false, false, false, false, false],
|
||||
"att3": [false, false, false, false, false, false, false, false],
|
||||
"ip": [false, false, false, false, false, false, false, false]
|
||||
},
|
||||
"ПРД-К3": {
|
||||
"temperature_ukp": [20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32],
|
||||
"power_ukp": [1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012],
|
||||
"sockets": [false, false, false, false, false],
|
||||
"dkm": [false, false, false, false, false, false, false],
|
||||
"dou2": [false, false, false, false, false, false, false],
|
||||
"dou3": [false, false, false, false, false, false, false],
|
||||
"att2": [false, false, false, false, false, false, false, false],
|
||||
"att3": [false, false, false, false, false, false, false, false],
|
||||
"ip": [false, false, false, false, false, false, false, false]
|
||||
},
|
||||
"ПРД-Н4": {
|
||||
"temperature_ukp": [20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31],
|
||||
"power_ukp": [1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011],
|
||||
"sockets": [false, false, false, false, false],
|
||||
"dkm": [false, false, false, false, false, false, false],
|
||||
"dou2": [false, false, false, false, false, false, false],
|
||||
"dou3": [false, false, false, false, false, false, false],
|
||||
"att2": [false, false, false, false, false, false, false, false],
|
||||
"att3": [false, false, false, false, false, false, false, false],
|
||||
"ip": [false, false, false, false, false, false, false, false]
|
||||
},
|
||||
"ПРД-В4": {
|
||||
"temperature_ukp": [20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31],
|
||||
"power_ukp": [1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011],
|
||||
"sockets": [false, false, false, false, false],
|
||||
"dkm": [false, false, false, false, false, false, false],
|
||||
"dou2": [false, false, false, false, false, false, false],
|
||||
"dou3": [false, false, false, false, false, false, false],
|
||||
"att2": [false, false, false, false, false, false, false, false],
|
||||
"att3": [false, false, false, false, false, false, false, false],
|
||||
"ip": [false, false, false, false, false, false, false, false]
|
||||
},
|
||||
"ПРД-К4": {
|
||||
"temperature_ukp": [20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32],
|
||||
"power_ukp": [1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012],
|
||||
"sockets": [false, false, false, false, false],
|
||||
"dkm": [false, false, false, false, false, false, false],
|
||||
"dou2": [false, false, false, false, false, false, false],
|
||||
"dou3": [false, false, false, false, false, false, false],
|
||||
"att2": [false, false, false, false, false, false, false, false],
|
||||
"att3": [false, false, false, false, false, false, false, false],
|
||||
"ip": [false, false, false, false, false, false, false, false]
|
||||
}
|
||||
}
|
||||
}
|
||||
517
main.gd
517
main.gd
@@ -1,27 +1,166 @@
|
||||
extends Control
|
||||
|
||||
const CONFIG_PATH = "res://config/default_data.json"
|
||||
const BUFFER_SIZE = 32
|
||||
var dictionary_yau07: Dictionary
|
||||
var udp_broadcast: UDPBroadcast
|
||||
var uf_broadcast: UF_Broadcast
|
||||
var default_data: Dictionary = {}
|
||||
var dictionary_yau07: Dictionary
|
||||
var dictionary_sockets_bit: Dictionary ## Байт 8 для отправки о состоянии ячеек
|
||||
|
||||
|
||||
func _load_default_data():
|
||||
var file = FileAccess.open(CONFIG_PATH, FileAccess.READ)
|
||||
if file:
|
||||
var json = JSON.new()
|
||||
var error = json.parse(file.get_as_text())
|
||||
if error == OK:
|
||||
default_data = json.data["default_data"]
|
||||
else:
|
||||
push_error("JSON Parse Error: ", json.get_error_message())
|
||||
file.close()
|
||||
else:
|
||||
push_error("Failed to load config file: ", CONFIG_PATH)
|
||||
|
||||
|
||||
func _apply_default_data():
|
||||
var prd_nodes = get_tree().get_nodes_in_group('prd')
|
||||
|
||||
for prd in prd_nodes:
|
||||
var device_name = prd.get_meta('yau07')
|
||||
if default_data.has(device_name):
|
||||
var device_data = default_data[device_name]
|
||||
_fill_ukp_fields(prd, device_data)
|
||||
|
||||
|
||||
# Заполняем поля температур
|
||||
func _fill_ukp_fields(prd_node: Control, device_data: Dictionary) -> void:
|
||||
var device_name = prd_node.get_meta('yau07')
|
||||
|
||||
# Заполняем поля температур
|
||||
var temp_fields = _get_ukp_nodes_for_device(device_name, [prd_node], "temperature_ukp")
|
||||
if device_data.has("temperature_ukp"):
|
||||
for i in range(min(temp_fields.size(), device_data["temperature_ukp"].size())):
|
||||
temp_fields[i].text = str(device_data["temperature_ukp"][i])
|
||||
|
||||
# Заполняем поля мощности
|
||||
var power_fields = _get_ukp_nodes_for_device(device_name, [prd_node], "power_ukp")
|
||||
if device_data.has("power_ukp"):
|
||||
for i in range(min(power_fields.size(), device_data["power_ukp"].size())):
|
||||
power_fields[i].text = str(device_data["power_ukp"][i])
|
||||
|
||||
# Устанавливаем состояния сокетов
|
||||
if device_data.has("sockets"):
|
||||
var socket_fields = _get_ukp_nodes_for_device(device_name, [prd_node], "socket")
|
||||
for i in range(min(socket_fields.size(), device_data["sockets"].size())):
|
||||
socket_fields[i].set_pressed_no_signal(device_data["sockets"][i])
|
||||
|
||||
# Устанавливаем состояния ДКМ
|
||||
if device_data.has("dkm"):
|
||||
var dkm_fields = _get_ukp_nodes_for_device(device_name, [prd_node], "dkm")
|
||||
for i in range(min(dkm_fields.size(), device_data["dkm"].size())):
|
||||
dkm_fields[i].set_pressed_no_signal(device_data["dkm"][i])
|
||||
|
||||
# Устанавливаем состояния ДОУ2
|
||||
if device_data.has("dou2"):
|
||||
var dou2_fields = _get_ukp_nodes_for_device(device_name, [prd_node], "dou2")
|
||||
for i in range(min(dou2_fields.size(), device_data["dou2"].size())):
|
||||
dou2_fields[i].set_pressed_no_signal(device_data["dou2"][i])
|
||||
|
||||
# Устанавливаем состояния ДОУ3
|
||||
if device_data.has("dou3"):
|
||||
var dou3_fields = _get_ukp_nodes_for_device(device_name, [prd_node], "dou3")
|
||||
for i in range(min(dou3_fields.size(), device_data["dou3"].size())):
|
||||
dou3_fields[i].set_pressed_no_signal(device_data["dou3"][i])
|
||||
|
||||
# Устанавливаем состояния аттенюаторов 1
|
||||
if device_data.has("att1"):
|
||||
var att1_fields = _get_ukp_nodes_for_device(device_name, [prd_node], "att1")
|
||||
for i in range(min(att1_fields.size(), device_data["att1"].size())):
|
||||
att1_fields[i].set_pressed_no_signal(device_data["att1"][i])
|
||||
|
||||
# Устанавливаем состояния аттенюаторов 2
|
||||
if device_data.has("att2"):
|
||||
var att2_fields = _get_ukp_nodes_for_device(device_name, [prd_node], "att2")
|
||||
for i in range(min(att2_fields.size(), device_data["att2"].size())):
|
||||
att2_fields[i].set_pressed_no_signal(device_data["att2"][i])
|
||||
|
||||
# Устанавливаем состояния аттенюаторов 3
|
||||
if device_data.has("att3"):
|
||||
var att3_fields = _get_ukp_nodes_for_device(device_name, [prd_node], "att3")
|
||||
for i in range(min(att3_fields.size(), device_data["att3"].size())):
|
||||
att3_fields[i].set_pressed_no_signal(device_data["att3"][i])
|
||||
|
||||
# Устанавливаем состояния источников питания (с инверсией)
|
||||
if device_data.has("ip"):
|
||||
var ip_fields = _get_ukp_nodes_for_device(device_name, [prd_node], "ip")
|
||||
for i in range(min(ip_fields.size(), device_data["ip"].size())):
|
||||
# Для IP используется инверсия: true в JSON = нажато = бит 0
|
||||
var is_pressed = not device_data["ip"][i]
|
||||
ip_fields[i].set_pressed_no_signal(is_pressed)
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
var device_yau07: Array = get_tree().get_nodes_in_group('device-addr')
|
||||
for device in device_yau07:
|
||||
device.connect('toggled', on_modify_device.bind(device.get_meta('device')))
|
||||
|
||||
var sockets: Array = get_tree().get_nodes_in_group('socket')
|
||||
for soc in sockets:
|
||||
soc.connect('toggled', _on_modify_sockets.bind(soc.get_meta('bit'), soc.get_meta('device'))) ## Мета bit от 0 до 3, мета ПРД
|
||||
|
||||
var power_ukp: Array = get_tree().get_nodes_in_group('power_ukp')
|
||||
for socket_power in power_ukp:
|
||||
var power_ukp_arr_node: Array = get_tree().get_nodes_in_group('power_ukp')
|
||||
for socket_power in power_ukp_arr_node:
|
||||
socket_power.connect('text_submitted', _on_ukp_submitted.bind(socket_power.get_meta('device')))
|
||||
|
||||
var temperature_ukp: Array = get_tree().get_nodes_in_group('temperature_ukp')
|
||||
for socket_temp in temperature_ukp:
|
||||
var temperature_ukp_arr_node: Array = get_tree().get_nodes_in_group('temperature_ukp')
|
||||
for socket_temp in temperature_ukp_arr_node:
|
||||
socket_temp.connect('text_submitted', _on_ukp_submitted.bind(socket_temp.get_meta('device')))
|
||||
|
||||
var dkm_arr_node: Array = get_tree().get_nodes_in_group('dkm')
|
||||
for dkm in dkm_arr_node:
|
||||
dkm.connect('toggled', _on_modify_dkm.bind(dkm.get_meta('bit'), dkm.get_meta('device')))
|
||||
|
||||
var dou2_arr_node: Array = get_tree().get_nodes_in_group('dou2')
|
||||
for dou2 in dou2_arr_node:
|
||||
dou2.toggled.connect(_on_modify_status.bind(dou2.get_meta('bit'), dou2.get_meta('device'), "dou2"))
|
||||
|
||||
var dou3_arr_node: Array = get_tree().get_nodes_in_group('dou3')
|
||||
for dou3 in dou3_arr_node:
|
||||
dou3.toggled.connect(_on_modify_status.bind(dou3.get_meta('bit'), dou3.get_meta('device'), "dou3"))
|
||||
|
||||
var att1_arr_node: Array = get_tree().get_nodes_in_group('att1')
|
||||
for att1 in att1_arr_node:
|
||||
att1.toggled.connect(_on_modify_status.bind(att1.get_meta('bit'), att1.get_meta('device'), "att1"))
|
||||
|
||||
var att2_arr_node: Array = get_tree().get_nodes_in_group('att2')
|
||||
for att2 in att2_arr_node:
|
||||
att2.toggled.connect(_on_modify_status.bind(att2.get_meta('bit'), att2.get_meta('device'), "att2"))
|
||||
|
||||
var att3_arr_node: Array = get_tree().get_nodes_in_group('att3')
|
||||
for att3 in att3_arr_node:
|
||||
att3.toggled.connect(_on_modify_status.bind(att3.get_meta('bit'), att3.get_meta('device'), "att3"))
|
||||
|
||||
var ip_arr_node: Array = get_tree().get_nodes_in_group('ip')
|
||||
for ip in ip_arr_node:
|
||||
ip.connect('toggled', _on_modify_ip.bind(ip.get_meta('bit'), ip.get_meta('device')))
|
||||
|
||||
var ems_arr_node: Array = get_tree().get_nodes_in_group('ems_g')
|
||||
for ems in ems_arr_node:
|
||||
ems.connect('bits_changed', _on_modify_ems_g_status.bind(ems.get_meta('device')))
|
||||
|
||||
$uf_button.connect('toggled', on_modify_uf.bind($uf_button.get_meta('device')))
|
||||
for bit in get_tree().get_nodes_in_group('uf_status'):
|
||||
bit.connect('toggled', _on_update_uf_status.bind(bit.get_meta('bit')))
|
||||
_update_tab_container()
|
||||
_load_default_data()
|
||||
_apply_default_data()
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
for device in dictionary_yau07:
|
||||
dictionary_yau07[device]._on_poll_timeout()
|
||||
|
||||
|
||||
func _exit_tree():
|
||||
for device in dictionary_yau07:
|
||||
@@ -31,119 +170,311 @@ func _exit_tree():
|
||||
|
||||
func on_modify_device(toggled: bool, name_device: String) -> void:
|
||||
if toggled:
|
||||
udp_broadcast = UDPBroadcast.new(name_device)
|
||||
udp_broadcast.add_timer_to_scene(self)
|
||||
var logger_node: Node
|
||||
for node in get_tree().get_nodes_in_group('logger'):
|
||||
if node.get_meta('device') == name_device:
|
||||
logger_node = node
|
||||
break
|
||||
udp_broadcast = UDPBroadcast.new(name_device, logger_node)
|
||||
udp_broadcast.add_timers_to_scene(self)
|
||||
udp_broadcast.start_broadcast()
|
||||
dictionary_yau07[name_device] = udp_broadcast
|
||||
print("Устройство %s активировано" % name_device)
|
||||
dictionary_yau07[name_device].connect('update_isa_ports', _on_update_isa_ports)
|
||||
dictionary_yau07[name_device].connect('update_socket_status', _on_update_socket_status)
|
||||
var device_data = default_data[name_device]
|
||||
_on_ukp_submitted('', name_device)
|
||||
dictionary_yau07[name_device].status_manager.set_dou2_status(bool_array_to_number(device_data["dou2"]))
|
||||
dictionary_yau07[name_device].status_manager.set_att2_status(bool_array_to_number(device_data["att2"]))
|
||||
dictionary_yau07[name_device].status_manager.set_dou3_status(bool_array_to_number(device_data["dou3"]))
|
||||
dictionary_yau07[name_device].status_manager.set_att3_status(bool_array_to_number(device_data["att3"]))
|
||||
dictionary_yau07[name_device].set_ip_status(bool_array_to_number(device_data["ip"]))
|
||||
dictionary_yau07[name_device].set_sockets_status(bool_array_to_number(device_data["sockets"]))
|
||||
else:
|
||||
dictionary_yau07[name_device].close_udp_unit()
|
||||
if dictionary_yau07.has(name_device) and dictionary_yau07[name_device]:
|
||||
dictionary_yau07[name_device].close_udp_unit()
|
||||
dictionary_yau07.erase(name_device)
|
||||
print("Устройство %s деактивировано" % name_device)
|
||||
|
||||
# Обновляем вкладки и переключаемся при активации
|
||||
_update_tab_container(toggled, name_device)
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
for device in dictionary_yau07:
|
||||
if dictionary_yau07[device]:
|
||||
dictionary_yau07[device].poll_receive()
|
||||
func on_modify_uf(toggled: bool, name_device: String) -> void:
|
||||
if toggled:
|
||||
uf_broadcast = UF_Broadcast.new(name_device)
|
||||
uf_broadcast.add_timers_to_scene(self)
|
||||
uf_broadcast.start_broadcast()
|
||||
dictionary_yau07[name_device] = uf_broadcast
|
||||
print("Устройство %s активировано" % name_device)
|
||||
else:
|
||||
if dictionary_yau07.has(name_device) and dictionary_yau07[name_device]:
|
||||
dictionary_yau07[name_device].close_udp_unit()
|
||||
dictionary_yau07.erase(name_device)
|
||||
print("Устройство %s деактивировано" % name_device)
|
||||
|
||||
|
||||
static func _set_bit(bits: int, index: int, val: bool) -> int:
|
||||
return bits | (1 << index) if val else bits & ~(1 << index)
|
||||
func _update_tab_container(just_activated: bool = false, activated_device: String = ""):
|
||||
var tab_container = $TabContainer
|
||||
var device_nodes = get_tree().get_nodes_in_group('device-addr')
|
||||
var has_visible_tabs = false
|
||||
|
||||
for i in range(tab_container.get_tab_count()):
|
||||
var tab_control = tab_container.get_tab_control(i)
|
||||
var device_name = tab_control.get_meta('yau07', '')
|
||||
|
||||
var device_button = null
|
||||
for device in device_nodes:
|
||||
if device.get_meta('device') == device_name:
|
||||
device_button = device
|
||||
break
|
||||
|
||||
if device_button:
|
||||
var is_enabled = device_button.button_pressed
|
||||
tab_container.set_tab_disabled(i, !is_enabled)
|
||||
|
||||
if is_enabled:
|
||||
has_visible_tabs = true
|
||||
if just_activated and device_name == activated_device:
|
||||
tab_container.current_tab = i
|
||||
|
||||
tab_container.visible = has_visible_tabs
|
||||
|
||||
|
||||
func _on_update_socket_status(status: int, device_name: String)->void:
|
||||
var socket_arr = _get_nodes_for_device(device_name, 'socket')
|
||||
for socket in socket_arr:
|
||||
var bit_index = socket.get_meta('bit')
|
||||
var is_bit_set = (status >> bit_index) & 1
|
||||
socket.set_pressed_no_signal(is_bit_set == 1)
|
||||
|
||||
|
||||
func _on_update_uf_status(toggled: bool, bit_index: int)->void:
|
||||
if not dictionary_yau07.has('УФ'): return
|
||||
var status = dictionary_yau07['УФ'].get_status_uf()
|
||||
if bit_index == 6:
|
||||
status = dictionary_yau07['УФ'].get_power_bit_uf()
|
||||
|
||||
if toggled: # Установить бит в 1
|
||||
status = status | (1 << bit_index)
|
||||
else: # Сбросить бит в 0
|
||||
status = status & ~(1 << bit_index)
|
||||
|
||||
if bit_index == 6: dictionary_yau07['УФ'].set_power_bit_uf(status)
|
||||
else: dictionary_yau07['УФ'].set_status_uf(status)
|
||||
|
||||
|
||||
func _on_update_isa_ports(isa_ports: Dictionary, device_name: String)->void:
|
||||
for port_addr in isa_ports:
|
||||
var value = isa_ports[port_addr]
|
||||
|
||||
var port_configs = {
|
||||
0x106: [ # Порт 0x106
|
||||
{'group': 'dou2', 'mask': 0b111, 'shift': 0},
|
||||
{'group': 'att2', 'mask': 0b111, 'shift': 3}
|
||||
],
|
||||
0x108: [ # Порт 0x108
|
||||
{'group': 'dou3', 'mask': 0b111, 'shift': 0},
|
||||
{'group': 'att3', 'mask': 0b111, 'shift': 3}
|
||||
],
|
||||
0x10A: [ # Порт 0x10A
|
||||
{'group': 'att1', 'mask': 0b111, 'shift': 0}
|
||||
]
|
||||
}
|
||||
|
||||
if port_configs.has(port_addr):
|
||||
for config in port_configs[port_addr]:
|
||||
var status = (value >> config.shift) & config.mask
|
||||
_update_specific_device_buttons(config.group, status, device_name)
|
||||
|
||||
|
||||
func _update_specific_device_buttons(group_name: String, status: int, target_device: String) -> void:
|
||||
"""Обновление кнопок только для конкретного устройства"""
|
||||
var buttons = _get_nodes_for_device(target_device, group_name)
|
||||
|
||||
for button in buttons:
|
||||
if button.has_meta('bit'):
|
||||
var bit_value = button.get_meta('bit')
|
||||
var should_be_pressed = (status == bit_value)
|
||||
|
||||
if button.button_pressed != should_be_pressed:
|
||||
button.set_pressed_no_signal(should_be_pressed)
|
||||
if should_be_pressed:
|
||||
button.grab_focus()
|
||||
|
||||
|
||||
func _get_nodes_for_device(device: String, group_name: String) -> Array:
|
||||
"""Получение всех нод в группе, принадлежащих указанному устройству"""
|
||||
var prd_nodes = get_tree().get_nodes_in_group('prd')
|
||||
var result = []
|
||||
|
||||
for prd in prd_nodes:
|
||||
if prd.get_meta('yau07') == device:
|
||||
for node in get_tree().get_nodes_in_group(group_name):
|
||||
if prd.is_ancestor_of(node) and node.get_meta('device') == device:
|
||||
result.append(node)
|
||||
break
|
||||
return result
|
||||
|
||||
|
||||
## Функция для установки статусов ячеек на связи (УГ, ЭМС-Г, УКП)
|
||||
func _on_modify_sockets(toggled: bool, bit: int, device: String)->void:
|
||||
if dictionary_yau07.has(device):
|
||||
var udp_unit = dictionary_yau07[device]
|
||||
udp_unit.sockets_status_bit = _set_bit(udp_unit.sockets_status_bit, bit, toggled)
|
||||
var current_status = udp_unit.get_sockets_status() # Используем геттер
|
||||
var new_status = _set_bit(current_status, bit, toggled)
|
||||
udp_unit.set_sockets_status(new_status) # Используем сеттер
|
||||
print("Статус сокетов устройства %s обновлен: 0x%02X" % [device, new_status])
|
||||
|
||||
|
||||
## Функция для установки статусов ДКМ в ПРД
|
||||
func _on_modify_dkm(toggled: bool, bit: int, device: String)->void:
|
||||
if dictionary_yau07.has(device):
|
||||
var udp_unit = dictionary_yau07[device]
|
||||
var current_status = udp_unit.get_dkm_status() # Используем геттер
|
||||
var new_status = _set_bit(current_status, bit, toggled)
|
||||
udp_unit.set_dkm_status(new_status) # Используем сеттер
|
||||
print("Статус DKM устройства %s обновлен: 0x%02X" % [device, new_status])
|
||||
|
||||
|
||||
func _on_modify_ems_g_status(input_impulse: int, input_const: int, output_impulse: int, output_const: int, device: String)->void:
|
||||
if not dictionary_yau07.has(device):
|
||||
return
|
||||
var udp_unit = dictionary_yau07[device]
|
||||
udp_unit.set_ems_g_status(input_impulse, input_const, output_impulse, output_const)
|
||||
|
||||
|
||||
func _on_modify_status(toggled: bool, bit: int, device: String, status_type: String) -> void:
|
||||
if not dictionary_yau07.has(device):
|
||||
return
|
||||
|
||||
var udp_unit = dictionary_yau07[device]
|
||||
var button_group = _get_nodes_for_device(device, status_type)
|
||||
|
||||
if not toggled:
|
||||
# Восстанавливаем предыдущее состояние
|
||||
for button in button_group:
|
||||
if button.has_meta('bit') and button.get_meta('bit') == bit:
|
||||
button.set_pressed(true)
|
||||
return
|
||||
|
||||
# Выключаем другие кнопки в группе
|
||||
for button in button_group:
|
||||
if button.has_meta('bit') and button.get_meta('bit') != bit and button.button_pressed:
|
||||
button.set_pressed_no_signal(false)
|
||||
# Устанавливаем статус через менеджер
|
||||
match status_type:
|
||||
"dou2": udp_unit.status_manager.set_dou2_status(bit)
|
||||
"att1": udp_unit.status_manager.set_att1_status(bit)
|
||||
"att2": udp_unit.status_manager.set_att2_status(bit)
|
||||
"dou3": udp_unit.status_manager.set_dou3_status(bit)
|
||||
"att3": udp_unit.status_manager.set_att3_status(bit)
|
||||
|
||||
|
||||
func _on_modify_ip(toggled: bool, bit: int, device: String):
|
||||
if dictionary_yau07.has(device):
|
||||
var udp_unit = dictionary_yau07[device]
|
||||
var current_status = udp_unit.get_ip_status()
|
||||
# Инверсия: нажата = 0, отжата = 1
|
||||
var bit_value = 0 if toggled else 1
|
||||
var new_status
|
||||
if bit_value == 0: new_status = current_status & ~(1 << bit) # Устанавливаем бит в 0
|
||||
else: new_status = current_status | (1 << bit) # Устанавливаем бит в 1
|
||||
|
||||
udp_unit.set_ip_status(new_status)
|
||||
print("Статус ИП устройства %s обновлен: 0x%02X" % [device, new_status])
|
||||
|
||||
|
||||
## Функция для установки значений в ячейках УКП
|
||||
func _on_ukp_submitted(_new_text: String, device: String) -> void:
|
||||
if not dictionary_yau07.has(device):
|
||||
return
|
||||
|
||||
var prep_temperature_ukp1_array: Array = _on_text_temperature_changed(device, 1)
|
||||
var prep_temperature_ukp2_array: Array = _on_text_temperature_changed(device, 2)
|
||||
|
||||
var prep_power_ukp1_array: Array = _on_text_power_changed(device, 1)
|
||||
var prep_power_ukp2_array: Array = _on_text_power_changed(device, 2)
|
||||
var prep_power_ukp2_array: Array = _on_text_power_changed(device, 2)
|
||||
|
||||
var combine_data_ukp1: Array
|
||||
combine_data_ukp1 = _combine_arrays(combine_data_ukp1, prep_temperature_ukp1_array, prep_power_ukp1_array)
|
||||
var combine_data_ukp2: Array
|
||||
combine_data_ukp2 = _combine_arrays(combine_data_ukp2, prep_temperature_ukp2_array, prep_power_ukp2_array)
|
||||
_form_buffers(device,combine_data_ukp1, 1, dictionary_yau07)
|
||||
_form_buffers(device,combine_data_ukp2, 2, dictionary_yau07)
|
||||
var combine_data_ukp1: Array = _combine_arrays(prep_temperature_ukp1_array, prep_power_ukp1_array)
|
||||
var combine_data_ukp2: Array = _combine_arrays(prep_temperature_ukp2_array, prep_power_ukp2_array)
|
||||
|
||||
_form_buffers(device, combine_data_ukp1, 1, dictionary_yau07)
|
||||
_form_buffers(device, combine_data_ukp2, 2, dictionary_yau07)
|
||||
|
||||
|
||||
func _on_text_temperature_changed(device: String, number_device: int) -> Array:
|
||||
return _process_ukp_data(device, number_device, "temperature_ukp", _convert_temperature)
|
||||
|
||||
func _on_text_power_changed(device: String, number_device: int) -> Array:
|
||||
return _process_ukp_data(device, number_device, "power_ukp", _convert_power)
|
||||
|
||||
|
||||
func _process_ukp_data(device: String, number_device: int, group_name: String, converter: Callable) -> Array:
|
||||
var prd_module_arr = get_tree().get_nodes_in_group('prd')
|
||||
var current_change_nodes: Array = _get_ukp_nodes_for_device(device, prd_module_arr, group_name)
|
||||
var result_arr: Array = [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]
|
||||
var config: Dictionary = _get_ukp_config(number_device)
|
||||
|
||||
for change_node in current_change_nodes:
|
||||
var place = change_node.get_meta('place')
|
||||
if change_node.get_meta('place') in config.meta_range:
|
||||
if number_device == 2: place -= 8
|
||||
var value = _safe_convert_to_int(change_node.text)
|
||||
result_arr[place] = converter.call(value)
|
||||
return result_arr
|
||||
|
||||
|
||||
static func _get_ukp_nodes_for_device(device: String, prd_module_arr: Array, group_name: String) -> Array:
|
||||
for prd in prd_module_arr:
|
||||
if device == prd.get_meta('yau07'):
|
||||
var nodes = []
|
||||
for node in prd.get_tree().get_nodes_in_group(group_name):
|
||||
if prd.is_ancestor_of(node):
|
||||
nodes.append(node)
|
||||
return nodes
|
||||
return []
|
||||
|
||||
|
||||
static func _get_ukp_config(number_device: int) -> Dictionary:
|
||||
if number_device == 1:
|
||||
return {
|
||||
"meta_range": [0, 1, 2, 3 ,4, 5, 6, 7]
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"meta_range": [8, 9, 10, 11, 12, 13, 14, 15]
|
||||
}
|
||||
|
||||
|
||||
static func _convert_temperature(value: int) -> int:
|
||||
const CONST_MIN_TEMP: int = -25
|
||||
const MAXIMUM_CODE_ADC: int = 3796
|
||||
const MINIMUM_CODE_AD: int = 2660
|
||||
const TEMP: float = 115.0 / (MAXIMUM_CODE_ADC - MINIMUM_CODE_AD)
|
||||
const TEMP: float = 115.0 / (MAXIMUM_CODE_ADC - MINIMUM_CODE_AD)
|
||||
|
||||
var current_change: Array
|
||||
for prd in get_tree().get_nodes_in_group('prd'):
|
||||
if device == prd.get_meta('yau07'):
|
||||
for temperature_node in prd.get_tree().get_nodes_in_group('temperature_ukp'):
|
||||
if prd.is_ancestor_of(temperature_node):
|
||||
current_change.append(temperature_node)
|
||||
break
|
||||
|
||||
var temp_arr: Array = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
|
||||
if number_device == 1:
|
||||
for i in 6:
|
||||
if not current_change[i].text == null:
|
||||
var value = _safe_convert_to_int(current_change[i].text)
|
||||
var normal_temp: int = MAXIMUM_CODE_ADC - (value - CONST_MIN_TEMP - 3) / TEMP
|
||||
temp_arr[i] = normal_temp
|
||||
elif number_device == 2:
|
||||
for i in 6:
|
||||
if not current_change[i+6].text == null:
|
||||
var value = _safe_convert_to_int(current_change[i+6].text)
|
||||
var normal_temp: int = MAXIMUM_CODE_ADC - (value - CONST_MIN_TEMP - 3) / TEMP
|
||||
temp_arr[i] = normal_temp
|
||||
return temp_arr
|
||||
var result: float = MAXIMUM_CODE_ADC - (value - CONST_MIN_TEMP - 3) / TEMP
|
||||
return int(result)
|
||||
|
||||
|
||||
func _on_text_power_changed(device: String, number_device: int) -> Array:
|
||||
var current_change: Array
|
||||
for prd in get_tree().get_nodes_in_group('prd'):
|
||||
if device == prd.get_meta('yau07'):
|
||||
for power_node in prd.get_tree().get_nodes_in_group('power_ukp'):
|
||||
if prd.is_ancestor_of(power_node):
|
||||
current_change.append(power_node)
|
||||
break
|
||||
|
||||
var power_arr: Array = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
|
||||
|
||||
if number_device == 1:
|
||||
for i in 6:
|
||||
if not current_change[i].text == null:
|
||||
var value = _safe_convert_to_int(current_change[i].text)
|
||||
power_arr[i] = value
|
||||
elif number_device == 2:
|
||||
for i in 6:
|
||||
if not current_change[i+6].text == null:
|
||||
var value = _safe_convert_to_int(current_change[i+6].text)
|
||||
power_arr[i] = value
|
||||
|
||||
return power_arr
|
||||
#_update_buffers(power_arr_1, device)
|
||||
static func _convert_power(value: int) -> int:
|
||||
return value
|
||||
|
||||
|
||||
static func _safe_convert_to_int(text: String) -> int:
|
||||
text = text.strip_edges()
|
||||
text = text.strip_edges().to_lower()
|
||||
if text.is_valid_int():
|
||||
return int(text)
|
||||
elif text.is_valid_float():
|
||||
return roundi(float(text))
|
||||
elif text.begins_with("0x") and text.substr(2).is_valid_hex_number():
|
||||
return text.hex_to_int()
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
static func _combine_arrays(ukp_data: Array, power_arr: Array, temp_arr: Array)-> Array:
|
||||
for i in temp_arr.size():
|
||||
ukp_data.append(temp_arr[i])
|
||||
for i in power_arr.size():
|
||||
ukp_data.append(power_arr[i])
|
||||
return ukp_data
|
||||
static func _combine_arrays(power_arr: Array, temp_arr: Array)-> Array:
|
||||
return temp_arr + power_arr
|
||||
|
||||
|
||||
static func _form_buffers(device: String, ukp_data: Array, number_device: int, dic_yau07: Dictionary):
|
||||
@@ -155,5 +486,39 @@ static func _form_buffers(device: String, ukp_data: Array, number_device: int, d
|
||||
var udp_unit = dic_yau07[device]
|
||||
if number_device == 1:
|
||||
udp_unit.ukp0_data = buffer
|
||||
print("Данные UKP0 устройства %s обновлены" % device)
|
||||
elif number_device == 2:
|
||||
udp_unit.ukp1_data = buffer
|
||||
print("Данные UKP1 устройства %s обновлены" % device)
|
||||
|
||||
|
||||
static func _set_bit(bits: int, index: int, val: bool) -> int:
|
||||
return bits | (1 << index) if val else bits & ~(1 << index)
|
||||
|
||||
|
||||
static func bool_array_to_number(bool_array: Array)-> int:
|
||||
var result: int = 0
|
||||
for i in range(bool_array.size()):
|
||||
if bool_array[i]:
|
||||
result |= (1 << i)
|
||||
return result
|
||||
|
||||
|
||||
## Метод для работы с ISA портами
|
||||
func read_isa_ports(device: String, port_addresses: Array) -> Dictionary:
|
||||
"""Чтение ISA портов указанного устройства"""
|
||||
if dictionary_yau07.has(device):
|
||||
return dictionary_yau07[device].read_isa_ports(port_addresses)
|
||||
else:
|
||||
push_error("Устройство %s не найдено" % device)
|
||||
return {}
|
||||
|
||||
|
||||
## Метод для записи ISA портов
|
||||
func write_isa_port(device: String, port_address: int, value: int) -> bool:
|
||||
"""Запись значения в ISA порт указанного устройства"""
|
||||
if dictionary_yau07.has(device):
|
||||
return dictionary_yau07[device].set_isa_port(port_address, value)
|
||||
else:
|
||||
push_error("Устройство %s не найдено" % device)
|
||||
return false
|
||||
|
||||
19
main_radial_gradient.gdshader
Normal file
19
main_radial_gradient.gdshader
Normal file
@@ -0,0 +1,19 @@
|
||||
shader_type canvas_item;
|
||||
|
||||
uniform float outerRadius : hint_range(0.0, 50.0) = 1.0;
|
||||
uniform float MainAlpha : hint_range(0.0, 1.0) = 1.0;
|
||||
uniform vec4 circle_color : source_color = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
uniform vec4 circle_color2 : source_color = vec4(0.0, 0.0, 1.0, 1.0);
|
||||
|
||||
void fragment() {
|
||||
float x = abs(UV.x-.35)*2.0;
|
||||
float y = abs(UV.y-.3)*2.0;
|
||||
float v = (sqrt((x*x)+(y*y))/outerRadius);
|
||||
|
||||
// Плавный переход прозрачности
|
||||
float alpha = 1.0 - smoothstep(0.0, 1.0, v);
|
||||
|
||||
// Создаем градиент от circle_color к circle_color2
|
||||
vec4 gradient_color = mix(circle_color, circle_color2, v);
|
||||
COLOR = vec4(gradient_color.rgb, alpha * MainAlpha * gradient_color.a);
|
||||
}
|
||||
1
main_radial_gradient.gdshader.uid
Normal file
1
main_radial_gradient.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cp2p2g3mgxm8o
|
||||
@@ -17,10 +17,5 @@ config/icon="res://icon.svg"
|
||||
|
||||
[display]
|
||||
|
||||
window/size/viewport_width=1200
|
||||
window/size/viewport_height=600
|
||||
|
||||
[rendering]
|
||||
|
||||
renderer/rendering_method="gl_compatibility"
|
||||
renderer/rendering_method.mobile="gl_compatibility"
|
||||
window/size/viewport_width=1500
|
||||
window/size/viewport_height=850
|
||||
|
||||
21
sockets/ems_g/socket_status.gd
Normal file
21
sockets/ems_g/socket_status.gd
Normal file
@@ -0,0 +1,21 @@
|
||||
extends PanelContainer
|
||||
|
||||
@onready var animated_sprite = $SZI_x
|
||||
signal update_frame(bit: int, frame: int)
|
||||
|
||||
func _ready():
|
||||
gui_input.connect(_on_gui_input)
|
||||
mouse_filter = Control.MOUSE_FILTER_PASS
|
||||
|
||||
func _on_gui_input(event):
|
||||
if event is InputEventMouseButton:
|
||||
if event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
|
||||
_switch_frame()
|
||||
|
||||
|
||||
func _switch_frame():
|
||||
var current_frame = animated_sprite.frame
|
||||
var next_frame = (current_frame + 1) % 3
|
||||
animated_sprite.frame = next_frame
|
||||
emit_signal('update_frame', get_meta("bit"), next_frame)
|
||||
|
||||
1
sockets/ems_g/socket_status.gd.uid
Normal file
1
sockets/ems_g/socket_status.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bg8n8wt3kjqpm
|
||||
46
sockets/ems_g/socket_status.tscn
Normal file
46
sockets/ems_g/socket_status.tscn
Normal file
@@ -0,0 +1,46 @@
|
||||
[gd_scene load_steps=7 format=3 uid="uid://dn3jp4r8ij3rf"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://cwabmu3cljbpr" path="res://sockets/ems_g/эмс-бланк.png" id="1_bsrew"]
|
||||
[ext_resource type="Script" uid="uid://bg8n8wt3kjqpm" path="res://sockets/ems_g/socket_status.gd" id="1_kydjn"]
|
||||
[ext_resource type="Texture2D" uid="uid://sx6xcpus2yf" path="res://sockets/ems_g/эмс-бланк-пост.png" id="2_b2kjm"]
|
||||
[ext_resource type="Texture2D" uid="uid://snpqhalopnp" path="res://sockets/ems_g/эмс-бланк-перем.png" id="3_odpjv"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_q1ixs"]
|
||||
bg_color = Color(0, 0, 0, 0.490196)
|
||||
corner_radius_top_left = 5
|
||||
corner_radius_top_right = 5
|
||||
corner_radius_bottom_right = 5
|
||||
corner_radius_bottom_left = 5
|
||||
|
||||
[sub_resource type="SpriteFrames" id="SpriteFrames_a7q1i"]
|
||||
animations = [{
|
||||
"frames": [{
|
||||
"duration": 1.0,
|
||||
"texture": ExtResource("1_bsrew")
|
||||
}, {
|
||||
"duration": 1.0,
|
||||
"texture": ExtResource("2_b2kjm")
|
||||
}, {
|
||||
"duration": 1.0,
|
||||
"texture": ExtResource("3_odpjv")
|
||||
}, {
|
||||
"duration": 1.0,
|
||||
"texture": null
|
||||
}],
|
||||
"loop": true,
|
||||
"name": &"default",
|
||||
"speed": 5.0
|
||||
}]
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer"]
|
||||
custom_minimum_size = Vector2(50, 35)
|
||||
offset_left = -3.0
|
||||
offset_right = 47.0
|
||||
offset_bottom = 35.0
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_q1ixs")
|
||||
script = ExtResource("1_kydjn")
|
||||
|
||||
[node name="SZI_x" type="AnimatedSprite2D" parent="."]
|
||||
position = Vector2(25, 17)
|
||||
scale = Vector2(1.2, 1.2)
|
||||
sprite_frames = SubResource("SpriteFrames_a7q1i")
|
||||
341
sockets/ems_g/емс-г-В.tscn
Normal file
341
sockets/ems_g/емс-г-В.tscn
Normal file
@@ -0,0 +1,341 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://bhh0m5tbxjfmy"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://dn3jp4r8ij3rf" path="res://sockets/ems_g/socket_status.tscn" id="2_fbuee"]
|
||||
|
||||
[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_deko5"]
|
||||
|
||||
[node name="ЕМС-Г" type="Panel" groups=["ems_g"]]
|
||||
offset_top = -8.0
|
||||
offset_bottom = -8.0
|
||||
theme_override_styles/panel = SubResource("StyleBoxTexture_deko5")
|
||||
metadata/_tab_index = 3
|
||||
metadata/device = "ПРД-В1"
|
||||
|
||||
[node name="output" type="GridContainer" parent="."]
|
||||
layout_mode = 2
|
||||
offset_left = 161.0
|
||||
offset_top = 15.0
|
||||
offset_right = 1021.0
|
||||
offset_bottom = 77.0
|
||||
columns = 16
|
||||
|
||||
[node name="Label" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "СИ1"
|
||||
|
||||
[node name="Label2" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "СИ2"
|
||||
|
||||
[node name="Label3" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "СИ3"
|
||||
|
||||
[node name="Label4" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "Мод1"
|
||||
|
||||
[node name="Label5" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "Мод2"
|
||||
|
||||
[node name="Label6" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "Мод3"
|
||||
|
||||
[node name="Label7" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label8" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label9" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "ФГОЗ"
|
||||
|
||||
[node name="Label10" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "ФГОЗ"
|
||||
|
||||
[node name="Label11" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "МодМ"
|
||||
|
||||
[node name="Label12" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label13" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label14" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label15" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label16" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="PanelContainer0" parent="output" groups=["output"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 0
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="PanelContainer1" parent="output" groups=["output"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 1
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="PanelContainer2" parent="output" groups=["output"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 2
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="PanelContainer3" parent="output" groups=["output"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 3
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="PanelContainer4" parent="output" groups=["output"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 4
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="PanelContainer5" parent="output" groups=["output"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 5
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="PanelContainer6" parent="output" groups=["output"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 6
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="PanelContainer7" parent="output" groups=["output"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 7
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="PanelContainer8" parent="output" groups=["output"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 8
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="PanelContainer9" parent="output" groups=["output"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 9
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="PanelContainer10" parent="output" groups=["output"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 10
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="PanelContainer11" parent="output" groups=["output"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 11
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="PanelContainer12" parent="output" groups=["output"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 12
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="PanelContainer13" parent="output" groups=["output"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 13
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="PanelContainer14" parent="output" groups=["output"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 14
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="PanelContainer15" parent="output" groups=["output"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 15
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="input" type="GridContainer" parent="."]
|
||||
layout_mode = 2
|
||||
offset_left = 9.0
|
||||
offset_top = 83.0
|
||||
offset_right = 155.0
|
||||
offset_bottom = 703.0
|
||||
columns = 2
|
||||
|
||||
[node name="Label" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СЗИ1 от УФ"
|
||||
|
||||
[node name="PanelContainer0" parent="input" groups=["input"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 0
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="Label2" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СЗИ2 от УФ"
|
||||
|
||||
[node name="PanelContainer1" parent="input" groups=["input"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 1
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="Label3" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СЗИ3 от УФ"
|
||||
|
||||
[node name="PanelContainer2" parent="input" groups=["input"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 2
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="Label4" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СЗИ4 от УФ"
|
||||
|
||||
[node name="PanelContainer3" parent="input" groups=["input"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 3
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="Label5" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СЗИ5 от УФ"
|
||||
|
||||
[node name="PanelContainer4" parent="input" groups=["input"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 4
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="Label6" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СЗИ6 от УФ"
|
||||
|
||||
[node name="PanelContainer5" parent="input" groups=["input"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 5
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="Label7" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СЗИ7 от УФ"
|
||||
|
||||
[node name="PanelContainer6" parent="input" groups=["input"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 6
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="Label8" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "Х"
|
||||
|
||||
[node name="PanelContainer7" parent="input" groups=["input"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 7
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="Label9" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СИ1 от ФС"
|
||||
|
||||
[node name="PanelContainer8" parent="input" groups=["input"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 8
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="Label10" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СИ2 от ФС"
|
||||
|
||||
[node name="PanelContainer9" parent="input" groups=["input"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 9
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="Label11" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СИ3 от ФС"
|
||||
|
||||
[node name="PanelContainer10" parent="input" groups=["input"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 10
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="Label12" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СИ4 от ФС"
|
||||
|
||||
[node name="PanelContainer11" parent="input" groups=["input"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 11
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="Label13" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СИ5 от ФС"
|
||||
|
||||
[node name="PanelContainer12" parent="input" groups=["input"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 12
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="Label14" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СИ6 от ФС"
|
||||
|
||||
[node name="PanelContainer13" parent="input" groups=["input"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 13
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="Label15" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СИ7 от ФС"
|
||||
|
||||
[node name="PanelContainer14" parent="input" groups=["input"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 14
|
||||
metadata/device = "ПРД-В"
|
||||
|
||||
[node name="Label16" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "Х"
|
||||
|
||||
[node name="PanelContainer15" parent="input" groups=["input"] instance=ExtResource("2_fbuee")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 15
|
||||
metadata/device = "ПРД-В"
|
||||
342
sockets/ems_g/емс-г-К.tscn
Normal file
342
sockets/ems_g/емс-г-К.tscn
Normal file
@@ -0,0 +1,342 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://pq47qp2lye4o"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://jyoti1htitwg" path="res://sockets/ems_g/емс_г_к.gd" id="1_rhd7l"]
|
||||
[ext_resource type="PackedScene" uid="uid://dn3jp4r8ij3rf" path="res://sockets/ems_g/socket_status.tscn" id="2_0kk21"]
|
||||
|
||||
[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_deko5"]
|
||||
|
||||
[node name="ЕМС-Г" type="Panel" groups=["ems_g"]]
|
||||
visible = false
|
||||
theme_override_styles/panel = SubResource("StyleBoxTexture_deko5")
|
||||
script = ExtResource("1_rhd7l")
|
||||
metadata/_tab_index = 4
|
||||
metadata/device = "ПРД-К1"
|
||||
|
||||
[node name="output" type="GridContainer" parent="."]
|
||||
layout_mode = 2
|
||||
offset_left = 161.0
|
||||
offset_top = 15.0
|
||||
offset_right = 1021.0
|
||||
offset_bottom = 77.0
|
||||
columns = 16
|
||||
|
||||
[node name="Label" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "СИ1"
|
||||
|
||||
[node name="Label2" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "СИ2"
|
||||
|
||||
[node name="Label3" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "СИ3"
|
||||
|
||||
[node name="Label4" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "Мод1"
|
||||
|
||||
[node name="Label5" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "Мод2"
|
||||
|
||||
[node name="Label6" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "Мод3"
|
||||
|
||||
[node name="Label7" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label8" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label9" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "ФГОЗ"
|
||||
|
||||
[node name="Label10" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "ФГОЗ"
|
||||
|
||||
[node name="Label11" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "МодМ"
|
||||
|
||||
[node name="Label12" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label13" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label14" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label15" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label16" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="PanelContainer0" parent="output" groups=["output"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 0
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="PanelContainer1" parent="output" groups=["output"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 1
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="PanelContainer2" parent="output" groups=["output"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 2
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="PanelContainer3" parent="output" groups=["output"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 3
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="PanelContainer4" parent="output" groups=["output"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 4
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="PanelContainer5" parent="output" groups=["output"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 5
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="PanelContainer6" parent="output" groups=["output"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 6
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="PanelContainer7" parent="output" groups=["output"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 7
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="PanelContainer8" parent="output" groups=["output"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 8
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="PanelContainer9" parent="output" groups=["output"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 9
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="PanelContainer10" parent="output" groups=["output"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 10
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="PanelContainer11" parent="output" groups=["output"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 11
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="PanelContainer12" parent="output" groups=["output"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 12
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="PanelContainer13" parent="output" groups=["output"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 13
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="PanelContainer14" parent="output" groups=["output"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 14
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="PanelContainer15" parent="output" groups=["output"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 15
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="input" type="GridContainer" parent="."]
|
||||
layout_mode = 2
|
||||
offset_left = 9.0
|
||||
offset_top = 83.0
|
||||
offset_right = 155.0
|
||||
offset_bottom = 703.0
|
||||
columns = 2
|
||||
|
||||
[node name="Label" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СЗИ1 от УФ"
|
||||
|
||||
[node name="PanelContainer0" parent="input" groups=["input"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 0
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="Label2" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СЗИ2 от УФ"
|
||||
|
||||
[node name="PanelContainer1" parent="input" groups=["input"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 1
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="Label3" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СЗИ3 от УФ"
|
||||
|
||||
[node name="PanelContainer2" parent="input" groups=["input"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 2
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="Label4" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СЗИ4 от УФ"
|
||||
|
||||
[node name="PanelContainer3" parent="input" groups=["input"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 3
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="Label5" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СЗИ5 от УФ"
|
||||
|
||||
[node name="PanelContainer4" parent="input" groups=["input"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 4
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="Label6" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СЗИ6 от УФ"
|
||||
|
||||
[node name="PanelContainer5" parent="input" groups=["input"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 5
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="Label7" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СЗИ7 от УФ"
|
||||
|
||||
[node name="PanelContainer6" parent="input" groups=["input"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 6
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="Label8" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "Х"
|
||||
|
||||
[node name="PanelContainer7" parent="input" groups=["input"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 7
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="Label9" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СИ1 от ФС"
|
||||
|
||||
[node name="PanelContainer8" parent="input" groups=["input"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 8
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="Label10" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СИ2 от ФС"
|
||||
|
||||
[node name="PanelContainer9" parent="input" groups=["input"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 9
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="Label11" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СИ3 от ФС"
|
||||
|
||||
[node name="PanelContainer10" parent="input" groups=["input"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 10
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="Label12" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СИ4 от ФС"
|
||||
|
||||
[node name="PanelContainer11" parent="input" groups=["input"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 11
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="Label13" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СИ5 от ФС"
|
||||
|
||||
[node name="PanelContainer12" parent="input" groups=["input"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 12
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="Label14" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СИ6 от ФС"
|
||||
|
||||
[node name="PanelContainer13" parent="input" groups=["input"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 13
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="Label15" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СИ7 от ФС"
|
||||
|
||||
[node name="PanelContainer14" parent="input" groups=["input"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 14
|
||||
metadata/device = "ПРД-К"
|
||||
|
||||
[node name="Label16" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "Х"
|
||||
|
||||
[node name="PanelContainer15" parent="input" groups=["input"] instance=ExtResource("2_0kk21")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 15
|
||||
metadata/device = "ПРД-К"
|
||||
341
sockets/ems_g/емс-г-Н.tscn
Normal file
341
sockets/ems_g/емс-г-Н.tscn
Normal file
@@ -0,0 +1,341 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://2rjgbflmbi7e"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://dn3jp4r8ij3rf" path="res://sockets/ems_g/socket_status.tscn" id="1_deko5"]
|
||||
|
||||
[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_deko5"]
|
||||
|
||||
[node name="ЕМС-Г" type="Panel"]
|
||||
offset_top = -9.0
|
||||
offset_right = 789.0
|
||||
offset_bottom = 386.0
|
||||
theme_override_styles/panel = SubResource("StyleBoxTexture_deko5")
|
||||
metadata/_tab_index = 3
|
||||
|
||||
[node name="output" type="GridContainer" parent="."]
|
||||
layout_mode = 2
|
||||
offset_left = 161.0
|
||||
offset_top = 15.0
|
||||
offset_right = 1021.0
|
||||
offset_bottom = 77.0
|
||||
columns = 16
|
||||
|
||||
[node name="Label" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "СИ1"
|
||||
|
||||
[node name="Label2" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "СИ2"
|
||||
|
||||
[node name="Label3" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "СИ3"
|
||||
|
||||
[node name="Label4" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "Мод1"
|
||||
|
||||
[node name="Label5" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "Мод2"
|
||||
|
||||
[node name="Label6" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "Мод3"
|
||||
|
||||
[node name="Label7" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label8" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label9" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "ФГОЗ"
|
||||
|
||||
[node name="Label10" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "ФГОЗ"
|
||||
|
||||
[node name="Label11" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
text = "МодМ"
|
||||
|
||||
[node name="Label12" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label13" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label14" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label15" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label16" type="Label" parent="output"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="PanelContainer0" parent="output" groups=["output"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 0
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="PanelContainer1" parent="output" groups=["output"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 1
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="PanelContainer2" parent="output" groups=["output"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 2
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="PanelContainer3" parent="output" groups=["output"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 3
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="PanelContainer4" parent="output" groups=["output"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 4
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="PanelContainer5" parent="output" groups=["output"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 5
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="PanelContainer6" parent="output" groups=["output"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 6
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="PanelContainer7" parent="output" groups=["output"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 7
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="PanelContainer8" parent="output" groups=["output"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 8
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="PanelContainer9" parent="output" groups=["output"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 9
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="PanelContainer10" parent="output" groups=["output"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 10
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="PanelContainer11" parent="output" groups=["output"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 11
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="PanelContainer12" parent="output" groups=["output"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 12
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="PanelContainer13" parent="output" groups=["output"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 13
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="PanelContainer14" parent="output" groups=["output"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 14
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="PanelContainer15" parent="output" groups=["output"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 15
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="input" type="GridContainer" parent="."]
|
||||
layout_mode = 2
|
||||
offset_left = 9.0
|
||||
offset_top = 83.0
|
||||
offset_right = 155.0
|
||||
offset_bottom = 703.0
|
||||
columns = 2
|
||||
|
||||
[node name="Label" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СЗИ1 от УФ"
|
||||
|
||||
[node name="PanelContainer0" parent="input" groups=["input"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 0
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="Label2" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СЗИ2 от УФ"
|
||||
|
||||
[node name="PanelContainer1" parent="input" groups=["input"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 1
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="Label3" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СЗИ3 от УФ"
|
||||
|
||||
[node name="PanelContainer2" parent="input" groups=["input"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 2
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="Label4" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СЗИ4 от УФ"
|
||||
|
||||
[node name="PanelContainer3" parent="input" groups=["input"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 3
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="Label5" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СЗИ5 от УФ"
|
||||
|
||||
[node name="PanelContainer4" parent="input" groups=["input"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 4
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="Label6" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СЗИ6 от УФ"
|
||||
|
||||
[node name="PanelContainer5" parent="input" groups=["input"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 5
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="Label7" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СЗИ7 от УФ"
|
||||
|
||||
[node name="PanelContainer6" parent="input" groups=["input"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 6
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="Label8" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "Х"
|
||||
|
||||
[node name="PanelContainer7" parent="input" groups=["input"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 7
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="Label9" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СИ1 от ФС"
|
||||
|
||||
[node name="PanelContainer8" parent="input" groups=["input"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 8
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="Label10" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СИ2 от ФС"
|
||||
|
||||
[node name="PanelContainer9" parent="input" groups=["input"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 9
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="Label11" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СИ3 от ФС"
|
||||
|
||||
[node name="PanelContainer10" parent="input" groups=["input"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 10
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="Label12" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СИ4 от ФС"
|
||||
|
||||
[node name="PanelContainer11" parent="input" groups=["input"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 11
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="Label13" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СИ5 от ФС"
|
||||
|
||||
[node name="PanelContainer12" parent="input" groups=["input"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 12
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="Label14" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СИ6 от ФС"
|
||||
|
||||
[node name="PanelContainer13" parent="input" groups=["input"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 13
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="Label15" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "СИ7 от ФС"
|
||||
|
||||
[node name="PanelContainer14" parent="input" groups=["input"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 14
|
||||
metadata/device = "ПРД-Н"
|
||||
|
||||
[node name="Label16" type="Label" parent="input"]
|
||||
layout_mode = 2
|
||||
text = "Х"
|
||||
|
||||
[node name="PanelContainer15" parent="input" groups=["input"] instance=ExtResource("1_deko5")]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
metadata/bit = 15
|
||||
metadata/device = "ПРД-Н"
|
||||
96
sockets/ems_g/емс_г_в.gd
Normal file
96
sockets/ems_g/емс_г_в.gd
Normal file
@@ -0,0 +1,96 @@
|
||||
extends Panel
|
||||
|
||||
@onready var output_status = $output
|
||||
# Константы состояний фреймов
|
||||
const DEVICE: String = 'ПРД-В'
|
||||
const FRAME_OFF := 0
|
||||
const FRAME_CONST := 1
|
||||
const FRAME_IMPULSE := 2
|
||||
|
||||
var _input_impulse: int = 0
|
||||
var _input_const: int = 0
|
||||
var _output_impulse: int = 0
|
||||
var _output_const: int = 0
|
||||
|
||||
#region Сигналы для уведомления об изменениях
|
||||
signal input_bits_updated(input_impulse: int, input_const: int)
|
||||
signal output_bits_updated(output_impulse: int, output_const: int)
|
||||
signal bits_changed(input_impulse: int, input_const: int, output_impulse: int, output_const: int)
|
||||
#endregion
|
||||
|
||||
func _ready():
|
||||
_setup_connections()
|
||||
|
||||
|
||||
func _setup_connections():
|
||||
var _all_input_nodes = get_tree().get_nodes_in_group('input')
|
||||
var _all_outputs_nodes= get_tree().get_nodes_in_group('output')
|
||||
var _filtered_inputs = _all_input_nodes.filter(
|
||||
func(node): return node.get_meta('device') == DEVICE)
|
||||
var _filtered_outputs = _all_outputs_nodes.filter(
|
||||
func(node): return node.get_meta('device') == DEVICE)
|
||||
|
||||
for node in _filtered_inputs:
|
||||
if node.has_signal('update_frame'):
|
||||
node.update_frame.connect(on_update_frame_input)
|
||||
|
||||
for node in _filtered_outputs:
|
||||
if node.has_signal('update_frame'):
|
||||
node.update_frame.connect(on_update_frame_output)
|
||||
|
||||
|
||||
func on_update_frame_input(bit: int, frame: int)-> void:
|
||||
var mask = 1 << bit
|
||||
var old_impulse = _input_impulse
|
||||
var old_const = _input_const
|
||||
_input_impulse = _input_impulse & ~mask | (mask if frame == FRAME_IMPULSE else 0)
|
||||
_input_const = _input_const & ~mask | (mask if frame == FRAME_CONST else 0)
|
||||
# Отправляем сигналы только если значения изменились
|
||||
if _input_impulse != old_impulse || _input_const != old_const:
|
||||
input_bits_updated.emit(get_input_impulse(), get_input_const())
|
||||
bits_changed.emit(get_input_impulse(), get_input_const(), get_output_impulse(), get_output_const())
|
||||
|
||||
|
||||
func on_update_frame_output(bit: int, frame: int)-> void:
|
||||
var mask = 1 << bit
|
||||
var old_impulse = _output_impulse
|
||||
var old_const = _output_const
|
||||
_output_impulse = _output_impulse & ~mask | (mask if frame == FRAME_IMPULSE else 0)
|
||||
_output_const = _output_const & ~mask | (mask if frame == FRAME_CONST else 0)
|
||||
# Отправляем сигналы только если значения изменились
|
||||
if _output_impulse != old_impulse || _output_const != old_const:
|
||||
output_bits_updated.emit(get_output_impulse(), get_output_const())
|
||||
bits_changed.emit(get_input_impulse(), get_input_const(), get_output_impulse(), get_output_const())
|
||||
|
||||
|
||||
func _invert_bits(value: int) -> int:
|
||||
'''Инвертирует все биты (0 становится 0xFFFF, 0xFFFF становится 0)'''
|
||||
return value ^ 0xFFFF
|
||||
|
||||
|
||||
#region Геттеры для безопасного доступа к данным
|
||||
func get_input_impulse() -> int:
|
||||
return _input_impulse
|
||||
|
||||
|
||||
func get_input_const() -> int:
|
||||
return _input_const
|
||||
|
||||
|
||||
func get_output_impulse() -> int:
|
||||
return _output_impulse
|
||||
|
||||
|
||||
func get_output_const() -> int:
|
||||
return _output_const
|
||||
#endregion
|
||||
|
||||
#region Функция для получения всех данных сразу
|
||||
func get_all_bits() -> Dictionary:
|
||||
return {
|
||||
'input_impulse': _input_impulse,
|
||||
'input_const': _input_const,
|
||||
'output_impulse': _output_impulse,
|
||||
'output_const': _output_const
|
||||
}
|
||||
#endregion
|
||||
1
sockets/ems_g/емс_г_в.gd.uid
Normal file
1
sockets/ems_g/емс_г_в.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cgtvbvw1xfqay
|
||||
96
sockets/ems_g/емс_г_к.gd
Normal file
96
sockets/ems_g/емс_г_к.gd
Normal file
@@ -0,0 +1,96 @@
|
||||
extends Panel
|
||||
|
||||
@onready var output_status = $output
|
||||
# Константы состояний фреймов
|
||||
const DEVICE: String = 'ПРД-К'
|
||||
const FRAME_OFF := 0
|
||||
const FRAME_CONST := 1
|
||||
const FRAME_IMPULSE := 2
|
||||
|
||||
var _input_impulse: int = 0
|
||||
var _input_const: int = 0
|
||||
var _output_impulse: int = 0
|
||||
var _output_const: int = 0
|
||||
|
||||
#region Сигналы для уведомления об изменениях
|
||||
signal input_bits_updated(input_impulse: int, input_const: int)
|
||||
signal output_bits_updated(output_impulse: int, output_const: int)
|
||||
signal bits_changed(input_impulse: int, input_const: int, output_impulse: int, output_const: int)
|
||||
#endregion
|
||||
|
||||
func _ready():
|
||||
_setup_connections()
|
||||
|
||||
|
||||
func _setup_connections():
|
||||
var _all_input_nodes = get_tree().get_nodes_in_group('input')
|
||||
var _all_outputs_nodes= get_tree().get_nodes_in_group('output')
|
||||
var _filtered_inputs = _all_input_nodes.filter(
|
||||
func(node): return node.get_meta('device') == DEVICE)
|
||||
var _filtered_outputs = _all_outputs_nodes.filter(
|
||||
func(node): return node.get_meta('device') == DEVICE)
|
||||
|
||||
for node in _filtered_inputs:
|
||||
if node.has_signal('update_frame'):
|
||||
node.update_frame.connect(on_update_frame_input)
|
||||
|
||||
for node in _filtered_outputs:
|
||||
if node.has_signal('update_frame'):
|
||||
node.update_frame.connect(on_update_frame_output)
|
||||
|
||||
|
||||
func on_update_frame_input(bit: int, frame: int)-> void:
|
||||
var mask = 1 << bit
|
||||
var old_impulse = _input_impulse
|
||||
var old_const = _input_const
|
||||
_input_impulse = _input_impulse & ~mask | (mask if frame == FRAME_IMPULSE else 0)
|
||||
_input_const = _input_const & ~mask | (mask if frame == FRAME_CONST else 0)
|
||||
# Отправляем сигналы только если значения изменились
|
||||
if _input_impulse != old_impulse || _input_const != old_const:
|
||||
input_bits_updated.emit(get_input_impulse(), get_input_const())
|
||||
bits_changed.emit(get_input_impulse(), get_input_const(), get_output_impulse(), get_output_const())
|
||||
|
||||
|
||||
func on_update_frame_output(bit: int, frame: int)-> void:
|
||||
var mask = 1 << bit
|
||||
var old_impulse = _output_impulse
|
||||
var old_const = _output_const
|
||||
_output_impulse = _output_impulse & ~mask | (mask if frame == FRAME_IMPULSE else 0)
|
||||
_output_const = _output_const & ~mask | (mask if frame == FRAME_CONST else 0)
|
||||
# Отправляем сигналы только если значения изменились
|
||||
if _output_impulse != old_impulse || _output_const != old_const:
|
||||
output_bits_updated.emit(get_output_impulse(), get_output_const())
|
||||
bits_changed.emit(get_input_impulse(), get_input_const(), get_output_impulse(), get_output_const())
|
||||
|
||||
|
||||
func _invert_bits(value: int) -> int:
|
||||
'''Инвертирует все биты (0 становится 0xFFFF, 0xFFFF становится 0)'''
|
||||
return value ^ 0xFFFF
|
||||
|
||||
|
||||
#region Геттеры для безопасного доступа к данным
|
||||
func get_input_impulse() -> int:
|
||||
return _input_impulse
|
||||
|
||||
|
||||
func get_input_const() -> int:
|
||||
return _input_const
|
||||
|
||||
|
||||
func get_output_impulse() -> int:
|
||||
return _output_impulse
|
||||
|
||||
|
||||
func get_output_const() -> int:
|
||||
return _output_const
|
||||
#endregion
|
||||
|
||||
#region Функция для получения всех данных сразу
|
||||
func get_all_bits() -> Dictionary:
|
||||
return {
|
||||
'input_impulse': _input_impulse,
|
||||
'input_const': _input_const,
|
||||
'output_impulse': _output_impulse,
|
||||
'output_const': _output_const
|
||||
}
|
||||
#endregion
|
||||
1
sockets/ems_g/емс_г_к.gd.uid
Normal file
1
sockets/ems_g/емс_г_к.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://jyoti1htitwg
|
||||
96
sockets/ems_g/емс_г_н.gd
Normal file
96
sockets/ems_g/емс_г_н.gd
Normal file
@@ -0,0 +1,96 @@
|
||||
extends Panel
|
||||
|
||||
@onready var output_status = $output
|
||||
# Константы состояний фреймов
|
||||
const DEVICE: String = 'ПРД-Н'
|
||||
const FRAME_OFF := 0
|
||||
const FRAME_CONST := 1
|
||||
const FRAME_IMPULSE := 2
|
||||
|
||||
var _input_impulse: int = 0
|
||||
var _input_const: int = 0
|
||||
var _output_impulse: int = 0
|
||||
var _output_const: int = 0
|
||||
|
||||
#region Сигналы для уведомления об изменениях
|
||||
signal input_bits_updated(input_impulse: int, input_const: int)
|
||||
signal output_bits_updated(output_impulse: int, output_const: int)
|
||||
signal bits_changed(input_impulse: int, input_const: int, output_impulse: int, output_const: int)
|
||||
#endregion
|
||||
|
||||
func _ready():
|
||||
_setup_connections()
|
||||
|
||||
|
||||
func _setup_connections():
|
||||
var _all_input_nodes = get_tree().get_nodes_in_group('input')
|
||||
var _all_outputs_nodes= get_tree().get_nodes_in_group('output')
|
||||
var _filtered_inputs = _all_input_nodes.filter(
|
||||
func(node): return node.get_meta('device') == DEVICE)
|
||||
var _filtered_outputs = _all_outputs_nodes.filter(
|
||||
func(node): return node.get_meta('device') == DEVICE)
|
||||
|
||||
for node in _filtered_inputs:
|
||||
if node.has_signal('update_frame'):
|
||||
node.update_frame.connect(on_update_frame_input)
|
||||
|
||||
for node in _filtered_outputs:
|
||||
if node.has_signal('update_frame'):
|
||||
node.update_frame.connect(on_update_frame_output)
|
||||
|
||||
|
||||
func on_update_frame_input(bit: int, frame: int)-> void:
|
||||
var mask = 1 << bit
|
||||
var old_impulse = _input_impulse
|
||||
var old_const = _input_const
|
||||
_input_impulse = _input_impulse & ~mask | (mask if frame == FRAME_IMPULSE else 0)
|
||||
_input_const = _input_const & ~mask | (mask if frame == FRAME_CONST else 0)
|
||||
# Отправляем сигналы только если значения изменились
|
||||
if _input_impulse != old_impulse || _input_const != old_const:
|
||||
input_bits_updated.emit(get_input_impulse(), get_input_const())
|
||||
bits_changed.emit(get_input_impulse(), get_input_const(), get_output_impulse(), get_output_const())
|
||||
|
||||
|
||||
func on_update_frame_output(bit: int, frame: int)-> void:
|
||||
var mask = 1 << bit
|
||||
var old_impulse = _output_impulse
|
||||
var old_const = _output_const
|
||||
_output_impulse = _output_impulse & ~mask | (mask if frame == FRAME_IMPULSE else 0)
|
||||
_output_const = _output_const & ~mask | (mask if frame == FRAME_CONST else 0)
|
||||
# Отправляем сигналы только если значения изменились
|
||||
if _output_impulse != old_impulse || _output_const != old_const:
|
||||
output_bits_updated.emit(get_output_impulse(), get_output_const())
|
||||
bits_changed.emit(get_input_impulse(), get_input_const(), get_output_impulse(), get_output_const())
|
||||
|
||||
|
||||
func _invert_bits(value: int) -> int:
|
||||
'''Инвертирует все биты (0 становится 0xFFFF, 0xFFFF становится 0)'''
|
||||
return value ^ 0xFFFF
|
||||
|
||||
|
||||
#region Геттеры для безопасного доступа к данным
|
||||
func get_input_impulse() -> int:
|
||||
return _input_impulse
|
||||
|
||||
|
||||
func get_input_const() -> int:
|
||||
return _input_const
|
||||
|
||||
|
||||
func get_output_impulse() -> int:
|
||||
return _output_impulse
|
||||
|
||||
|
||||
func get_output_const() -> int:
|
||||
return _output_const
|
||||
#endregion
|
||||
|
||||
#region Функция для получения всех данных сразу
|
||||
func get_all_bits() -> Dictionary:
|
||||
return {
|
||||
'input_impulse': _input_impulse,
|
||||
'input_const': _input_const,
|
||||
'output_impulse': _output_impulse,
|
||||
'output_const': _output_const
|
||||
}
|
||||
#endregion
|
||||
1
sockets/ems_g/емс_г_н.gd.uid
Normal file
1
sockets/ems_g/емс_г_н.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b3hcliukdo2wm
|
||||
BIN
sockets/ems_g/эмс-бланк-перем.png
Executable file
BIN
sockets/ems_g/эмс-бланк-перем.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 704 B |
34
sockets/ems_g/эмс-бланк-перем.png.import
Normal file
34
sockets/ems_g/эмс-бланк-перем.png.import
Normal file
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://snpqhalopnp"
|
||||
path="res://.godot/imported/эмс-бланк-перем.png-91f487c2526e52fdad35ee87d52f0d71.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://sockets/ems_g/эмс-бланк-перем.png"
|
||||
dest_files=["res://.godot/imported/эмс-бланк-перем.png-91f487c2526e52fdad35ee87d52f0d71.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
BIN
sockets/ems_g/эмс-бланк-пост.png
Executable file
BIN
sockets/ems_g/эмс-бланк-пост.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 483 B |
34
sockets/ems_g/эмс-бланк-пост.png.import
Normal file
34
sockets/ems_g/эмс-бланк-пост.png.import
Normal file
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://sx6xcpus2yf"
|
||||
path="res://.godot/imported/эмс-бланк-пост.png-7c8eb3ac5e6dec0cbe7af0e932cdf19f.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://sockets/ems_g/эмс-бланк-пост.png"
|
||||
dest_files=["res://.godot/imported/эмс-бланк-пост.png-7c8eb3ac5e6dec0cbe7af0e932cdf19f.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
BIN
sockets/ems_g/эмс-бланк.png
Executable file
BIN
sockets/ems_g/эмс-бланк.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 787 B |
34
sockets/ems_g/эмс-бланк.png.import
Normal file
34
sockets/ems_g/эмс-бланк.png.import
Normal file
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cwabmu3cljbpr"
|
||||
path="res://.godot/imported/эмс-бланк.png-15fb9a2c8256ce49f20eda63d19d1abc.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://sockets/ems_g/эмс-бланк.png"
|
||||
dest_files=["res://.godot/imported/эмс-бланк.png-15fb9a2c8256ce49f20eda63d19d1abc.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
717
udp_broadcast.gd
717
udp_broadcast.gd
@@ -1,143 +1,638 @@
|
||||
class_name UDPBroadcast
|
||||
|
||||
const addres_list: Dictionary = {
|
||||
'ПРД-Н1': [50011, "10.1.1.11"],
|
||||
'ПРД-В1': [50012, "10.1.1.12"],
|
||||
'ПРД-К1': [50013, "10.1.1.13"],
|
||||
'ПРД-Н2': [50021, "10.1.1.21"],
|
||||
'ПРД-В2': [50022, "10.1.1.22"],
|
||||
'ПРД-К2': [50023, "10.1.1.23"],
|
||||
'ПРД-Н3': [50031, "10.1.1.31"],
|
||||
'ПРД-В3': [50032, "10.1.1.32"],
|
||||
'ПРД-К3': [50033, "10.1.1.33"],
|
||||
'ПРД-Н4': [50041, "10.1.1.41"],
|
||||
'ПРД-В4': [50042, "10.1.1.42"],
|
||||
'ПРД-К4': [50043, "10.1.1.43"],
|
||||
# Константы для размеров данных и смещений
|
||||
const STATUS_PACKET_SIZE: int = 103
|
||||
const HEADER_SIZE: int = 8
|
||||
const EMS_G_DATA_OFFSET: int = 9
|
||||
const EMS_G_DATA_SIZE: int = 26 # 13 * 2 байта
|
||||
const UG_DATA_OFFSET: int = 35
|
||||
const UKP0_DATA_OFFSET: int = 39
|
||||
const UKP1_DATA_OFFSET: int = 71
|
||||
const UKP_DATA_SIZE: int = 32
|
||||
|
||||
# Константы команд ISA
|
||||
const CMD_READ_ISA: int = 0
|
||||
const CMD_WRITE_ISA: int = 1
|
||||
const CMD_FLAG_EMS_G: int = 70
|
||||
|
||||
# Минимальный размер пакета для валидации
|
||||
const MIN_PACKET_SIZE: int = 7
|
||||
|
||||
# Словарь адресов устройств
|
||||
const ADDRESS_LIST: Dictionary = {
|
||||
'ПРД-Н1': [50011, '10.1.1.11'],
|
||||
'ПРД-В1': [50012, '10.1.1.12'],
|
||||
'ПРД-К1': [50013, '10.1.1.13'],
|
||||
'ПРД-Н2': [50021, '10.1.1.21'],
|
||||
'ПРД-В2': [50022, '10.1.1.22'],
|
||||
'ПРД-К2': [50023, '10.1.1.23'],
|
||||
'ПРД-Н3': [50031, '10.1.1.31'],
|
||||
'ПРД-В3': [50032, '10.1.1.32'],
|
||||
'ПРД-К3': [50033, '10.1.1.33'],
|
||||
'ПРД-Н4': [50041, '10.1.1.41'],
|
||||
'ПРД-В4': [50042, '10.1.1.42'],
|
||||
'ПРД-К4': [50043, '10.1.1.43'],
|
||||
}
|
||||
const broadcast_addr: Array = [50000, "10.1.1.255"]
|
||||
#const bind_addr: Array = [50_000, "10.1.1.70"] TODO: Порт по умолчанию
|
||||
|
||||
# Широковещательный адрес
|
||||
const BROADCAST_ADDR: Array = [50000, '10.1.1.255']
|
||||
|
||||
# Приватные свойства
|
||||
var status_manager: StatusManager
|
||||
var logs_manager: LogsRich
|
||||
var _socket: SocketUDP
|
||||
var self_name: String
|
||||
var _self_name: String
|
||||
var _isa_ports: Dictionary = {}
|
||||
var _written_isa_ports: Array = []
|
||||
var _timer: Timer
|
||||
var sockets_status_bit: int = 0
|
||||
var ukp0_data: PackedByteArray:
|
||||
set(v):
|
||||
ukp0_data = v
|
||||
print('Произошло Обновление данных ukp0_data')
|
||||
var _sockets_status_bit: int = 0
|
||||
var _dkm_status_bit: int = 0
|
||||
var _dry_contact_status_bit: int = 0xFF
|
||||
var _cmd_number_count: int = 0
|
||||
var _last_received_command: int = -1
|
||||
var _input_impulse: int = 0xffff
|
||||
var _input_const: int = 0xffff
|
||||
var _output_impulse: int = 0xffff
|
||||
var _output_const: int = 0xffff
|
||||
var ukp0_data: PackedByteArray
|
||||
var ukp1_data: PackedByteArray
|
||||
|
||||
var ukp1_data: PackedByteArray:
|
||||
set(v):
|
||||
ukp1_data = v
|
||||
print('Произошло Обновление данных ukp1_data')
|
||||
signal update_isa_ports(_isa_ports: Dictionary)
|
||||
signal update_socket_status(_sockets_status_bit: int)
|
||||
|
||||
|
||||
func _init(name: String):
|
||||
self_name = name
|
||||
_socket = SocketUDP.new()
|
||||
_timer = Timer.new()
|
||||
_timer.wait_time = 1.0 / 3.0
|
||||
_timer.timeout.connect(_on_timer_timeout)
|
||||
ukp0_data.resize(32)
|
||||
ukp0_data.fill(0)
|
||||
ukp1_data.resize(32)
|
||||
ukp1_data.fill(0)
|
||||
func _init(name: String, logs_node: RichTextLabel):
|
||||
'''Инициализация UDP broadcast клиента'''
|
||||
status_manager = StatusManager.new(self)
|
||||
_self_name = name
|
||||
initialize_logs_manager(logs_node)
|
||||
_initialize_socket()
|
||||
_initialize_ukp_data()
|
||||
_initialize_timers()
|
||||
_initialize_isa_ports()
|
||||
|
||||
if addres_list.has(name):
|
||||
var port: int = addres_list[name][0]
|
||||
var addr: String = addres_list[name][1]
|
||||
bind_unit_addres(port, addr)
|
||||
else:
|
||||
push_error("Неизвестное устройство: %s" % name)
|
||||
if not _bind_to_device_address(name):
|
||||
push_error('Не удалось инициализировать устройство: %s' % name)
|
||||
|
||||
|
||||
func bind_unit_addres(port_for_bind: int, addr_for_bind: String) -> void:
|
||||
var bind_result = _socket.bind(port_for_bind, addr_for_bind)
|
||||
func initialize_logs_manager(logs_node: LogsRich) -> void:
|
||||
'''Инициализация менеджера логов'''
|
||||
logs_manager = logs_node
|
||||
logs_manager.info("Логирование инициализировано для %s" % _self_name)
|
||||
|
||||
|
||||
func _initialize_socket() -> void:
|
||||
'''Инициализация UDP сокета'''
|
||||
_socket = SocketUDP.new()
|
||||
if logs_manager:
|
||||
logs_manager.debug("UDP сокет инициализирован")
|
||||
|
||||
|
||||
func _initialize_timers() -> void:
|
||||
'''Инициализация таймеров'''
|
||||
# Таймер для широковещательной рассылки (3 раза в секунду)
|
||||
_timer = Timer.new()
|
||||
_timer.wait_time = 1.0 / 5.0
|
||||
_timer.timeout.connect(_on_broadcast_timeout)
|
||||
if logs_manager:
|
||||
logs_manager.debug("Таймеры инициализированы")
|
||||
|
||||
|
||||
func _initialize_ukp_data() -> void:
|
||||
'''Инициализация данных UKP нулевыми значениями'''
|
||||
ukp0_data = PackedByteArray()
|
||||
ukp0_data.resize(UKP_DATA_SIZE)
|
||||
ukp0_data.fill(0)
|
||||
|
||||
ukp1_data = PackedByteArray()
|
||||
ukp1_data.resize(UKP_DATA_SIZE)
|
||||
ukp1_data.fill(0)
|
||||
if logs_manager:
|
||||
logs_manager.debug("Данные UKP инициализированы")
|
||||
|
||||
|
||||
func _initialize_isa_ports() -> void:
|
||||
'''Инициализация ISA портов начальными значениями'''
|
||||
# Инициализируем порты, которые могут запрашиваться
|
||||
set_isa_port(0x0106, 0) # DOU2 статус
|
||||
set_isa_port(0x0108, 0) # DOU3 статус
|
||||
set_isa_port(0x010A, 0) # ATT
|
||||
if logs_manager:
|
||||
logs_manager.debug("ISA порты инициализированы")
|
||||
|
||||
|
||||
func _bind_to_device_address(device_name: String) -> bool:
|
||||
'''Привязка к адресу устройства по его имени'''
|
||||
if not ADDRESS_LIST.has(device_name):
|
||||
_log_error('Неизвестное устройство: %s' % device_name)
|
||||
return false
|
||||
|
||||
var port: int = ADDRESS_LIST[device_name][0]
|
||||
var address: String = ADDRESS_LIST[device_name][1]
|
||||
|
||||
return bind_unit_address(port, address)
|
||||
|
||||
|
||||
func bind_unit_address(port: int, address: String) -> bool:
|
||||
'''Привязка сокета к указанному порту и адресу'''
|
||||
if port <= 0 or port > 65535:
|
||||
_log_error('Некорректный номер порта: %d' % port)
|
||||
return false
|
||||
|
||||
var bind_result = _socket.bind(port, address)
|
||||
if bind_result != OK:
|
||||
push_error("Не удалось привязаться к %s: %s" % [addr_for_bind, error_string(bind_result)])
|
||||
|
||||
|
||||
func start_broadcast() -> void:
|
||||
_timer.start()
|
||||
|
||||
|
||||
func stop_broadcast() -> void:
|
||||
_timer.stop()
|
||||
|
||||
|
||||
func send_broadcast() -> bool:
|
||||
_socket.set_broadcast_enabled(true)
|
||||
var data: PackedByteArray = _form_status_packet()
|
||||
# добавление 11 байтов вперед вохоже
|
||||
_socket.send_to(broadcast_addr[1], broadcast_addr[0], data)
|
||||
_log_error('Не удалось привязаться к %s:%d - %s' % [address, port, error_string(bind_result)])
|
||||
return false
|
||||
|
||||
_log_info('Успешно привязано к %s:%d' % [address, port])
|
||||
return true
|
||||
|
||||
|
||||
func close_udp_unit() -> void:
|
||||
func add_timers_to_scene(parent: Node) -> void:
|
||||
'''Добавление таймеров в дерево сцены'''
|
||||
# Проверяем что таймеры еще не имеют родителя
|
||||
if not _timer.get_parent():
|
||||
parent.add_child(_timer)
|
||||
elif _timer.get_parent() != parent:
|
||||
_log_warning('Таймер broadcast уже добавлен в другую сцену')
|
||||
else:
|
||||
_log_debug("Таймеры добавлены в сцену")
|
||||
|
||||
|
||||
func start_broadcast() -> void:
|
||||
'''Запуск широковещательной рассылки и опроса сокета'''
|
||||
_timer.start()
|
||||
_log_info('Широковещательная рассылка запущена')
|
||||
|
||||
|
||||
func stop_broadcast() -> void:
|
||||
'''Остановка широковещательной рассылки'''
|
||||
_timer.stop()
|
||||
_log_info('Широковещательная рассылка остановлена')
|
||||
|
||||
|
||||
func close_udp_unit() -> void:
|
||||
'''Закрытие UDP соединения'''
|
||||
stop_broadcast()
|
||||
_socket.close()
|
||||
_log_info('UDP соединение закрыто')
|
||||
|
||||
|
||||
func add_timer_to_scene(parent: Node) -> void:
|
||||
parent.add_child(_timer)
|
||||
#region Публичные методы для управления состоянием
|
||||
func _handle_set_flag_ems_g(set_flag: bool)->void:
|
||||
'''Установка или сброс 5-го бита (бит 4) в статусе сокетов'''
|
||||
var current_status = get_sockets_status()
|
||||
if set_flag:
|
||||
current_status = current_status | (1 << 4)
|
||||
_log_info('Установлен флаг загрузки EMS-G')
|
||||
set_sockets_status(current_status)
|
||||
|
||||
|
||||
func poll_receive() -> void:
|
||||
while _socket.get_available_packet_count() > 0:
|
||||
var broadcast_packet = _socket.get_packet()
|
||||
var addr_receive = _socket.get_packet_ip()
|
||||
#var port_receive = _socket.get_packet_port()
|
||||
#var parsed_data = _parse_packet(broadcast_packet)
|
||||
_handle_received_data(broadcast_packet, addr_receive)
|
||||
func set_sockets_status(status: int) -> void:
|
||||
'''Установка статуса сокетов'''
|
||||
_sockets_status_bit = status
|
||||
emit_signal('update_socket_status', _sockets_status_bit, _self_name)
|
||||
_log_debug("Статус сокетов обновлен: 0x%02X" % status)
|
||||
|
||||
|
||||
func _handle_received_data(data: PackedByteArray, addr: String) -> void:
|
||||
print("данные от %s: %s" % [addr, data])
|
||||
# Здесь можно эмитировать сигналы или обрабатывать данные
|
||||
func get_sockets_status() -> int:
|
||||
'''Получение статуса сокетов'''
|
||||
return _sockets_status_bit
|
||||
|
||||
|
||||
func _on_timer_timeout() -> void:
|
||||
func set_dkm_status(status: int) -> void:
|
||||
'''Установка статуса DKM'''
|
||||
_dkm_status_bit = status
|
||||
_log_debug("Статус DKM установлен: 0x%02X" % status)
|
||||
|
||||
|
||||
func get_dkm_status() -> int:
|
||||
'''Получение статуса DKM'''
|
||||
return _dkm_status_bit
|
||||
|
||||
|
||||
func set_ip_status(status: int)->void:
|
||||
'''Установка статуса ИП'''
|
||||
_dry_contact_status_bit = status
|
||||
_log_debug("Статус ИП установлен: 0x%02X" % status)
|
||||
|
||||
|
||||
func get_ip_status()->int:
|
||||
'''Получение статуса ИП'''
|
||||
return _dry_contact_status_bit
|
||||
|
||||
|
||||
func set_ems_g_status(in_imp: int, in_const: int, out_imp: int, out_const: int) -> void:
|
||||
'''Установка статуса входов и выходов ЕМС-Г'''
|
||||
_input_impulse = in_imp
|
||||
_input_const = in_const
|
||||
_output_impulse = out_imp
|
||||
_output_const = out_const
|
||||
_log_debug("Статус EMS-G обновлен: IN_C=0x%04X, IN_I=0x%04X, OUT_C=0x%04X, OUT_I=0x%04X" % [in_const, in_imp, out_const, out_imp])
|
||||
|
||||
|
||||
func set_isa_port(port_addr: int, value: int) -> bool:
|
||||
'''Установка значения ISA порта'''
|
||||
if port_addr < 0 or port_addr > 0xFFFF:
|
||||
_log_error('Некорректный адрес порта: 0x%03X' % port_addr)
|
||||
return false
|
||||
|
||||
_isa_ports[port_addr] = value
|
||||
emit_signal('update_isa_ports', _isa_ports, _self_name)
|
||||
_log_debug("Порт ISA 0x%04X установлен: 0x%04X" % [port_addr, value])
|
||||
return true
|
||||
|
||||
|
||||
func get_isa_port(port_addr: int) -> int:
|
||||
'''Получение значения ISA порта'''
|
||||
return _isa_ports.get(port_addr, 0xFFFF)
|
||||
|
||||
|
||||
func read_isa_ports(port_addresses: Array) -> Dictionary:
|
||||
'''Чтение значений нескольких ISA портов'''
|
||||
var result = {}
|
||||
|
||||
for port_addr in port_addresses:
|
||||
if port_addr is int and port_addr >= 0 and port_addr <= 0xFFFF:
|
||||
result[port_addr] = get_isa_port(port_addr)
|
||||
else:
|
||||
_log_error('Некорректный адрес порта: ' + str(port_addr))
|
||||
|
||||
return result
|
||||
|
||||
#endregion
|
||||
|
||||
#region Обработчики таймеров
|
||||
|
||||
func _on_broadcast_timeout() -> void:
|
||||
'''Обработчик таймера широковещательной рассылки'''
|
||||
send_broadcast()
|
||||
|
||||
|
||||
func _form_status_packet() -> PackedByteArray:
|
||||
var buf = PackedByteArray()
|
||||
buf.resize(126) # Увеличиваем размер до 126 байт
|
||||
func _on_poll_timeout() -> void:
|
||||
'''Обработчик таймера опроса сокета'''
|
||||
_poll_socket()
|
||||
|
||||
#endregion
|
||||
|
||||
#region Работа с сокетом
|
||||
|
||||
func send_broadcast() -> bool:
|
||||
'''Отправка широковещательного пакета'''
|
||||
_socket.set_broadcast_enabled(true)
|
||||
var data: PackedByteArray = _form_status_device_packet()
|
||||
var send_result = _socket.send_to(BROADCAST_ADDR[1], BROADCAST_ADDR[0], data)
|
||||
|
||||
# Заголовок (0-5 байты)
|
||||
buf.encode_u16(0, 0) # 00 00
|
||||
buf.encode_u16(2, 0x0cff) # ff 0c
|
||||
buf.encode_u16(4, 0) # 00 00
|
||||
|
||||
# Идентификатор пакета
|
||||
buf[6] = 103 # 67
|
||||
|
||||
# Статус устройств
|
||||
buf[7] = 0
|
||||
buf[8] = sockets_status_bit
|
||||
|
||||
# Данные EMS-G (байты 9-34)
|
||||
var ems_g_data = [0x9e00, 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0x0000,
|
||||
0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff]
|
||||
for i in range(13):
|
||||
buf.encode_u16(9 + i * 2, ems_g_data[i])
|
||||
|
||||
# Данные UG (байты 35-38)
|
||||
buf.encode_u16(35, 0x0000) # 00 00
|
||||
buf.encode_u16(37, 0x059e) # 9e 05
|
||||
|
||||
# Данные UKP0 (байты 39-70)
|
||||
for i in ukp0_data.size():
|
||||
buf[39 + i] = ukp0_data[i]
|
||||
# Данные UKP1 (байты 71-102)
|
||||
for i in ukp1_data.size():
|
||||
buf[71 + i] = ukp1_data[i]
|
||||
return buf
|
||||
if send_result == OK:
|
||||
return true
|
||||
else:
|
||||
_log_error('Ошибка отправки широковещательного пакета')
|
||||
return false
|
||||
|
||||
|
||||
####
|
||||
func _poll_socket() -> void:
|
||||
'''Опрос сокета для получения входящих пакетов'''
|
||||
while _socket.get_available_packet_count() > 0:
|
||||
var packet = _socket.get_packet()
|
||||
var address = _socket.get_packet_ip()
|
||||
var port = _socket.get_packet_port()
|
||||
_handle_received_data(packet, address, port)
|
||||
|
||||
#endregion
|
||||
|
||||
#region Формирование пакета статуса устройства
|
||||
|
||||
func _form_status_device_packet() -> PackedByteArray:
|
||||
var buffer = PackedByteArray()
|
||||
|
||||
# Базовый размер пакета + дополнительные байты для записанных портов
|
||||
# + 2 байта для полей команды (код + результат)
|
||||
var header_size = 8
|
||||
var ports_count_size = 1
|
||||
var cmd_fields_size = 0
|
||||
var isa_ports_size = 0
|
||||
if _written_isa_ports.size() > 0:
|
||||
isa_ports_size = _written_isa_ports.size() * 4
|
||||
cmd_fields_size = 4
|
||||
var total_size = header_size + STATUS_PACKET_SIZE + ports_count_size + cmd_fields_size + isa_ports_size
|
||||
|
||||
buffer.resize(total_size)
|
||||
buffer.fill(0)
|
||||
|
||||
_encode_packet_header(buffer)
|
||||
_encode_device_data(buffer)
|
||||
|
||||
# Добавляем поле команды после статуса
|
||||
if _written_isa_ports.size() > 0:
|
||||
var cmd_offset = header_size + STATUS_PACKET_SIZE
|
||||
if cmd_offset < buffer.size():
|
||||
buffer.encode_u16(cmd_offset, _last_received_command) # код команды (0 для статуса)
|
||||
if (cmd_offset + 1) < buffer.size():
|
||||
buffer.encode_u16(cmd_offset+1, 1) # результат выполнения
|
||||
|
||||
var ports_count_offset = cmd_offset + 2
|
||||
# Затем ISA порты
|
||||
buffer.encode_u8(ports_count_offset, _written_isa_ports.size())
|
||||
_encode_written_isa_ports(buffer, ports_count_offset+1)
|
||||
return buffer
|
||||
|
||||
|
||||
func _encode_packet_header(buffer: PackedByteArray) -> void:
|
||||
'''Кодирование заголовка пакета'''
|
||||
# 0-1: Reserved (0x0000)
|
||||
buffer.encode_u16(0, 0)
|
||||
# 2-3: Номер команды
|
||||
buffer.encode_u16(2, _cmd_number_count)
|
||||
# 4-5: Reserved (0x0000)
|
||||
buffer.encode_u16(4, 0)
|
||||
# 6-7: Длина статуса
|
||||
buffer.encode_u16(6, STATUS_PACKET_SIZE)
|
||||
|
||||
|
||||
func _encode_written_isa_ports(buffer: PackedByteArray, offset: int) -> void:
|
||||
'''Добавление данных о записанных ISA портах в конец пакета'''
|
||||
for i in range(_written_isa_ports.size()):
|
||||
var port_data = _written_isa_ports[i]
|
||||
# Добавляем порт и значение (по 2 байта каждый)
|
||||
buffer.encode_u16(offset, port_data[0])
|
||||
buffer.encode_u16(offset + 2, port_data[1])
|
||||
offset += 4
|
||||
|
||||
|
||||
func _encode_device_data(buffer: PackedByteArray) -> void:
|
||||
'''Кодирование данных устройств в пакет'''
|
||||
# 8-9: Статус сокетов
|
||||
buffer.encode_u16(8, _sockets_status_bit)
|
||||
|
||||
# 9-34: Данные EMS-G
|
||||
_encode_ems_g_data(buffer)
|
||||
|
||||
# 35-38: Данные UG
|
||||
_encode_ug_data(buffer)
|
||||
|
||||
# 39-70: Данные UKP0
|
||||
# 71-102: Данные UKP1
|
||||
_encode_ukp_data(buffer)
|
||||
|
||||
|
||||
func _encode_ems_g_data(buffer: PackedByteArray) -> void:
|
||||
'''Кодирование данных EMS-G'''
|
||||
buffer.encode_u16(EMS_G_DATA_OFFSET, _input_const)
|
||||
buffer.encode_u16(EMS_G_DATA_OFFSET + 6, _input_impulse)
|
||||
buffer.encode_u16(EMS_G_DATA_OFFSET + 12, _output_const)
|
||||
buffer.encode_u16(EMS_G_DATA_OFFSET + 18, _output_impulse)
|
||||
|
||||
|
||||
func _encode_ug_data(buffer: PackedByteArray) -> void:
|
||||
'''Кодирование данных UG'''
|
||||
# D15...D8 = ДКМ (старший байт)
|
||||
buffer.encode_u8(UG_DATA_OFFSET + 1, _dkm_status_bit & 0xFF)
|
||||
# D7...D0 = Сухие контакты (младший байт)
|
||||
buffer.encode_u8(UG_DATA_OFFSET, _dry_contact_status_bit & 0xFF)
|
||||
|
||||
|
||||
func _encode_ukp_data(buffer: PackedByteArray) -> void:
|
||||
'''Кодирование данных UKP'''
|
||||
for i in range(UKP_DATA_SIZE):
|
||||
if i < ukp0_data.size():
|
||||
buffer[UKP0_DATA_OFFSET + i] = ukp0_data[i]
|
||||
if i < ukp1_data.size():
|
||||
buffer[UKP1_DATA_OFFSET + i] = ukp1_data[i]
|
||||
|
||||
#endregion
|
||||
|
||||
#region Прямая отправка ответа
|
||||
|
||||
func _send_immediate_response(address: String, port: int) -> void:
|
||||
'''Немедленная отправка пакета на указанный адрес и порт'''
|
||||
var data: PackedByteArray = _form_status_device_packet()
|
||||
_socket.set_broadcast_enabled(false) # Отключаем broadcast для точечной отправки
|
||||
var send_result = _socket.send_to(address, port, data)
|
||||
_socket.set_broadcast_enabled(true) # Включаем обратно для broadcast
|
||||
|
||||
if send_result == OK:
|
||||
_log_debug('Отправлен немедленный ответ на %s:%d' % [address, port])
|
||||
else:
|
||||
_log_error('Ошибка отправки ответа на %s:%d' % [address, port])
|
||||
|
||||
#endregion
|
||||
|
||||
#region Обработка входящих данных
|
||||
|
||||
func _handle_received_data(data: PackedByteArray, address: String, port: int) -> void:
|
||||
'''Обработка входящих данных'''
|
||||
if not _validate_received_packet(data):
|
||||
return
|
||||
|
||||
var command_type = _get_command_type(data)
|
||||
_cmd_number_count = data.decode_u16(2)
|
||||
if command_type == -1: # Проверяем на -1 вместо null
|
||||
return
|
||||
_handle_isa_command(command_type, data, address, port)
|
||||
|
||||
|
||||
func _validate_received_packet(data: PackedByteArray) -> bool:
|
||||
'''Валидация входящего пакета'''
|
||||
if data.size() < MIN_PACKET_SIZE:
|
||||
_log_warning('Получен слишком короткий пакет: %d байт' % data.size())
|
||||
return false
|
||||
return true
|
||||
|
||||
|
||||
func _get_command_type(data: PackedByteArray) -> int:
|
||||
'''Получение типа команды из данных пакета'''
|
||||
if data.size() < 6:
|
||||
return -1 # Используем -1 для обозначения ошибки
|
||||
return data.decode_u8(6)
|
||||
|
||||
|
||||
func _handle_isa_command(command_code: int, data: PackedByteArray, address: String, port: int) -> void:
|
||||
'''Обработка команд ISA'''
|
||||
_last_received_command = command_code # Запоминаем последнюю команду
|
||||
match command_code:
|
||||
CMD_READ_ISA:
|
||||
_handle_read_isa_command(data, address, port)
|
||||
CMD_WRITE_ISA:
|
||||
_handle_write_isa_command(data, address, port)
|
||||
CMD_FLAG_EMS_G:
|
||||
_handle_set_flag_ems_g(true)
|
||||
_:
|
||||
_log_warning('Неизвестная команда ISA: %d от %s:%d' % [command_code, address, port])
|
||||
|
||||
|
||||
func _handle_read_isa_command(data: PackedByteArray, address: String, port: int) -> void:
|
||||
'''Обработка команды чтения ISA портов'''
|
||||
var ports = _parse_command_ports(data)
|
||||
if ports.is_empty():
|
||||
return
|
||||
|
||||
var port_data = _get_isa_ports_data(ports)
|
||||
_log_info('Принята команда на чтение ISA портов от %s:%d: %s' % [address, port, port_data])
|
||||
_written_isa_ports = []
|
||||
for i in range(ports.size()):
|
||||
_written_isa_ports.append([ports[i], port_data[i]])
|
||||
|
||||
# Отправляем ответ с данными запрошенных портов
|
||||
_send_immediate_response(address, port)
|
||||
|
||||
|
||||
func _handle_write_isa_command(data: PackedByteArray, address: String, port: int) -> void:
|
||||
'''Обработка команды записи ISA портов'''
|
||||
var ports = _parse_command_ports(data)
|
||||
var data_to_write = _parse_command_ports_data(data)
|
||||
if ports.size() != data_to_write.size():
|
||||
_log_warning('Несоответствие размеров портов и данных от %s:%d' % [address, port])
|
||||
return
|
||||
|
||||
# Обновляем или добавляем записанные порты
|
||||
for i in range(ports.size()):
|
||||
var port_addr = ports[i]
|
||||
var value = data_to_write[i]
|
||||
set_isa_port(port_addr, value)
|
||||
|
||||
# Ищем порт в массиве, если есть - обновляем, если нет - добавляем
|
||||
var found = false
|
||||
for j in range(_written_isa_ports.size()):
|
||||
if _written_isa_ports[j][0] == port_addr:
|
||||
_written_isa_ports[j][1] = value # Обновляем значение
|
||||
found = true
|
||||
break
|
||||
|
||||
if not found:
|
||||
_written_isa_ports.append([port_addr, value]) # Добавляем новый порт
|
||||
|
||||
_log_info('Принята команда на запись в ISA порты от %s:%d: %s' % [address, port, _isa_ports])
|
||||
# Немедленная отправка ответа отправителю
|
||||
_send_immediate_response(address, port)
|
||||
#endregion
|
||||
|
||||
#region Парсинг команд ISA
|
||||
|
||||
func _parse_command_ports(data: PackedByteArray) -> Array:
|
||||
'''Парсинг адресов портов из команды'''
|
||||
if data.size() < 7:
|
||||
return []
|
||||
|
||||
var ports_count = data.decode_u8(7)
|
||||
if data.size() <= (ports_count + 8):
|
||||
return []
|
||||
|
||||
var ports = []
|
||||
if _get_command_type(data) == CMD_READ_ISA:
|
||||
for i in range(ports_count):
|
||||
var port_address = data.decode_u16(8 + i * 2)
|
||||
ports.append(port_address)
|
||||
elif _get_command_type(data) == CMD_WRITE_ISA:
|
||||
for i in range(ports_count):
|
||||
var port_address = data.decode_u16(8 + i * 4)
|
||||
ports.append(port_address)
|
||||
return ports
|
||||
|
||||
|
||||
func _parse_command_ports_data(data: PackedByteArray) -> Array:
|
||||
'''Парсинг данных портов из команды записи'''
|
||||
if data.size() < 8:
|
||||
return []
|
||||
|
||||
var ports_count = data.decode_u8(7)
|
||||
if data.size() <= (ports_count + 10):
|
||||
return []
|
||||
|
||||
var ports_data = []
|
||||
var data_offset = 10 # Смещение для данных портов
|
||||
|
||||
for i in range(ports_count):
|
||||
if data_offset + i * 4 < data.size():
|
||||
var port = data.decode_u16(8 + i * 4)
|
||||
var port_data = data.decode_u16(data_offset + i * 4)
|
||||
ports_data.append(port_data)
|
||||
_log_debug('Данные порта 0x%02X: 0x%02X' % [port, port_data])
|
||||
return ports_data
|
||||
|
||||
|
||||
func _get_isa_ports_data(ports: Array) -> Array:
|
||||
'''Получение данных указанных ISA портов'''
|
||||
var result = []
|
||||
for port_address in ports:
|
||||
result.append(get_isa_port(port_address))
|
||||
return result
|
||||
|
||||
|
||||
func _set_isa_ports_data(ports: Array, data: Array) -> void:
|
||||
'''Установка данных для указанных ISA портов'''
|
||||
for i in range(ports.size()):
|
||||
if i < data.size():
|
||||
set_isa_port(ports[i], data[i])
|
||||
|
||||
#endregion
|
||||
|
||||
#region Методы логирования
|
||||
|
||||
func _log_info(message: String) -> void:
|
||||
'''Логирование информационного сообщения'''
|
||||
if logs_manager:
|
||||
logs_manager.info("[%s] %s" % [_self_name, message])
|
||||
else:
|
||||
print("[%s] INFO: %s" % [_self_name, message])
|
||||
|
||||
func _log_warning(message: String) -> void:
|
||||
'''Логирование предупреждения'''
|
||||
if logs_manager:
|
||||
logs_manager.warning("[%s] %s" % [_self_name, message])
|
||||
else:
|
||||
print("[%s] WARNING: %s" % [_self_name, message])
|
||||
|
||||
func _log_error(message: String) -> void:
|
||||
'''Логирование ошибки'''
|
||||
if logs_manager:
|
||||
logs_manager.error("[%s] %s" % [_self_name, message])
|
||||
else:
|
||||
print("[%s] ERROR: %s" % [_self_name, message])
|
||||
|
||||
func _log_debug(message: String) -> void:
|
||||
'''Логирование отладочной информации'''
|
||||
if logs_manager:
|
||||
logs_manager.debug("[%s] %s" % [_self_name, message])
|
||||
else:
|
||||
print("[%s] DEBUG: %s" % [_self_name, message])
|
||||
|
||||
#endregion
|
||||
|
||||
#region Вложенный класс SocketUDP
|
||||
|
||||
class SocketUDP extends PacketPeerUDP:
|
||||
func send_to(addr: String, port: int, data: PackedByteArray):
|
||||
set_dest_address(addr, port)
|
||||
var rc: = put_packet(data)
|
||||
if rc != OK:
|
||||
push_error('%s: %s:%s' % [error_string(rc), addr, port])
|
||||
'''Расширенный класс UDP сокета с улучшенной обработкой ошибок'''
|
||||
|
||||
func send_to(address: String, port: int, data: PackedByteArray) -> int:
|
||||
'''Отправка данных на указанный адрес и порт'''
|
||||
set_dest_address(address, port)
|
||||
var result = put_packet(data)
|
||||
|
||||
if result != OK:
|
||||
push_error('Ошибка отправки: %s - %s:%d' % [error_string(result), address, port])
|
||||
|
||||
return result
|
||||
|
||||
#endregion
|
||||
|
||||
#region Методы управления записанными портами
|
||||
|
||||
func clear_written_ports() -> void:
|
||||
'''Очистка списка записанных портов (ручное управление)'''
|
||||
_written_isa_ports.clear()
|
||||
_log_info('Список записанных портов очищен')
|
||||
|
||||
func get_written_ports_count() -> int:
|
||||
'''Получение количества записанных портов'''
|
||||
return _written_isa_ports.size()
|
||||
|
||||
func remove_written_port(port_addr: int) -> bool:
|
||||
'''Удаление конкретного порта из списка записанных'''
|
||||
for i in range(_written_isa_ports.size()):
|
||||
if _written_isa_ports[i][0] == port_addr:
|
||||
_written_isa_ports.remove_at(i)
|
||||
_log_info('Порт 0x%04X удален из списка записанных' % port_addr)
|
||||
return true
|
||||
return false
|
||||
|
||||
#endregion
|
||||
|
||||
198
uf_broadcast.gd
Normal file
198
uf_broadcast.gd
Normal file
@@ -0,0 +1,198 @@
|
||||
class_name UF_Broadcast
|
||||
|
||||
const ADDRESS_LIST: Dictionary = {
|
||||
'УФ': [50052, '10.1.1.52']}
|
||||
const BROADCAST_ADDR: Array = [50000, '10.1.1.255']
|
||||
const MIN_PACKET_SIZE: int = 7
|
||||
|
||||
var _self_name: String
|
||||
var _socket: SocketUDP
|
||||
var _timer: Timer
|
||||
var _cmd_number_count: int = 0
|
||||
var status: int = 0
|
||||
var ip: int = 0
|
||||
|
||||
|
||||
func _init(name: String):
|
||||
'''Инициализация UDP broadcast UF клиента'''
|
||||
_self_name = name
|
||||
_initialize_socket()
|
||||
_initialize_timers()
|
||||
|
||||
|
||||
if not _bind_to_device_address(name):
|
||||
push_error('Не удалось инициализировать устройство: %s' % name)
|
||||
|
||||
|
||||
func _initialize_socket() -> void:
|
||||
'''Инициализация UDP сокета'''
|
||||
_socket = SocketUDP.new()
|
||||
|
||||
func _initialize_timers() -> void:
|
||||
'''Инициализация таймеров'''
|
||||
# Таймер для широковещательной рассылки (3 раза в секунду)
|
||||
_timer = Timer.new()
|
||||
_timer.wait_time = 1.0 / 5.0
|
||||
_timer.timeout.connect(_on_broadcast_timeout)
|
||||
|
||||
|
||||
func add_timers_to_scene(parent: Node) -> void:
|
||||
'''Добавление таймеров в дерево сцены'''
|
||||
# Проверяем что таймеры еще не имеют родителя
|
||||
if not _timer.get_parent():
|
||||
parent.add_child(_timer)
|
||||
elif _timer.get_parent() != parent:
|
||||
push_warning('Таймер broadcast уже добавлен в другую сцену')
|
||||
|
||||
|
||||
func _bind_to_device_address(device_name: String) -> bool:
|
||||
'''Привязка к адресу устройства по его имени'''
|
||||
if not ADDRESS_LIST.has(device_name):
|
||||
push_error('Неизвестное устройство: %s' % device_name)
|
||||
return false
|
||||
|
||||
var port: int = ADDRESS_LIST[device_name][0]
|
||||
var address: String = ADDRESS_LIST[device_name][1]
|
||||
|
||||
return bind_unit_address(port, address)
|
||||
|
||||
|
||||
func bind_unit_address(port: int, address: String) -> bool:
|
||||
'''Привязка сокета к указанному порту и адресу'''
|
||||
if port <= 0 or port > 65535:
|
||||
push_error('Некорректный номер порта: %d' % port)
|
||||
return false
|
||||
|
||||
var bind_result = _socket.bind(port, address)
|
||||
if bind_result != OK:
|
||||
push_error('Не удалось привязаться к %s:%d - %s' % [address, port, error_string(bind_result)])
|
||||
return false
|
||||
|
||||
print('Успешно привязано к %s:%d' % [address, port])
|
||||
return true
|
||||
|
||||
|
||||
func _on_broadcast_timeout() -> void:
|
||||
'''Обработчик таймера широковещательной рассылки'''
|
||||
send_broadcast()
|
||||
|
||||
|
||||
func send_broadcast() -> bool:
|
||||
'''Отправка широковещательного пакета'''
|
||||
_socket.set_broadcast_enabled(true)
|
||||
var data: PackedByteArray = _form_status_device_packet()
|
||||
var send_result = _socket.send_to(BROADCAST_ADDR[1], BROADCAST_ADDR[0], data)
|
||||
if send_result == OK:
|
||||
return true
|
||||
else:
|
||||
push_error('Ошибка отправки широковещательного пакета')
|
||||
return false
|
||||
|
||||
|
||||
func _form_status_device_packet() -> PackedByteArray:
|
||||
var uf: Array = [0x00, 0x00, _cmd_number_count, 0x05, 0x00, 0x00, 0x4f, 0x00, status, 0x00, ip, 0x00, 0x00, 0xff, 0xff, 0x00,\
|
||||
0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff,\
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,\
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0x04, 0x24, 0x01, 0x00, 0x00, 0x26, 0x01,\
|
||||
0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0x2a, 0x01, 0xff, 0xff]
|
||||
|
||||
var buffer = PackedByteArray()
|
||||
for byte in uf:
|
||||
buffer.append(byte)
|
||||
return buffer
|
||||
|
||||
|
||||
func start_broadcast() -> void:
|
||||
'''Запуск широковещательной рассылки и опроса сокета'''
|
||||
_timer.start()
|
||||
print('Широковещательная рассылка запущена')
|
||||
|
||||
|
||||
func stop_broadcast() -> void:
|
||||
'''Остановка широковещательной рассылки'''
|
||||
_timer.stop()
|
||||
print('Широковещательная рассылка остановлена')
|
||||
|
||||
|
||||
func close_udp_unit() -> void:
|
||||
'''Закрытие UDP соединения'''
|
||||
stop_broadcast()
|
||||
_socket.close()
|
||||
print('UDP соединение закрыто')
|
||||
|
||||
|
||||
func _on_poll_timeout() -> void:
|
||||
'''Обработчик таймера опроса сокета'''
|
||||
_poll_socket()
|
||||
|
||||
|
||||
func _poll_socket() -> void:
|
||||
'''Опрос сокета для получения входящих пакетов'''
|
||||
while _socket.get_available_packet_count() > 0:
|
||||
var packet = _socket.get_packet()
|
||||
_handle_received_data(packet)
|
||||
|
||||
|
||||
func _handle_received_data(data: PackedByteArray) -> void:
|
||||
'''Обработка входящих данных'''
|
||||
if not _validate_received_packet(data):
|
||||
return
|
||||
|
||||
var command_type = _get_command_type(data)
|
||||
_cmd_number_count = data.decode_u16(2)
|
||||
if command_type == -1: # Проверяем на -1 вместо null
|
||||
return
|
||||
|
||||
|
||||
func _validate_received_packet(data: PackedByteArray) -> bool:
|
||||
'''Валидация входящего пакета'''
|
||||
if data.size() < MIN_PACKET_SIZE:
|
||||
push_warning('Получен слишком короткий пакет: %d байт' % data.size())
|
||||
return false
|
||||
return true
|
||||
|
||||
|
||||
func _get_command_type(data: PackedByteArray) -> int:
|
||||
'''Получение типа команды из данных пакета'''
|
||||
if data.size() < 6:
|
||||
return -1 # Используем -1 для обозначения ошибки
|
||||
return data.decode_u8(6)
|
||||
|
||||
|
||||
func set_status_uf(new_status: int) -> void:
|
||||
if status != new_status:
|
||||
status = new_status
|
||||
print('Установлен статус УФ: %s' % status)
|
||||
|
||||
|
||||
func get_status_uf() -> int:
|
||||
return status
|
||||
|
||||
|
||||
func set_power_bit_uf(new_status)-> void:
|
||||
if ip != new_status:
|
||||
ip = new_status
|
||||
|
||||
|
||||
func get_power_bit_uf() -> int:
|
||||
return ip
|
||||
|
||||
|
||||
#region Вложенный класс SocketUDP
|
||||
|
||||
class SocketUDP extends PacketPeerUDP:
|
||||
'''Расширенный класс UDP сокета с улучшенной обработкой ошибок'''
|
||||
|
||||
func send_to(address: String, port: int, data: PackedByteArray) -> int:
|
||||
'''Отправка данных на указанный адрес и порт'''
|
||||
set_dest_address(address, port)
|
||||
var result = put_packet(data)
|
||||
|
||||
if result != OK:
|
||||
push_error('Ошибка отправки: %s - %s:%d' % [error_string(result), address, port])
|
||||
|
||||
return result
|
||||
|
||||
#endregion
|
||||
1
uf_broadcast.gd.uid
Normal file
1
uf_broadcast.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://lju7b4vxgjpd
|
||||
88
журнал.gd
Normal file
88
журнал.gd
Normal file
@@ -0,0 +1,88 @@
|
||||
class_name LogsRich
|
||||
extends RichTextLabel
|
||||
|
||||
enum LogLevel {
|
||||
INFO,
|
||||
WARNING,
|
||||
ERROR,
|
||||
DEBUG
|
||||
}
|
||||
|
||||
var _level_colors: Dictionary = {
|
||||
LogLevel.INFO: Color.WHITE,
|
||||
LogLevel.WARNING: Color.YELLOW,
|
||||
LogLevel.ERROR: Color.RED,
|
||||
LogLevel.DEBUG: Color.CYAN
|
||||
}
|
||||
|
||||
var _level_prefixes: Dictionary = {
|
||||
LogLevel.INFO: "[INFO]",
|
||||
LogLevel.WARNING: "[WARNING]",
|
||||
LogLevel.ERROR: "[ERROR]",
|
||||
LogLevel.DEBUG: "[DEBUG]"
|
||||
}
|
||||
|
||||
var max_lines: int = 1000
|
||||
|
||||
func _ready():
|
||||
scroll_active = true
|
||||
#scroll_following = true
|
||||
bbcode_enabled = true
|
||||
fit_content = false
|
||||
clear_logs()
|
||||
|
||||
|
||||
func add_log(message: String, level: LogLevel = LogLevel.INFO) -> void:
|
||||
if not is_inside_tree():
|
||||
push_warning("LogsRich не добавлен в дерево сцены!")
|
||||
return
|
||||
|
||||
var timestamp = Time.get_time_string_from_system()
|
||||
var prefix = _level_prefixes.get(level, "[INFO]")
|
||||
var color = _level_colors.get(level, Color.WHITE)
|
||||
|
||||
var formatted_message = "[%s] %s %s" % [timestamp, prefix, message]
|
||||
var color_hex = color.to_html(false)
|
||||
|
||||
# Просто добавляем текст (RichTextLabel сам обрабатывает BBcode)
|
||||
append_text("[color=#%s]%s[/color]\n" % [color_hex, formatted_message])
|
||||
|
||||
# Прокручиваем вниз
|
||||
if is_inside_tree():
|
||||
scroll_to_line(get_line_count())
|
||||
|
||||
# Ограничиваем количество строк
|
||||
limit_line_count_simple()
|
||||
|
||||
func info(message: String) -> void:
|
||||
add_log(message, LogLevel.INFO)
|
||||
|
||||
func warning(message: String) -> void:
|
||||
add_log(message, LogLevel.WARNING)
|
||||
|
||||
func error(message: String) -> void:
|
||||
add_log(message, LogLevel.ERROR)
|
||||
|
||||
func debug(message: String) -> void:
|
||||
add_log(message, LogLevel.DEBUG)
|
||||
|
||||
func clear_logs() -> void:
|
||||
text = ""
|
||||
|
||||
func limit_line_count_simple() -> void:
|
||||
var lines = get_line_count()
|
||||
if lines > max_lines:
|
||||
# Получаем чистый текст без BBcode
|
||||
var raw_text = get_parsed_text()
|
||||
var text_lines = raw_text.split("\n")
|
||||
|
||||
if text_lines.size() > max_lines:
|
||||
# Удаляем первые строки
|
||||
text_lines = text_lines.slice(text_lines.size() - max_lines)
|
||||
|
||||
# Очищаем и перезаписываем
|
||||
clear_logs()
|
||||
for line in text_lines:
|
||||
if line.strip_edges().length() > 0:
|
||||
# Добавляем как INFO (теряем цвета, но это проще)
|
||||
append_text("[color=#ffffff]%s[/color]\n" % line)
|
||||
1
журнал.gd.uid
Normal file
1
журнал.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bwll70u61ocw6
|
||||
Reference in New Issue
Block a user