From bbfae5e34169ff153d6e76588d4747378de616be Mon Sep 17 00:00:00 2001 From: MaD_CaT Date: Tue, 20 Jan 2026 10:10:47 +0300 Subject: [PATCH 1/7] =?UTF-8?q?Godot4.=20=D0=98=D0=B7=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B0=D0=B7=D0=BC=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=20=D0=BE=D1=82=D1=81=D1=82=D1=83=D0=BF=D0=BE=D0=B2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scenes/работа/работа.tscn | 2 +- scripts/prd-ctl-config.gd | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/scenes/работа/работа.tscn b/scenes/работа/работа.tscn index 0759e92e..8d9c5f26 100644 --- a/scenes/работа/работа.tscn +++ b/scenes/работа/работа.tscn @@ -389,8 +389,8 @@ texture_normal = ExtResource("14_ggrwd") [connection signal="toggled" from="btn_activate" to="." method="on_btn_activate_toggled"] [connection signal="toggled" from="btn_center" to="." method="on_btn_center_toggled"] [connection signal="button_down" from="zoom_plus" to="tilemap" method="_on_zoom_plus_button_down"] -[connection signal="button_up" from="zoom_plus" to="tilemap" method="_on_zoom_plus_button_up"] [connection signal="button_up" from="zoom_plus" to="tilemap" method="_on_zoom_button_up"] +[connection signal="button_up" from="zoom_plus" to="tilemap" method="_on_zoom_plus_button_up"] [connection signal="button_down" from="zoom_minus" to="tilemap" method="_on_zoom_minus_button_down"] [connection signal="button_up" from="zoom_minus" to="tilemap" method="_on_zoom_button_up"] [connection signal="pressed" from="btn_all_work" to="." method="_on_btn_all_work_pressed"] diff --git a/scripts/prd-ctl-config.gd b/scripts/prd-ctl-config.gd index b5851062..c21ca4c8 100644 --- a/scripts/prd-ctl-config.gd +++ b/scripts/prd-ctl-config.gd @@ -154,7 +154,7 @@ func _ensure_config_exists() -> bool: # Проверяем, нужно ли обновить конфигурацию if _should_update_config(): return _update_config() - + # Если файл уже существует - все ок if FileAccess.file_exists(CONFIG_PATH): return true @@ -172,13 +172,13 @@ func _should_update_config() -> bool: # Если файла конфигурации нет - нужно создать if not FileAccess.file_exists(CONFIG_PATH): return true - + # Проверяем версию существующей конфигурации var config_file = FileAccess.open(CONFIG_PATH, FileAccess.READ) if config_file: var json_text = config_file.get_as_text() config_file.close() - + var json = JSON.new() if json.parse(json_text) == OK: var existing_version = json.data.get("config_version", "0.0.0") @@ -187,7 +187,7 @@ func _should_update_config() -> bool: else: # Если ошибка парсинга - нужно обновить return true - + return false @@ -196,16 +196,16 @@ func _should_update_config() -> bool: static func _compare_versions(version1: String, version2: String) -> int: var v1_parts = version1.split(".") var v2_parts = version2.split(".") - + for i in range(max(v1_parts.size(), v2_parts.size())): var v1_part = int(v1_parts[i]) if i < v1_parts.size() else 0 var v2_part = int(v2_parts[i]) if i < v2_parts.size() else 0 - + if v1_part < v2_part: return -1 elif v1_part > v2_part: return 1 - + return 0 @@ -216,7 +216,7 @@ func _update_config() -> bool: var backup_path = CONFIG_PATH + ".backup_v" + _current_version DirAccess.copy_absolute(CONFIG_PATH, backup_path) print("Создана резервная копия: ", backup_path) - + # Копируем актуальную конфигурацию return _copy_default_config() From 98c29329d0d80db96144df6b70997714598373cb Mon Sep 17 00:00:00 2001 From: MaD_CaT Date: Tue, 20 Jan 2026 10:13:28 +0300 Subject: [PATCH 2/7] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F.=20=D0=A3=D0=B4=D0=B0=D0=BB=D1=91?= =?UTF-8?q?=D0=BD=20=D0=BB=D0=B8=D1=88=D0=BD=D0=B8=D0=B9=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=D0=BD=D1=82.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scenes/настройки/настройки.gd | 1 - scenes/работа/работа.tscn | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/scenes/настройки/настройки.gd b/scenes/настройки/настройки.gd index 2b6c54c2..fef86543 100644 --- a/scenes/настройки/настройки.gd +++ b/scenes/настройки/настройки.gd @@ -318,7 +318,6 @@ func on_color_closed(color_btn_act: ColorPickerButton): func _autosave_now() -> void: - print("AUTOSAVE") var json_data = {} for i in SETTING_TABLE.size(): var parameter = SETTING_TABLE[i][0] diff --git a/scenes/работа/работа.tscn b/scenes/работа/работа.tscn index 63389127..6220c622 100644 --- a/scenes/работа/работа.tscn +++ b/scenes/работа/работа.tscn @@ -389,8 +389,8 @@ texture_normal = ExtResource("14_ggrwd") [connection signal="toggled" from="btn_activate" to="." method="on_btn_activate_toggled"] [connection signal="toggled" from="btn_center" to="." method="on_btn_center_toggled"] [connection signal="button_down" from="zoom_plus" to="tilemap" method="_on_zoom_plus_button_down"] -[connection signal="button_up" from="zoom_plus" to="tilemap" method="_on_zoom_button_up"] [connection signal="button_up" from="zoom_plus" to="tilemap" method="_on_zoom_plus_button_up"] +[connection signal="button_up" from="zoom_plus" to="tilemap" method="_on_zoom_button_up"] [connection signal="button_down" from="zoom_minus" to="tilemap" method="_on_zoom_minus_button_down"] [connection signal="button_up" from="zoom_minus" to="tilemap" method="_on_zoom_button_up"] [connection signal="pressed" from="btn_all_work" to="." method="_on_btn_all_work_pressed"] From 6950b09879c2e503eb0909d67c5ff3b7f08df503 Mon Sep 17 00:00:00 2001 From: MaD_CaT Date: Fri, 23 Jan 2026 11:23:36 +0300 Subject: [PATCH 3/7] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=BA=D0=B0.=20=D0=A3=D0=BF=D1=80=D0=BE=D1=89=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D1=81=D1=87=D1=91=D1=82=D1=87=D0=B8=D0=BA=D0=B0?= =?UTF-8?q?=20=D0=BE=D0=BF=D0=B0=D1=81=D0=BD=D1=8B=D1=85=20=D1=86=D0=B5?= =?UTF-8?q?=D0=BB=D0=B5=D0=B9=20=D0=BF=D1=80=D0=B8=20=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=B5=20=D0=BF=D0=BE=20=D1=81=D0=B2=D0=BE=D0=B8?= =?UTF-8?q?=D0=BC.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scenes/работа/работа.gd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scenes/работа/работа.gd b/scenes/работа/работа.gd index 10d86c7d..fc6b6ae3 100644 --- a/scenes/работа/работа.gd +++ b/scenes/работа/работа.gd @@ -703,5 +703,5 @@ func count_threats(ths): if gos_flag: c = ths.values().filter(func(th: threats.Threat): return th.proto != '').size() else: - c = ths.values().filter(func(th: threats.Threat): return ((th.proto != '') and th.proto not in interfer.gos_protocols)).size() + c = ths.values().filter(func(th: threats.Threat): return not th.gos).size() $count_danger_pad/count_danger.text = '%02d' % c From 8f4134a911e5f9669f4ce1148a464fcaa58a28cc Mon Sep 17 00:00:00 2001 From: MaD_CaT Date: Fri, 30 Jan 2026 11:11:17 +0300 Subject: [PATCH 4/7] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=BA=D0=B0.=20=D0=9E=D0=B1=D0=BC=D0=B5=D0=BD=20=D1=81=205?= =?UTF-8?q?=D0=9F-28=20=D0=B2=D1=8B=D0=BD=D0=B5=D1=81=D0=B5=D0=BD=20=D0=B2?= =?UTF-8?q?=20=D0=BE=D1=82=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20?= =?UTF-8?q?=D0=BF=D0=BE=D1=82=D0=BE=D0=BA.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/network.gd | 91 +----------------------- scripts/tcp5p28.gd | 172 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 159 insertions(+), 104 deletions(-) diff --git a/scripts/network.gd b/scripts/network.gd index 6691fd59..7ea36cc9 100644 --- a/scripts/network.gd +++ b/scripts/network.gd @@ -110,24 +110,6 @@ class SocketUDP extends PacketPeerUDP: push_error('%s: %s', [error_string(rc), addr]) -class SocketTCP extends TCPServer: - const RX_TIMEOUT: int = 1000 ## Время сброса счётчика принятия части пакета. - var peerstream: = PacketPeerStream.new() - var unit_name: StringName ## Уникальное имя устройства - var head_len: int = 8 ## Длина заголовка команды. - var len_place: int = 4 ## Номер начального байта с длинной блока данных. - var type_len: int = 4 ## Количество байт в размере длинны. - var rx_tick: int ## Время приёма последнего пакета. - var rx_all: bool = true ## Флаг, что пакет принят полностью. - var rx_len: int ## Количество принятых байт. - var rx_data: PackedByteArray ## Принятые данные. - var data_len: int ## Размер ожидаемых данных. - - func send_to(data: PackedByteArray): - var peer = peerstream.get_stream_peer() - peer.put_data(data) - - var poll_sockets: Array[SocketUDP] ## Сокеты для непрерывного опроса наличия новых данных var tcp_sockets: Array[Array] ## Сокеты для TCP-соединений var units: Dictionary[StringName, unit.Unit] ## Экземпляры всех сетевых устройств @@ -187,21 +169,6 @@ func create_socket_caps(unit_name: StringName) -> SocketUDP: return sock -## [param unit_name] - Уникальное имя устройства[br] -func create_socket_tcp(unit_name: StringName) -> SocketTCP: - var st = settings.UnitProfiles[unit_name][1] - var addr = st[0] - var port = st[1] - var sock: = SocketTCP.new() - sock.unit_name = unit_name - var rc: = sock.listen(port, addr) - if rc == Error.OK: - log.message(log.INFO, '\"%s\" слушает на %s:%d' % [unit_name, addr, port]) - else: - log.message(log.ERROR, '\"%s\" %s:%d \"%s\"' % [unit_name, addr, port, error_string(rc)]) - return sock - - ## [param unit_name] - Уникальное имя устройства[br] func create_serial(unit_instance: unit.Unit) -> SocketSerial: var st = settings.UnitProfiles[unit_instance.name][1] @@ -279,9 +246,11 @@ func _ready() -> void: dst_ports[unit_name] = unit_profile[3] if proto in TCP_PROTO: + var addr = settings.UnitProfiles[unit_name][1] var unit_tcp = TCP_PROTO[proto].new(unit_name) units[unit_name] = unit_tcp units_tcp[unit_name] = unit_tcp + unit_tcp.open(addr[0], addr[1]) if proto in MODBUS_PROTO: var unit_modbus = MODBUS_PROTO[proto].new(unit_name) @@ -305,7 +274,6 @@ func _ready() -> void: units_nullp[unit_name] = unit_null - tcp_sockets.append([create_socket_tcp('уарэп-5п28'), units_tcp['уарэп-5п28']]) for key: StringName in dst_ports: port_to_unit_name[dst_ports[key]] = key if logger_page: @@ -347,55 +315,6 @@ func poll_receive_udp(sock: SocketUDP) -> bool: return false -func poll_receive_tcp(sock: SocketTCP) -> bool: - if sock.is_connection_available(): # Проверить, если кто то пытается подключиться - var client: = sock.take_connection() # Принять соединение - sock.peerstream.set_stream_peer(client) # Привязать поток к новому клиенту - log.info('подключен: %s:%d к порту: %d' % [ client.get_connected_host(), client.get_connected_port(), client.get_local_port() ]) - var peer = sock.peerstream.get_stream_peer() - if peer: - while true: - var peer_len_data: = peer.get_available_bytes() - if peer_len_data <= 0: - break - get_client_data(sock, peer, peer_len_data) - if sock.unit_name in units_tcp and sock.rx_all: - units_tcp[sock.unit_name].parse(sock.rx_data, tick) - return false - - -func get_client_data(sock: SocketTCP, peer: StreamPeer, peer_len_data: int) -> void: - if tick - sock.rx_tick > sock.RX_TIMEOUT: - sock.rx_all = true - sock.rx_tick = tick - if sock.rx_all: - if peer_len_data >= sock.head_len: - sock.rx_all = false - sock.rx_len = sock.head_len - var head = peer.get_data(sock.head_len) - sock.data_len = head[1].decode_u32(sock.len_place) - var len_data_in_buf = peer.get_available_bytes() - if len_data_in_buf > 0: - sock.rx_data = head[1] - var len_rx = len_data_in_buf - if len_data_in_buf >= sock.data_len: - len_rx = sock.data_len - get_tcp_data(sock, peer, len_rx) - else: - var len_rx = (sock.head_len + sock.data_len) - sock.rx_len - if peer_len_data < len_rx: - len_rx = peer_len_data - get_tcp_data(sock, peer, len_rx) - - -func get_tcp_data(sock: SocketTCP, peer: StreamPeer, len_rx: int): - var temp_data = peer.get_data(len_rx)[1] - sock.rx_data.append_array(temp_data) - sock.rx_len += len_rx - if sock.rx_len == sock.head_len + sock.data_len: - sock.rx_all = true - - func _process(_delta: float) -> void: if Engine.is_editor_hint(): return tick = Time.get_ticks_msec() @@ -421,12 +340,6 @@ func _process(_delta: float) -> void: for unit_name: StringName in units_modbus: var unit_modbus: = units_modbus[unit_name] unit_modbus.process(tick) - for sock_unit: Array in tcp_sockets: - var sock = sock_unit[0] - var unit_tcp = sock_unit[1] - if Error.OK == unit_tcp.process(tick): - sock.send_to(unit_tcp.tx_data) - poll_receive_tcp(sock) poll_sockets.any(poll_receive_udp) diff --git a/scripts/tcp5p28.gd b/scripts/tcp5p28.gd index 1e5699bb..1a3ed439 100644 --- a/scripts/tcp5p28.gd +++ b/scripts/tcp5p28.gd @@ -3,7 +3,6 @@ class_name tcp5_p28 extends Node ## Реализация "Протокол информационного сопряжения. ## СПО АСУ изделия МП-550 с СПО 5П-28 -const ONLINE_TIMEOUT = 5000 ## Время ожидания пакета от 5П-28, мс. const BUFFER_SIZE = 2048 ## Размер приёмного буфера для датаграмм. ## Тип модуляции для запаковки в пакет для 5П-28. @@ -56,24 +55,173 @@ class TCP5P28 extends unit.Unit: 'уарэп-яу07-4в': [8, 7], 'уарэп-яу07-4к': [16, 15] } + signal data_sended() + signal disconnected(rc: Array) + signal connected(rc: Array) signal get_threats(unit: TCP5P28) ## Сигнал запрос целей. signal get_interfers(unit: TCP5P28) ## Запрос состояния выполнения целеуказания. - var tx_stack: Array ## Массив пакетов для отправки. var uarep_state: int = 1 ## Флаги состояния прибора, 0 бит, состояние ПО var uarep_line: int = 3 ## Состояние линии связи с прибором var ext_cu: bool = false + var tx_queue: Array ## Очередь пакетов для отправки + var tx_mutex: Mutex ## Мютекс для очереди передачи + var thread: Thread ## Рабочий поток + var tctl_mutex: Mutex ## Мютекс для управления потоком + var tctl_run: bool ## Управление потоком + + enum STREAM_STATE { + IDLE, + CONNECT, + WAIT, + RX_START, + RX_DONE, + TX_START, + TX_DONE, + ERROR + } + + func _init(nm) -> void: super._init(nm) ext_cu = ProjectSettings.get_setting('application/config/Внешнее управление', false) ProjectSettings.connect('settings_changed', on_setting_changed) + tx_mutex = Mutex.new() + tctl_mutex = Mutex.new() + connect('data_received', on_data_received) + connect('data_sended', on_data_sended) + connect('connected', on_connected) + connect('disconnected', on_disconnected) init_state() + func on_connected(rc: Array): + log.info('Клиент 5П-28 подключен: %s:%s' % [ rc[0], rc[1]] ) + + func on_data_sended(): pass + + func on_data_received(data: PackedByteArray): + var tick: = Time.get_ticks_msec() + parse(data, tick) + + func on_disconnected(rc: Array): + log.info('Клиент 5П-28 отключен: %s:%s' % [ rc[0], rc[1]] ) + if online: + online = false + emit_signal('line_changed', self) + tx_mutex.lock() + tx_queue.clear() + tx_mutex.unlock() + func init_state(): for key in PR_STATE.keys(): var unit_pribor = network.get_unit_instance(key) unit_pribor.connect('line_changed', Callable(self, 'pribor_line_changed').bind(key)) + func open(host: String, port: int): + tctl_run = true + thread = Thread.new() + thread.start(thread_proc.bind(host, port)) + + func close(): + tctl_mutex.lock() + tctl_run = false + tctl_mutex.unlock() + + func thread_proc(host: String, port: int): + var sock = TCPServer.new() + var stream: = StreamPeerTCP.new() + var fsm: = STREAM_STATE.CONNECT + var rx_buff: PackedByteArray + var rx_bytes: int = 0 + var head_len: int = 8 ## Длина заголовка команды. + var len_place: int = 4 ## Номер начального байта с длинной блока данных. + var status: = StreamPeerTCP.Status.STATUS_NONE + var rc: = sock.listen(port, host) + var cl_host: String + var cl_port: int + while true: + stream.poll() + var new_status = stream.get_status() + if status != new_status: + status = new_status + match status: + stream.STATUS_NONE: + call_deferred('emit_signal', 'disconnected', [cl_host, cl_port]) + fsm = STREAM_STATE.ERROR + stream.STATUS_CONNECTED: + cl_host = stream.get_connected_host() + cl_port = stream.get_connected_port() + call_deferred('emit_signal', 'connected', [cl_host, cl_port]) + stream.STATUS_ERROR: + fsm = STREAM_STATE.ERROR + + if fsm == STREAM_STATE.CONNECT: + if sock.is_connection_available(): # Проверить, если кто то пытается подключиться + stream = sock.take_connection() # Принять соединение + new_status = stream.get_status() + if new_status == stream.STATUS_CONNECTED: + fsm = STREAM_STATE.WAIT + else: + fsm = STREAM_STATE.ERROR + elif fsm == STREAM_STATE.WAIT: + if status == stream.STATUS_CONNECTED: + fsm = STREAM_STATE.RX_START + else: + OS.delay_msec(50) + fsm = STREAM_STATE.CONNECT + elif fsm == STREAM_STATE.ERROR: + stream.disconnect_from_host() + fsm = STREAM_STATE.WAIT + OS.delay_msec(1000) + elif fsm == STREAM_STATE.IDLE: + OS.delay_msec(50) + fsm = STREAM_STATE.RX_START + elif fsm == STREAM_STATE.RX_START: + rx_buff.clear() + rx_bytes = 0 + var sz = stream.get_available_bytes() + if sz <= 0: + fsm = STREAM_STATE.TX_START + continue + var rxd = stream.get_data(head_len) + if rxd[0] == Error.OK: + rx_buff.append_array(rxd[1]) + else: + fsm = STREAM_STATE.ERROR + continue + var pay: = rx_buff.decode_u32(len_place) + rx_bytes = pay + head_len + if rx_buff.size() == rx_bytes: + fsm = STREAM_STATE.RX_DONE + else: + rxd = stream.get_data(rx_bytes - rx_buff.size()) + rc = rxd[0] + if rc == Error.OK: + rx_buff.append_array(rxd[1]) + fsm = STREAM_STATE.RX_DONE + else: + fsm = STREAM_STATE.ERROR + elif fsm == STREAM_STATE.RX_DONE: + var rx_data: = rx_buff.duplicate() + call_deferred('emit_signal', 'data_received', rx_data) + fsm = STREAM_STATE.TX_START + elif fsm == STREAM_STATE.TX_START: + tx_mutex.lock() + if not tx_queue.size(): + fsm = STREAM_STATE.IDLE + tx_mutex.unlock() + continue + var data = tx_queue.pop_front() + tx_mutex.unlock() + rc = stream.put_data(data) + if rc == Error.OK: + fsm = STREAM_STATE.TX_DONE + else: + fsm = STREAM_STATE.ERROR + elif fsm == STREAM_STATE.TX_DONE: + call_deferred('emit_signal', 'data_sended') + fsm = STREAM_STATE.RX_START + func pribor_line_changed(u, key): uarep_state = tools.set_bit(uarep_state, PR_STATE[key][0], u.online) uarep_line = tools.set_bit(uarep_state, PR_STATE[key][1], u.online) @@ -95,16 +243,10 @@ class TCP5P28 extends unit.Unit: if cmd_type == CMD_TYPE_IN and ext_cu: set_interfer(data) - func process(tick: int): - if online and ((tick - rx_tick) > ONLINE_TIMEOUT): - online = false - emit_signal('line_changed', self) - if len(tx_stack): - tx_data = tx_stack[0] - tx_stack.remove_at(0) - return Error.OK - else: - return Error.ERR_UNAVAILABLE + func queue_packet(packet: PackedByteArray): + tx_mutex.lock() + tx_queue.append(packet) + tx_mutex.unlock() func pack_threats(ths: Dictionary): var data = PackedByteArray() @@ -117,7 +259,7 @@ class TCP5P28 extends unit.Unit: data.append_array(get_threats_data(th, tick0)) var data_to_send: PackedByteArray = create_header(data_len) data_to_send.append_array(data) - tx_stack.append(data_to_send) + queue_packet(data_to_send) func pack_interfers(interfers: Dictionary, ecms: Dictionary): var data = PackedByteArray() @@ -141,7 +283,7 @@ class TCP5P28 extends unit.Unit: data.append_array(cu_data) var data_to_send: PackedByteArray = create_header(data_len + 4 * interfers.size()) data_to_send.append_array(data) - tx_stack.append(data_to_send) + queue_packet(data_to_send) func create_header(data_len: int): var head_data = PackedByteArray() @@ -210,7 +352,7 @@ class TCP5P28 extends unit.Unit: data_tx.encode_u16(0, err) # Код ошибки var data_to_send: PackedByteArray = create_header(data_len) data_to_send.append_array(data_tx) - tx_stack.append(data_to_send) + queue_packet(data_to_send) func on_setting_changed(): ext_cu = ProjectSettings.get_setting('application/config/Внешнее управление', false) From 996aee4a176cd4a0064e5ebf38cbcb6d449c286a Mon Sep 17 00:00:00 2001 From: MaD_CaT Date: Thu, 5 Feb 2026 16:03:38 +0300 Subject: [PATCH 5/7] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5.=20=D0=9E=D1=88=D0=B8=D0=B1=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=B2=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B5,=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=B3=D0=B4=D0=B0=20=D0=BD=D0=B5=20=D0=BD=D0=B0?= =?UTF-8?q?=D0=B9=D0=B4=D0=B5=D0=BD=D0=B0=20=D0=BD=D0=BE=D0=B4=D0=B0=20?= =?UTF-8?q?=D1=86=D0=B5=D0=BB=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scenes/работа/работа.gd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scenes/работа/работа.gd b/scenes/работа/работа.gd index fc6b6ae3..9bed5f60 100644 --- a/scenes/работа/работа.gd +++ b/scenes/работа/работа.gd @@ -329,7 +329,7 @@ func on_threat_update(th: threats.Threat): func on_interfer_new(ecm): if not interfer.thrs.has(ecm.ispp): return var th_id = interfer.thrs[ecm.ispp] - var bip = get_node('%d' % th_id) + var bip = get_node_or_null('%d' % th_id) if bip != null: if ecm.krp!= interfer.INTERFER_OFF: bip.set_track_visible(true) From 1a08b5ae50cf95333a478c556197c025efd20fa1 Mon Sep 17 00:00:00 2001 From: MaD_CaT Date: Tue, 10 Feb 2026 11:12:54 +0300 Subject: [PATCH 6/7] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F.=20=D0=A1=D0=BE=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D1=8F=D0=BD=D0=B8=D0=B5=20=D0=BB=D0=B8=D0=BD=D0=B8=D0=B8=20?= =?UTF-8?q?=D1=81=D0=B2=D1=8F=D0=B7=D0=B8=20=D1=81=20=D0=BF=D1=80=D0=B8?= =?UTF-8?q?=D0=B1=D0=BE=D1=80=D0=B0=D0=BC=D0=B8=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=D0=B0=D1=87=D0=B8=20=D0=B2=205?= =?UTF-8?q?=D0=9F-28.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/tcp5p28.gd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tcp5p28.gd b/scripts/tcp5p28.gd index 1a3ed439..acd0e6f3 100644 --- a/scripts/tcp5p28.gd +++ b/scripts/tcp5p28.gd @@ -224,7 +224,7 @@ class TCP5P28 extends unit.Unit: func pribor_line_changed(u, key): uarep_state = tools.set_bit(uarep_state, PR_STATE[key][0], u.online) - uarep_line = tools.set_bit(uarep_state, PR_STATE[key][1], u.online) + uarep_line = tools.set_bit(uarep_line, PR_STATE[key][1], u.online) func _to_string() -> String: return String('5П-28: "%s" %s ' % [self.name, ['отключен', 'на связи'][int(online)]]) From 7bfa6413ba9a90e86998998df704ef97a6ad91c8 Mon Sep 17 00:00:00 2001 From: MaD_CaT Date: Tue, 17 Feb 2026 14:23:01 +0300 Subject: [PATCH 7/7] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=BA=D0=B0.=20=D0=9E=D1=82=D0=BA=D0=BB=D1=8E=D1=87=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=81=D0=B8=D0=B3=D0=BD=D0=B0=D0=BB=D0=BE?= =?UTF-8?q?=D0=B2=20=D0=B4=D0=BB=D1=8F=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8?= =?UTF-8?q?=D1=86=D1=8B=20=D0=BF=D0=BE=D0=BC=D0=B5=D1=85=20=D0=B2=20=D1=80?= =?UTF-8?q?=D0=B5=D0=B6=D0=B8=D0=BC=D0=B0=D1=85=20=D0=BE=D1=82=D0=BB=D0=B8?= =?UTF-8?q?=D1=87=D0=BD=D1=8B=D1=85=20=D0=BE=D1=82=20=D1=80=D0=B5=D0=B6?= =?UTF-8?q?=D0=B8=D0=BC=D0=B0=20=D0=A0=D0=B0=D0=B1=D0=BE=D1=82=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scenes/frame-ecm-list/scroll-ecm-list.gd | 60 ++++++++++++++++++++---- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/scenes/frame-ecm-list/scroll-ecm-list.gd b/scenes/frame-ecm-list/scroll-ecm-list.gd index 39933aae..56b92fa2 100644 --- a/scenes/frame-ecm-list/scroll-ecm-list.gd +++ b/scenes/frame-ecm-list/scroll-ecm-list.gd @@ -42,6 +42,16 @@ const INTERFER_NAMES = { 'elrs': 'ЕЛРС' } +var SIGNALS_CONNECTIONS = [ + [signaller, 'interfer_new', 'on_interfer_new'], + [signaller, 'interfer_off', 'on_interfer_off'], + [signaller, 'rto_threat_unsel', 'on_rto_threat_unsel'], + [signaller, 'rto_threat_sel', 'on_rto_threat_sel'], + [interfer, 'interfer_update', 'on_interfer_update'], + [interfer, 'interfer_recommendate', 'on_interfer_recommendate'], + [interfer, 'interfer_resized', 'on_interfer_resized'] ] + + ## Индексы колонок const COLUMN_NUMBER = 0 const COLUMN_NAME = 1 @@ -52,8 +62,10 @@ const TABLE_TEXT_ROWS = 4 var course = 0.0 ## Курс корабля var color_emit: Color +var signal_conections: Array +var ecms: Dictionary ## Словарь с помехами -func on_rto_threat_unsel(_th_id): $table.clear_rows_selected() +func on_rto_threat_unsel(_th_id, _tbl_index): $table.clear_rows_selected() ## Вызывается при нажатии указателем мыши на выбранный ряд. @@ -86,17 +98,20 @@ func on_rto_threat_sel(th_id: int, table_index): # Called when the node enters the scene tree for the first time. func _ready(): var table_index: = Dictionary() - signaller.connect('interfer_new', Callable(self, 'on_interfer_new').bind(table_index)) - signaller.connect('interfer_off', Callable(self, 'on_interfer_off').bind(table_index)) - signaller.connect('rto_threat_unsel', Callable(self, 'on_rto_threat_unsel')) - signaller.connect('rto_threat_sel', Callable(self, 'on_rto_threat_sel').bind(table_index)) - interfer.connect('interfer_update', Callable(self, 'on_interfer_update').bind(table_index)) - interfer.connect('interfer_recommendate', Callable(self, 'on_interfer_recommendate')) + for item in SIGNALS_CONNECTIONS: + item.append(table_index) $table.connect('row_pressed', Callable(self, 'on_row_pressed')) call_deferred('init_table') var unit_nav = network.get_unit_instance('навигация') unit_nav.connect('data_received', on_navi_data_received) ProjectSettings.connect('settings_changed', on_settings_changed) + signaller.connect('режим_работа', connect_all) + signaller.connect('режим_контроль', disconnect_all) + signaller.connect('режим_журнал', disconnect_all) + signaller.connect('режим_эмс', disconnect_all) + signaller.connect('режим_эмс2', disconnect_all) + signaller.connect('режим_настройки', disconnect_all) + connect_all() func init_table(): @@ -180,7 +195,7 @@ func map_th_to_row(ecm) -> Array: return row -func on_interfer_recommendate(ecm): +func on_interfer_recommendate(ecm, _tbl_index): var sel_rows: Array $table.get_selected_rows(sel_rows) if not len(sel_rows): return @@ -207,3 +222,32 @@ func disable_edit(tbl, num_col: int, i_row: int): for col in num_col: var node: LineEdit = tbl.get_node2(col, i_row) node.editable = false + + +func connect_all() -> void: + signal_conections.clear() + var table_index = SIGNALS_CONNECTIONS[0][3] + for item in SIGNALS_CONNECTIONS: + var proc = Callable(self, item[2]).bind(item[3]) + var rc = item[0].connect(item[1], proc) + if rc == Error.OK: + signal_conections.append([item[0], item[1], proc]) + else: + var ers = error_string(rc) + push_error('%s: %s %s %s' % [ers, item[0], item[1], item[2]]) + signaller.emit_signal('connect_work_signal') + for ecm in ecms.values(): + on_interfer_new(ecm, table_index) + + +func disconnect_all() -> void: + var table_index = SIGNALS_CONNECTIONS[0][3] + for item in signal_conections: + item[0].disconnect(item[1], item[2]) + signal_conections.clear() + $table.clear_rows() + table_index.clear() + + +func on_interfer_resized(ecms_dic: Dictionary, _tbl_index) -> void: + ecms = ecms_dic