639 lines
24 KiB
GDScript
639 lines
24 KiB
GDScript
class_name UDPBroadcast
|
||
|
||
# Константы для размеров данных и смещений
|
||
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']
|
||
|
||
# Приватные свойства
|
||
var status_manager: StatusManager
|
||
var logs_manager: LogsRich
|
||
var _socket: SocketUDP
|
||
var _self_name: String
|
||
var _isa_ports: Dictionary = {}
|
||
var _written_isa_ports: Array = []
|
||
var _timer: Timer
|
||
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
|
||
|
||
signal update_isa_ports(_isa_ports: Dictionary)
|
||
signal update_socket_status(_sockets_status_bit: int)
|
||
|
||
|
||
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 not _bind_to_device_address(name):
|
||
push_error('Не удалось инициализировать устройство: %s' % name)
|
||
|
||
|
||
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:
|
||
_log_error('Не удалось привязаться к %s:%d - %s' % [address, port, error_string(bind_result)])
|
||
return false
|
||
|
||
_log_info('Успешно привязано к %s:%d' % [address, port])
|
||
return true
|
||
|
||
|
||
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 соединение закрыто')
|
||
|
||
|
||
#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 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 get_sockets_status() -> int:
|
||
'''Получение статуса сокетов'''
|
||
return _sockets_status_bit
|
||
|
||
|
||
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 _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)
|
||
|
||
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:
|
||
'''Расширенный класс 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
|