Compare commits

...

2 Commits

Author SHA1 Message Date
TotMaxim
39bef3a351 Дорабтока атт и статус менеджера 2025-11-21 13:02:32 +03:00
TotMaxim
3648e740a0 Отладка read_isa 2025-11-21 00:49:02 +03:00
5 changed files with 171 additions and 98 deletions

55
StatusManager.gd Normal file
View File

@@ -0,0 +1,55 @@
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)
# Триггерим обновление через установку тех же значений
_device.set_isa_port(0x106, current_106)
_device.set_isa_port(0x108, current_108)
# Универсальные методы для работы с битовыми полями
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_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
View File

@@ -0,0 +1 @@
uid://ddgp4l3kdjwg2

118
main.gd
View File

@@ -114,11 +114,19 @@ func _ready() -> void:
var dou2_arr_node: Array = get_tree().get_nodes_in_group('dou2')
for dou2 in dou2_arr_node:
dou2.connect('toggled', _on_modify_dou2.bind(dou2.get_meta('bit'), dou2.get_meta('device')))
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.connect('toggled', _on_modify_dou3.bind(dou3.get_meta('bit'), dou3.get_meta('device')))
dou3.toggled.connect(_on_modify_status.bind(dou3.get_meta('bit'), dou3.get_meta('device'), "dou3"))
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:
@@ -128,6 +136,11 @@ func _ready() -> void:
_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:
if dictionary_yau07[device]:
@@ -141,6 +154,7 @@ func on_modify_device(toggled: bool, name_device: String) -> void:
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)
else:
if dictionary_yau07.has(name_device) and dictionary_yau07[name_device]:
dictionary_yau07[name_device].close_udp_unit()
@@ -177,6 +191,38 @@ func _update_tab_container():
tab_container.visible = has_visible_tabs
func _on_update_isa_ports(isa_ports: Dictionary)->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}
]
}
if port_configs.has(port_addr):
for config in port_configs[port_addr]:
var status = (value >> config.shift) & config.mask
_update_button_group(config.group, status)
func _update_button_group(group_name: String, status: int) -> void:
"""Обновление всех кнопок в группе на основе статуса"""
var buttons = get_tree().get_nodes_in_group(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)
button.set_pressed_no_signal(should_be_pressed)
## Функция для установки статусов ячеек на связи (УГ, ЭМС-Г, УКП)
func _on_modify_sockets(toggled: bool, bit: int, device: String)->void:
if dictionary_yau07.has(device):
@@ -197,43 +243,35 @@ func _on_modify_dkm(toggled: bool, bit: int, device: String)->void:
print("Статус DKM устройства %s обновлен: 0x%04X" % [device, new_status])
## Функция для установки статусов ДОУ2 в ПРД
func _on_modify_dou2(toggled: bool, bit: int, device: String)->void:
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_tree().get_nodes_in_group(status_type)
if not toggled:
var dou2_arr_node = get_tree().get_nodes_in_group('dou2')
for dou2 in dou2_arr_node:
if dou2.has_meta('bit') and dou2.get_meta('bit') == bit:
dou2.set_pressed(true)
if toggled:
var dou2_arr_node = get_tree().get_nodes_in_group('dou2')
for dou2 in dou2_arr_node:
if dou2.has_meta('bit') and dou2.get_meta('bit') != bit and dou2.button_pressed:
dou2.set_pressed_no_signal(false)
# Восстанавливаем предыдущее состояние
for button in button_group:
if button.has_meta('bit') and button.get_meta('bit') == bit:
button.set_pressed(true)
return
# Всегда устанавливаем статус, если кнопка нажата
if toggled and dictionary_yau07.has(device):
var udp_unit = dictionary_yau07[device]
udp_unit.set_dou2_status(bit)
## Функция для установки статусов ДОУ3 в ПРД
func _on_modify_dou3(toggled: bool, bit: int, device: String)->void:
if not toggled:
var dou3_arr_node = get_tree().get_nodes_in_group('dou3')
for dou3 in dou3_arr_node:
if dou3.has_meta('bit') and dou3.get_meta('bit') == bit:
dou3.set_pressed(true)
if toggled:
var dou3_arr_node = get_tree().get_nodes_in_group('dou3')
for dou3 in dou3_arr_node:
if dou3.has_meta('bit') and dou3.get_meta('bit') != bit and dou3.button_pressed:
dou3.set_pressed_no_signal(false)
# Всегда устанавливаем статус, если кнопка нажата
if toggled and dictionary_yau07.has(device):
var udp_unit = dictionary_yau07[device]
udp_unit.set_dou3_status(bit)
# Выключаем другие кнопки в группе
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)
print('button_press_bit: ', bit)
# Устанавливаем статус через менеджер
match status_type:
"dou2":
udp_unit.status_manager.set_dou2_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):
@@ -369,7 +407,7 @@ static func _set_bit(bits: int, index: int, val: bool) -> int:
return bits | (1 << index) if val else bits & ~(1 << index)
## Новый метод для работы с ISA портами (если потребуется)
## Новый метод для работы с ISA портами
func read_isa_ports(device: String, port_addresses: Array) -> Dictionary:
"""Чтение ISA портов указанного устройства"""
if dictionary_yau07.has(device):
@@ -379,7 +417,7 @@ func read_isa_ports(device: String, port_addresses: Array) -> Dictionary:
return {}
## Новый метод для записи ISA портов (если потребуется)
## Новый метод для записи ISA портов
func write_isa_port(device: String, port_address: int, value: int) -> bool:
"""Запись значения в ISA порт указанного устройства"""
if dictionary_yau07.has(device):

View File

@@ -440,8 +440,8 @@ layout_mode = 2
[node name="CheckBox" type="CheckBox" parent="TabContainer/ПРД-Н1/TabBar/ug/GridContainer2" groups=["att2"]]
layout_mode = 2
text = "АТТ 0 dB"
metadata/att = 0
metadata/device = "ПРД-Н1"
metadata/bit = 0
[node name="CheckBox2" type="CheckBox" parent="TabContainer/ПРД-Н1/TabBar/ug/GridContainer2" groups=["att2"]]
layout_mode = 2

View File

@@ -37,44 +37,31 @@ const ADDRESS_LIST: Dictionary = {
const BROADCAST_ADDR: Array = [50000, "10.1.1.255"]
# Приватные свойства
var status_manager: StatusManager
var _socket: SocketUDP
var _self_name: String
var _isa_ports: Dictionary = {}
var _written_isa_ports: Array = []
var _timer: Timer
var _poll_timer: Timer
var _sockets_status_bit: int = 0
var _dkm_status_bit: int = 0
var _dry_contact_status_bit: int = 0xFF
var _dou_and_att_2_status_bit: Dictionary = {0x106: 0}
var _dou_and_att_3_status_bit: Dictionary = {0x108: 0}
var _isa_ports: Dictionary = {}
var _cmd_number_count: int = 0
var _written_isa_ports: Array = []
var _last_received_command: int = -1
var ukp0_data: PackedByteArray
var ukp1_data: PackedByteArray
# Публичные свойства с контролем доступа
var ukp0_data: PackedByteArray:
set(value):
if value.size() == UKP_DATA_SIZE:
ukp0_data = value
print('Данные UKP0 обновлены')
var ukp1_data: PackedByteArray:
set(value):
if value.size() == UKP_DATA_SIZE:
ukp1_data = value
print('Данные UKP1 обновлены')
signal update_isa_ports(_isa_ports: Dictionary)
func _init(name: String):
"""Инициализация UDP broadcast клиента"""
status_manager = StatusManager.new(self)
_self_name = name
_initialize_socket()
_initialize_ukp_data()
_initialize_timers()
_initialize_isa_ports()
if not _bind_to_device_address(name):
push_error("Не удалось инициализировать устройство: %s" % name)
@@ -89,13 +76,13 @@ func _initialize_timers() -> void:
"""Инициализация таймеров"""
# Таймер для широковещательной рассылки (3 раза в секунду)
_timer = Timer.new()
_timer.wait_time = 1.0 / 3.0
_timer.wait_time = 1.0 / 5.0
_timer.timeout.connect(_on_broadcast_timeout)
# Таймер для частого опроса сокета (100 раз в секунду)
_poll_timer = Timer.new()
_poll_timer.wait_time = 0.01
_poll_timer.timeout.connect(_on_poll_timeout)
#_poll_timer = Timer.new()
#_poll_timer.wait_time = 0.05
#_poll_timer.timeout.connect(_on_poll_timeout)
func _initialize_ukp_data() -> void:
@@ -109,6 +96,14 @@ func _initialize_ukp_data() -> void:
ukp1_data.fill(0)
func _initialize_isa_ports() -> void:
"""Инициализация ISA портов начальными значениями"""
# Инициализируем порты, которые могут запрашиваться
set_isa_port(0x0106, 0) # DOU2 статус
set_isa_port(0x0108, 0) # DOU3 статус
set_isa_port(0x010A, 0) # ATT
func _bind_to_device_address(device_name: String) -> bool:
"""Привязка к адресу устройства по его имени"""
if not ADDRESS_LIST.has(device_name):
@@ -144,23 +139,23 @@ func add_timers_to_scene(parent: Node) -> void:
elif _timer.get_parent() != parent:
push_warning("Таймер broadcast уже добавлен в другую сцену")
if not _poll_timer.get_parent():
parent.add_child(_poll_timer)
elif _poll_timer.get_parent() != parent:
push_warning("Таймер poll уже добавлен в другую сцену")
#if not _poll_timer.get_parent():
#parent.add_child(_poll_timer)
#elif _poll_timer.get_parent() != parent:
#push_warning("Таймер poll уже добавлен в другую сцену")
func start_broadcast() -> void:
"""Запуск широковещательной рассылки и опроса сокета"""
_timer.start()
_poll_timer.start()
#_poll_timer.start()
print("Широковещательная рассылка запущена")
func stop_broadcast() -> void:
"""Остановка широковещательной рассылки"""
_timer.stop()
_poll_timer.stop()
#_poll_timer.stop()
print("Широковещательная рассылка остановлена")
@@ -193,28 +188,6 @@ func get_dkm_status() -> int:
return _dkm_status_bit
func set_dou2_status(status: int) -> void:
"""Установка статуса DOU"""
var masked_status = status & 0b111 # Маска для первых 3 битов
_dou_and_att_2_status_bit[0x106] = masked_status
func get_dou2_status() -> int:
"""Получение статуса DOU"""
return _dou_and_att_2_status_bit[0x106] & 0b111
func set_dou3_status(status: int) -> void:
"""Установка статуса DOU"""
var masked_status = status & 0b111 # Маска для первых 3 битов
_dou_and_att_3_status_bit[0x108] = masked_status
func get_dou3_status() -> int:
"""Получение статуса DOU"""
return _dou_and_att_3_status_bit[0x108] & 0b111
func set_ip_status(status: int)->void:
"""Установка статуса ИП"""
_dry_contact_status_bit = status
@@ -228,10 +201,11 @@ func get_ip_status()->int:
func set_isa_port(port_addr: int, value: int) -> bool:
"""Установка значения ISA порта"""
if port_addr < 0 or port_addr > 0xFFFF:
push_error("Некорректный адрес порта: 0x%04X" % port_addr)
push_error("Некорректный адрес порта: 0x%03X" % port_addr)
return false
_isa_ports[port_addr] = value
emit_signal('update_isa_ports', _isa_ports)
return true
@@ -420,9 +394,9 @@ func _handle_received_data(data: PackedByteArray, address: String, port: int) ->
return
var command_type = _get_command_type(data)
_cmd_number_count = data.decode_u16(2)
if command_type == -1: # Проверяем на -1 вместо null
return
_cmd_number_count = (_cmd_number_count + 1) & 0xFFFF
_handle_isa_command(command_type, data, address, port)
@@ -467,6 +441,12 @@ func _handle_read_isa_command(data: PackedByteArray, address: String, port: int)
var port_data = _get_isa_ports_data(ports)
print('Принята команда на чтение 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:
@@ -500,7 +480,6 @@ func _handle_write_isa_command(data: PackedByteArray, address: String, port: int
_written_isa_ports.append([port_addr, value]) # Добавляем новый порт
added_ports += 1
# Выводим суммарное сообщение вместо спама для каждого порта
if added_ports > 0 or updated_ports > 0:
print("Обработана команда записи от %s:%d - добавлено: %d, обновлено: %d портов" % [address, port, added_ports, updated_ports])
@@ -524,7 +503,7 @@ func _parse_command_ports(data: PackedByteArray) -> Array:
for i in range(ports_count):
var port_address = data.decode_u16(8 + i * 2)
ports.append(port_address)
print("Порт %d: 0x%04X" % [i, port_address])
print("Порт %d: 0x%03X" % [i, port_address])
return ports