From 667f6d997e44a755f31f45ea4a3a5c35743412ec Mon Sep 17 00:00:00 2001
From: TotMaxim
Date: Thu, 20 Nov 2025 12:36:08 +0300
Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82=D0=BE?=
=?UTF-8?q?=D1=80=20=D0=B8=20=D0=B4=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82?=
=?UTF-8?q?=D0=BA=D0=B0=20read=5Fisa,=20write=5Fisa?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
main.gd | 55 ++++-
main.tscn | 5 +
udp_broadcast.gd | 613 +++++++++++++++++++++++++++++++++++++++--------
3 files changed, 564 insertions(+), 109 deletions(-)
diff --git a/main.gd b/main.gd
index a2bc443..7062361 100644
--- a/main.gd
+++ b/main.gd
@@ -36,46 +36,53 @@ 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)
+ udp_broadcast.add_timers_to_scene(self) # Исправлено имя метода
udp_broadcast.start_broadcast()
dictionary_yau07[name_device] = udp_broadcast
+ print("Устройство %s активировано" % name_device)
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)
## Функция для установки статусов ячеек на связи (УГ, ЭМС-Г, УКП)
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%04X" % [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]
- udp_unit.dkm_status_bit = _set_bit(udp_unit.dkm_status_bit, bit, toggled)
-
-
-func _process(_delta: float) -> void:
- for device in dictionary_yau07.keys():
- if dictionary_yau07[device]:
- dictionary_yau07[device].poll_receive()
+ 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%04X" % [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_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)
+ _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:
@@ -167,9 +174,31 @@ 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)
+
+
+## Новый метод для работы с 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
diff --git a/main.tscn b/main.tscn
index 38ea6d6..a80a9f4 100644
--- a/main.tscn
+++ b/main.tscn
@@ -581,6 +581,7 @@ metadata/place = 13
metadata/device = "ПРД-В1"
[node name="dkm" type="GridContainer" parent="TabContainer/ПРД-В1"]
+layout_mode = 0
offset_left = 10.0
offset_top = 201.0
offset_right = 50.0
@@ -639,6 +640,7 @@ metadata/bit = 4
metadata/device = "ПРД-К1"
[node name="ukp_1" type="GridContainer" parent="TabContainer/ПРД-К1"]
+layout_mode = 0
offset_left = 205.0
offset_top = 7.0
offset_right = 939.0
@@ -732,6 +734,7 @@ metadata/place = 5
metadata/device = "ПРД-К1"
[node name="ukp_1_lit_1" type="GridContainer" parent="TabContainer/ПРД-К1"]
+layout_mode = 0
offset_left = 205.0
offset_top = 195.0
offset_right = 939.0
@@ -765,6 +768,7 @@ metadata/place = 0
metadata/device = "ПРД-К1"
[node name="ukp_2" type="GridContainer" parent="TabContainer/ПРД-К1"]
+layout_mode = 0
offset_left = 205.0
offset_top = 103.0
offset_right = 939.0
@@ -858,6 +862,7 @@ metadata/place = 13
metadata/device = "ПРД-К1"
[node name="dkm" type="GridContainer" parent="TabContainer/ПРД-К1"]
+layout_mode = 0
offset_left = 10.0
offset_top = 201.0
offset_right = 50.0
diff --git a/udp_broadcast.gd b/udp_broadcast.gd
index fdd958e..44ebb1e 100644
--- a/udp_broadcast.gd
+++ b/udp_broadcast.gd
@@ -1,6 +1,24 @@
class_name UDPBroadcast
-const addres_list: Dictionary = {
+# Константы для размеров данных и смещений
+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 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"],
@@ -14,133 +32,536 @@ const addres_list: Dictionary = {
'ПРД-В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 _socket: SocketUDP
-var self_name: String
+var _self_name: String
var _timer: Timer
-var sockets_status_bit: int = 0
-var dkm_status_bit: int = 0
+var _poll_timer: Timer
+var _sockets_status_bit: int = 0
+var _dkm_status_bit: int = 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:
- set(v):
- ukp0_data = v
- print('Произошло Обновление данных ukp0_data')
+ set(value):
+ if value.size() == UKP_DATA_SIZE:
+ ukp0_data = value
+ print('Данные UKP0 обновлены')
-var ukp1_data: PackedByteArray:
- set(v):
- ukp1_data = v
- print('Произошло Обновление данных ukp1_data')
+
+var ukp1_data: PackedByteArray:
+ set(value):
+ if value.size() == UKP_DATA_SIZE:
+ ukp1_data = value
+ print('Данные UKP1 обновлены')
func _init(name: String):
- self_name = name
+ """Инициализация UDP broadcast клиента"""
+ _self_name = name
+ _initialize_socket()
+ _initialize_ukp_data()
+ _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 / 3.0
- _timer.timeout.connect(_on_timer_timeout)
- ukp0_data.resize(32)
- ukp0_data.fill(0)
- ukp1_data.resize(32)
- ukp1_data.fill(0)
+ _timer.timeout.connect(_on_broadcast_timeout)
- 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)
+ # Таймер для частого опроса сокета (100 раз в секунду)
+ _poll_timer = Timer.new()
+ _poll_timer.wait_time = 0.01
+ _poll_timer.timeout.connect(_on_poll_timeout)
-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_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)
+
+
+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: %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)
+ push_error("Не удалось привязаться к %s:%d - %s" % [address, port, error_string(bind_result)])
+ return false
+
+ print("Успешно привязано к %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:
+ push_warning("Таймер broadcast уже добавлен в другую сцену")
+
+ 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()
+ print("Широковещательная рассылка запущена")
+
+
+func stop_broadcast() -> void:
+ """Остановка широковещательной рассылки"""
_timer.stop()
+ _poll_timer.stop()
+ print("Широковещательная рассылка остановлена")
+
+
+func close_udp_unit() -> void:
+ """Закрытие UDP соединения"""
+ stop_broadcast()
_socket.close()
+ print("UDP соединение закрыто")
-func add_timer_to_scene(parent: Node) -> void:
- parent.add_child(_timer)
+#region Публичные методы для управления состоянием
+
+func set_sockets_status(status: int) -> void:
+ """Установка статуса сокетов"""
+ _sockets_status_bit = 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 get_sockets_status() -> int:
+ """Получение статуса сокетов"""
+ return _sockets_status_bit
-func _handle_received_data(data: PackedByteArray, addr: String) -> void:
- print("данные от %s: %s" % [addr, data])
- # Здесь можно эмитировать сигналы или обрабатывать данные
+func set_dkm_status(status: int) -> void:
+ """Установка статуса DKM"""
+ _dkm_status_bit = status
-func _on_timer_timeout() -> void:
+func get_dkm_status() -> int:
+ """Получение статуса DKM"""
+ return _dkm_status_bit
+
+
+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)
+ return false
+
+ _isa_ports[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:
+ push_error("UDPBroadcast: Некорректный адрес порта: " + 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_u8(35, 0x00)
- buf.encode_u8(36, dkm_status_bit)
- 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:
+ push_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)
+ print('_written_isa_ports.size(): ', _written_isa_ports.size())
+ # Добавляем поле команды после статуса
+ 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"""
+ var ems_g_data = [
+ 0x9e00, 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0x0000,
+ 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff
+ ]
+
+ for i in range(ems_g_data.size()):
+ buffer.encode_u16(EMS_G_DATA_OFFSET + i * 2, ems_g_data[i])
+
+
+func _encode_ug_data(buffer: PackedByteArray) -> void:
+ """Кодирование данных UG"""
+ buffer.encode_u16(UG_DATA_OFFSET, _dkm_status_bit) # Статус DKM
+ buffer.encode_u16(UG_DATA_OFFSET + 2, 0x059e) # DRY CONTACT
+
+
+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:
+ print("Отправлен немедленный ответ на %s:%d" % [address, port])
+ else:
+ push_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)
+ if command_type == -1: # Проверяем на -1 вместо null
+ return
+ _cmd_number_count = (_cmd_number_count + 1) & 0xFFFF
+ _handle_isa_command(command_type, data, address, port)
+
+
+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() < 7:
+ return -1 # Используем -1 для обозначения ошибки
+
+ # Определяем длину статуса из заголовка
+ var status_length = data.decode_u8(7)
+ if data.size() <= (status_length + 8):
+ 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)
+ _:
+ push_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)
+ print('Принята команда на чтение ISA портов от %s:%d: %s' % [address, port, port_data])
+
+
+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():
+ push_warning("Несоответствие размеров портов и данных от %s:%d" % [address, port])
+ return
+
+ var added_ports = 0
+ var updated_ports = 0
+
+ # Обновляем или добавляем записанные порты
+ 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
+ updated_ports += 1
+ break
+
+ if not found:
+ _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])
+
+ print('Принята команда на запись в 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 = []
+ 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])
+
+ 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 * 2 < data.size():
+ var port_data = data.decode_u16(data_offset + i * 2)
+ ports_data.append(port_data)
+ print("Данные порта %d: 0x%04X" % [i, 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 Вложенный класс 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()
+ print("Список записанных портов очищен")
+
+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)
+ print("Порт 0x%04X удален из списка записанных" % port_addr)
+ return true
+ return false
+
+#endregion