diff --git a/project.godot b/project.godot index 2d08c71..dba11e7 100644 --- a/project.godot +++ b/project.godot @@ -13,6 +13,7 @@ config_version=5 config/name="uarep-ctl" run/main_scene="res://scenes/tab_switch.tscn" config/features=PackedStringArray("4.1") +run/low_processor_mode=true run/delta_smoothing=false boot_splash/show_image=false boot_splash/fullsize=false @@ -21,11 +22,12 @@ config/icon="res://data/icon.png" [autoload] +Log="*res://addons/godot-logger/scripts/logger.gd" Tools="*res://scripts/tools.gd" REPSettings="*res://scripts/repsettings.gd" REPNetwork="*res://scripts/repnetwork.gd" yau07="*res://scripts/yau07.gd" -Log="*res://addons/godot-logger/scripts/logger.gd" +capsrpb="*res://scripts/capsrpb.gd" Table="*res://table/table.gd" Threats="*res://scripts/threats.gd" YemsDevs="*res://scripts/yems_devs.gd" @@ -33,6 +35,16 @@ YemsDevs="*res://scripts/yems_devs.gd" [debug] file_logging/enable_file_logging=true +gdscript/warnings/exclude_addons=false +gdscript/warnings/unassigned_variable=2 +gdscript/warnings/unassigned_variable_op_assign=2 +gdscript/warnings/shadowed_variable=2 +gdscript/warnings/shadowed_variable_base_class=2 +gdscript/warnings/shadowed_global_identifier=2 +gdscript/warnings/unsafe_cast=1 +gdscript/warnings/assert_always_true=2 +gdscript/warnings/assert_always_false=2 +gdscript/warnings/integer_division=0 [display] @@ -48,7 +60,7 @@ version_control/autoload_on_startup=true [editor_plugins] -enabled=PackedStringArray("res://addons/godot-logger/plugin.cfg") +enabled=PackedStringArray() [gui] diff --git a/scenes/bip.tscn b/scenes/bip.tscn index ec38fa0..18854c9 100644 --- a/scenes/bip.tscn +++ b/scenes/bip.tscn @@ -1,10 +1,10 @@ -[gd_scene load_steps=5 format=3 uid="uid://cfk41dnfbr0wx"] +[gd_scene load_steps=5 format=3 uid="uid://nl1vklubr5kr"] [ext_resource type="Shader" path="res://shaders/bip.gdshader" id="1_k6vue"] [sub_resource type="ShaderMaterial" id="ShaderMaterial_2dulj"] shader = ExtResource("1_k6vue") -shader_parameter/color = Color(0.666667, 0.690196, 0.807843, 1) +shader_parameter/color = Color(1, 0.101961, 0.494118, 1) [sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_tgf76"] diff --git a/scenes/frm_threats.gd b/scenes/frm_threats.gd new file mode 100644 index 0000000..7fe42c3 --- /dev/null +++ b/scenes/frm_threats.gd @@ -0,0 +1,35 @@ +extends "res://scenes/рамка.gd" + +var TableHeader = preload('res://table/header.tscn') +var TableNode = preload('res://table/node.tscn') + + +func _ready() -> void: + assert(TableHeader) + assert(TableNode) + call_deferred('init_table') + + +func init_table(): + $scrl_threats/tbl_threats.set_header([TableHeader, TableHeader, TableHeader, TableHeader]) + $scrl_threats/tbl_threats.set_header_text(['Номер', 'Пеленг', 'Частота, МГц', 'Назначено']) + $scrl_threats/tbl_threats.set_columns_min_size([50, 140, 140, 100]) + $scrl_threats/tbl_threats.pin_header($scrl_threats, self) + $scrl_threats/tbl_threats.connect('row_pressed', Callable(self, 'on_row_pressed')) + + +func on_row_pressed(i_row: int): + $scrl_threats/tbl_threats.set_row_selected(i_row, true) + + +func _on_btn_add_thr_pressed() -> void: + var i_row = $scrl_threats/tbl_threats.get_rows_count() + $scrl_threats/tbl_threats.add_row([TableNode, TableNode, TableNode, TableNode]) + $scrl_threats/tbl_threats.set_row_text(i_row, ['%d' % i_row, '%d' % ((i_row * 100) + 2000), '%d' % ((i_row * 20) % 360), 'Нет']) + + +func _on_btn_del_thr_pressed() -> void: + var i_rows: = Array() + $scrl_threats/tbl_threats.get_selected_rows(i_rows) + for i in i_rows: + $scrl_threats/tbl_threats.remove_row(i) diff --git a/scenes/pribor_spt_r.tscn b/scenes/pribor_spt_r.tscn index 62c0337..6834bbe 100644 --- a/scenes/pribor_spt_r.tscn +++ b/scenes/pribor_spt_r.tscn @@ -1,10 +1,6 @@ -[gd_scene format=2] +[gd_scene format=3 uid="uid://bv0dyyaodxcvc"] [node name="pribor_UF" type="Node2D"] [node name="test_label" type="Label" parent="."] -margin_left = 12.0 -margin_top = 8.0 -margin_right = 154.0 -margin_bottom = 22.0 text = "Здесь будет схема прибора СПТ Правый" diff --git a/scenes/tab_switch.gd b/scenes/tab_switch.gd new file mode 100644 index 0000000..c287888 --- /dev/null +++ b/scenes/tab_switch.gd @@ -0,0 +1,15 @@ +extends TabContainer + + +# Called when the node enters the scene tree for the first time. +func _ready() -> void: + pass + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +func _process(delta: float) -> void: + pass + + +func _enter_tree() -> void: + REPNetwork.logger_page = $'журнал' diff --git a/scenes/tab_switch.tscn b/scenes/tab_switch.tscn index aec5f96..32af829 100644 --- a/scenes/tab_switch.tscn +++ b/scenes/tab_switch.tscn @@ -1,5 +1,6 @@ [gd_scene load_steps=5 format=3 uid="uid://3slb0i3pvowc"] +[ext_resource type="Script" path="res://scenes/tab_switch.gd" id="1_33fiq"] [ext_resource type="PackedScene" uid="uid://b276iygic5itk" path="res://scenes/работа.tscn" id="1_uow82"] [ext_resource type="PackedScene" uid="uid://lwmw4egynmd1" path="res://scenes/контроль.tscn" id="2_83m7a"] [ext_resource type="PackedScene" uid="uid://trt0q8th3bn2" path="res://scenes/журнал.tscn" id="3_hgnup"] @@ -8,6 +9,7 @@ [node name="tab_switch" type="TabContainer"] offset_right = 1600.0 offset_bottom = 1200.0 +script = ExtResource("1_33fiq") [node name="работа" parent="." instance=ExtResource("1_uow82")] layout_mode = 2 diff --git a/scenes/журнал.gd b/scenes/журнал.gd index 214a680..6d19807 100644 --- a/scenes/журнал.gd +++ b/scenes/журнал.gd @@ -1,9 +1,19 @@ extends Control +func _ready() -> void: Log.info('Модуль журнала работы готов') +func on_line_changed(unit, addr): Log.message(Logger.INFO, 'состоянии связи: %s %s' % [unit, addr]) +func on_command_fail(unit, addr): Log.message(Logger.ERROR, 'команда не выполнена: %s %s' % [unit, addr]) + + func _on_clear_button_down() -> void: +<<<<<<< HEAD $content.clear() Log.info('содержание журнала очищено оператором') +======= + $content.clear() + Log.info('Cодержание журнала очищено оператором') +>>>>>>> sasha/master func _on_btn_save_button_down() -> void: diff --git a/scenes/журнал.tscn b/scenes/журнал.tscn index cfd4ac8..5d29c55 100644 --- a/scenes/журнал.tscn +++ b/scenes/журнал.tscn @@ -15,10 +15,11 @@ script = ExtResource("1_3f1mv") [node name="content" type="RichTextLabel" parent="."] layout_mode = 0 offset_left = 16.0 -offset_top = 57.0 +offset_top = 16.0 offset_right = 1584.0 -offset_bottom = 999.0 +offset_bottom = 1059.0 focus_mode = 2 +theme_override_colors/selection_color = Color(0.72549, 0.270588, 0.133333, 1) threaded = true selection_enabled = true deselect_on_focus_loss_enabled = false @@ -26,18 +27,18 @@ script = ExtResource("1_t5g4h") [node name="btn_save" type="Button" parent="."] layout_mode = 0 -offset_left = 1344.0 -offset_top = 1044.0 -offset_right = 1440.0 -offset_bottom = 1080.0 +offset_left = 1464.0 +offset_top = 1080.0 +offset_right = 1560.0 +offset_bottom = 1116.0 text = "Сохранить" [node name="btn_clear" type="Button" parent="."] layout_mode = 0 -offset_left = 1200.0 -offset_top = 1044.0 -offset_right = 1296.0 -offset_bottom = 1080.0 +offset_left = 1344.0 +offset_top = 1080.0 +offset_right = 1440.0 +offset_bottom = 1116.0 text = "Очистить" [node name="dlg_file" type="FileDialog" parent="."] diff --git a/scenes/работа.gd b/scenes/работа.gd index 74ea742..fa9ed2a 100644 --- a/scenes/работа.gd +++ b/scenes/работа.gd @@ -9,7 +9,6 @@ extends Panel @export var drag_scale_width: float @export var drag_scale_band: float @export var window_0_id: int -@export var window_1_id: int signal add_imit_threat (signal_name: String) signal del_imit_threat (signal_name: String) @@ -156,9 +155,14 @@ func toggle_full_screen(id: int): func _on_full_screen(): +<<<<<<< HEAD toggle_full_screen(window_1_id) toggle_full_screen(window_0_id) func _on_btn_down(signal_name: String) -> void: emit_signal(signal_name) +======= + toggle_full_screen(window_0_id) + +>>>>>>> sasha/master diff --git a/scenes/работа.tscn b/scenes/работа.tscn index 02292ff..e9a3cb6 100644 --- a/scenes/работа.tscn +++ b/scenes/работа.tscn @@ -1,9 +1,10 @@ -[gd_scene load_steps=7 format=3 uid="uid://b276iygic5itk"] +[gd_scene load_steps=8 format=3 uid="uid://b276iygic5itk"] [ext_resource type="Script" path="res://scenes/работа.gd" id="1_qjoce"] [ext_resource type="PackedScene" uid="uid://b5kjdyxuwsot5" path="res://scenes/canvas.tscn" id="2_bl0yt"] [ext_resource type="PackedScene" uid="uid://bq7haw1ypiv48" path="res://scenes/frame.tscn" id="3_l1omj"] [ext_resource type="PackedScene" uid="uid://da7w3vkhadfwe" path="res://scenes/button_flat.tscn" id="4_5es2r"] +[ext_resource type="Script" path="res://scenes/frm_threats.gd" id="4_hg23i"] [ext_resource type="Script" path="res://table/table.gd" id="4_mqhcf"] [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_5ugj8"] @@ -18,7 +19,6 @@ strob_min_band = 0.1 strob_max_band = 15.538 drag_scale_width = 0.5 drag_scale_band = 0.05 -window_1_id = 1 metadata/_edit_vertical_guides_ = [] metadata/_edit_lock_ = true @@ -31,19 +31,15 @@ offset_left = 1121.0 offset_top = 6.0 offset_right = 1594.0 offset_bottom = 642.0 +script = ExtResource("4_hg23i") text = "Список целей" - -[node name="tbl_threats" type="GridContainer" parent="frm_threats"] -layout_mode = 0 -offset_right = 40.0 -offset_bottom = 40.0 -script = ExtResource("4_mqhcf") +metadata/_edit_lock_ = true [node name="рамка-параметры-цели" parent="frm_threats" instance=ExtResource("3_l1omj")] layout_mode = 0 offset_left = 5.0 offset_top = 313.0 -offset_right = 467.0 +offset_right = 465.0 offset_bottom = 632.0 text = "Параметры цели" @@ -218,6 +214,19 @@ scale = Vector2(1, 0.6) tooltip_text = "Удалить цель" text = "-" +[node name="scrl_threats" type="ScrollContainer" parent="frm_threats"] +layout_mode = 0 +offset_left = 8.0 +offset_top = 57.0 +offset_right = 464.0 +offset_bottom = 306.0 +horizontal_scroll_mode = 0 + +[node name="tbl_threats" type="GridContainer" parent="frm_threats/scrl_threats"] +layout_mode = 2 +columns = 4 +script = ExtResource("4_mqhcf") + [node name="рамка-сеансы-помех" parent="." instance=ExtResource("3_l1omj")] layout_mode = 0 offset_left = 1121.0 @@ -647,5 +656,5 @@ metadata/rfi_name = "" [connection signal="drag_begin" from="." to="." method="_on_drag_begin"] [connection signal="drag_continue" from="." to="." method="_on_drag_continue"] [connection signal="full_screen" from="." to="." method="_on_full_screen" flags=3] -[connection signal="button_down" from="frm_threats/btn_add_thr" to="." method="_on_btn_down" binds= ["add_imit_threat"]] -[connection signal="button_down" from="frm_threats/btn_del_thr" to="." method="_on_btn_down" binds= ["del_imit_threat"]] +[connection signal="pressed" from="frm_threats/btn_add_thr" to="frm_threats" method="_on_btn_add_thr_pressed"] +[connection signal="pressed" from="frm_threats/btn_del_thr" to="frm_threats" method="_on_btn_del_thr_pressed"] diff --git a/scripts/capsrpb.gd b/scripts/capsrpb.gd new file mode 100644 index 0000000..435266b --- /dev/null +++ b/scripts/capsrpb.gd @@ -0,0 +1,38 @@ +extends Node + +const ONLINE_TIMEOUT = 5.0 # Время ожидания пакета от ячейки, секунды +const BUFFER_SIZE = 2048 + + +class CapsRpb: + signal line_changed(unit: CapsRpb) + signal command_done(unit: CapsRpb) + signal command_fail(unit: CapsRpb) + var online: = false + var name: = String() + var test_json_conv: JSON + var tick: = 0.0 + var tick_rx: = 0.0 + + func _to_string() -> String: return String('капсрпб: "%s" %s ' % [self.name, ['отключен', 'на связи'][int(online)]]) + func _init(nm): + test_json_conv = JSON.new() + self.name = nm + + + func parse(data): + tick_rx = tick + if not online: + online = true + emit_signal('line_changed', self) + var utf8_data = data.get_string_from_utf8() + test_json_conv.parse(utf8_data) + var json = test_json_conv.get_data() + print_debug(json) + + + func process(delta: float): + tick += delta + if online and ((tick - tick_rx) > ONLINE_TIMEOUT): + online = false + emit_signal('line_changed', self) diff --git a/scripts/repnetwork.gd b/scripts/repnetwork.gd index 3f9f59e..dbbf81a 100644 --- a/scripts/repnetwork.gd +++ b/scripts/repnetwork.gd @@ -1,36 +1,69 @@ extends Node -var sock_unicast: PacketPeerUDP -var sock_broadcast: PacketPeerUDP -var units_yau07: Dictionary +class Socket extends PacketPeerUDP: + func send_to(addr, data): + self.set_dest_address(addr[0], addr[1]) + self.put_packet(data) + + +const PROTO_TYPE: = {'yau07tx': yau07.YaU07, 'jsontx': capsrpb.CapsRpb} +var poll_sockets: Array[Socket] +var units: Dictionary +var sock_unicast: Socket +var logger_page: Node + + +func create_socket(nm) -> Socket: + var addr = REPSettings.addr[nm][1] + var port = REPSettings.addr[nm][2] + var broad = REPSettings.addr[nm][3] + var bind = REPSettings.addr[nm][4] + var sock: = Socket.new() + sock.set_broadcast_enabled(broad) + var rc = Error.OK if not bind else sock.bind(port, addr) + var errlevel = Log.INFO if rc == Error.OK else Log.ERROR + Log.message(errlevel, '%s: сокет:%s:%d привязанный:%s %s' % [nm, addr, port, ['нет', 'да'][int(bind)], error_string(rc)]) + return sock func _ready() -> void: - var addr = REPSettings.addr['уарэп-яу07-частный'][1] - var port = REPSettings.addr['уарэп-яу07-частный'][2] - sock_unicast = PacketPeerUDP.new() - sock_unicast.bind(port, addr) + Log.info('Сетевой модуль готов') + poll_sockets.append(create_socket('уарэп-яу07-частный')) + poll_sockets.append(create_socket('уарэп-яу07-общий')) + poll_sockets.append(create_socket('уарэп-капсрпб-пол')) + + sock_unicast = poll_sockets[0] + for key in REPSettings.addr: - var prof = REPSettings.addr[key] - if prof[0] == 'yau07': - addr = REPSettings.addr[key][1] - port = REPSettings.addr[key][2] - var unit = yau07.YaU07.new([addr, port]) - var addr_port: String = '%s:%d' % [addr, port] - units_yau07[addr_port] = unit - Log.info('ЯУ-07: %s' % unit) + var setting = REPSettings.addr[key] + var proto = setting[0] + if proto in PROTO_TYPE: + var unit = PROTO_TYPE[proto].new(key) + var addr = Array([setting[1], setting[2]]) + units[addr] = unit + unit.connect('line_changed', Callable(logger_page, 'on_line_changed').bind(addr)) + unit.connect('command_fail', Callable(logger_page, 'on_command_fail').bind(addr)) + + for addr in units: + var unit = units[addr] + Log.info('%s %s:%d' % [unit.name, addr[0], addr[1]]) + + +func poll_receive(sock: Socket): + while sock.get_available_packet_count() > 0: + var data: = sock.get_packet() + var addr: = sock.get_packet_ip() + var port: = sock.get_packet_port() + var addr_port: = [addr, port] + if addr_port in units: units[addr_port].parse(data) func _process(delta: float) -> void: - for unit in units_yau07.values() as Array[yau07.YaU07]: - unit.process(delta, sock_unicast) - - while sock_unicast.get_available_packet_count() > 0: - var data = sock_unicast.get_packet() - var addr = sock_unicast.get_packet_ip() - var port = sock_unicast.get_packet_port() - var addr_port: String = '%s:%d' % [addr, port] - if addr_port in units_yau07: - var unit: yau07.YaU07 = units_yau07[addr_port] - unit.parse(data) + for addr in units: + var unit = units[addr] + match unit.process(delta): + Error.OK: sock_unicast.send_to(addr, unit.data_tx) + Error.FAILED: emit_signal('socket_error', 'ошибка: %s %s:%d' % [unit, addr[0], addr[1]]) + for sock in poll_sockets: + poll_receive(sock) diff --git a/scripts/repsettings.gd b/scripts/repsettings.gd index c2780f3..e069f9d 100644 --- a/scripts/repsettings.gd +++ b/scripts/repsettings.gd @@ -1,5 +1,6 @@ extends Node +<<<<<<< HEAD @export var addr: Dictionary = { \ 'уарэп-яу07-частный': ['udp', '10.1.1.160', 50160, 'IP-адрес ЯУ-07 прибора УФ'], 'уарэп-яу07-общий': ['udp', '10.1.1.255', 50000, 'IP-адрес для приёма широковещательных пакетов от ЯУ-07'], @@ -19,3 +20,30 @@ extends Node 'уарэп-яу07-3н': ['yau07', '10.1.1.49', 50049, 'IP-адрес ЯУ-07 прибора ПРД-Н'], 'уарэп-яу07-3к': ['yau07', '10.1.1.51', 50051, 'IP-адрес ЯУ-07 прибора ПРД-Н'], 'уарэп-щ3': ['uart', '/dev/stty0', 115200, 1, 1, false, 1000, 'Прибор Щ3 (скорость, стартовых, стоповых, чётность, таймаут в мкс)'] } +======= + +@export var addr: = { \ +# Название Протокол Адрес Порт Широков. Привяз. Комментарий + 'уарэп-яу07-частный': ['yau07rx', '127.0.0.1', 50079, false, true, 'IP-адрес на котором принимают частные сообщения от ЯУ-07'], + 'уарэп-яу07-общий': ['yau07rx', '127.0.0.255', 50000, true, true, 'IP-адрес на котором принимают широковещательные сообщения от ЯУ-07'], + 'уарэп-капсрпб-пол': ['jsonrx', '127.0.0.1', 42023, false, true, 'IP-адрес на котором принимают сообщения от КАПС РПБ'], + 'уарэп-капсрпб-отп': ['jsontx', '127.0.0.1', 42022, false, false, 'IP-адрес на который отправляют сообщения для КАПС РПБ'], + 'уарэп-эмс': ['yau07tx', '10.1.1.27', 50027, false, false, 'IP-адрес ЯУ-07 прибора УФ'], + 'уарэп-яу07-2в': ['yau07tx', '10.1.1.34', 50034, false, false, 'IP-адрес ЯУ-07 прибора ПРД-В'], + 'уарэп-яу07-2н': ['yau07tx', '10.1.1.33', 50033, false, false, 'IP-адрес ЯУ-07 прибора ПРД-Н'], + 'уарэп-яу07-2к': ['yau07tx', '10.1.1.35', 50035, false, false, 'IP-адрес ЯУ-07 прибора ПРД-К'], + 'уарэп-яу07-4в': ['yau07tx', '10.1.1.66', 50066, false, false, 'IP-адрес ЯУ-07 прибора ПРД-В'], + 'уарэп-яу07-4н': ['yau07tx', '10.1.1.65', 50065, false, false, 'IP-адрес ЯУ-07 прибора ПРД-Н'], + 'уарэп-яу07-4к': ['yau07tx', '10.1.1.67', 50067, false, false, 'IP-адрес ЯУ-07 прибора ПРД-К'], + 'уарэп-яу07-1в': ['yau07tx', '10.1.1.18', 50018, false, false, 'IP-адрес ЯУ-07 прибора ПРД-В'], + 'уарэп-яу07-1н': ['yau07tx', '10.1.1.17', 50017, false, false, 'IP-адрес ЯУ-07 прибора ПРД-Н'], + 'уарэп-яу07-1к': ['yau07tx', '10.1.1.19', 50019, false, false, 'IP-адрес ЯУ-07 прибора ПРД-К'], + 'уарэп-яу07-3в': ['yau07tx', '10.1.1.50', 50050, false, false, 'IP-адрес ЯУ-07 прибора ПРД-В'], + 'уарэп-яу07-3н': ['yau07tx', '10.1.1.49', 50049, false, false, 'IP-адрес ЯУ-07 прибора ПРД-Н'], + 'уарэп-яу07-3к': ['yau07tx', '10.1.1.51', 50051, false, false, 'IP-адрес ЯУ-07 прибора ПРД-Н'], + 'уарэп-щ3': ['uart', '/dev/stty0', 115200, 1, 1, false, 1000, 'Прибор Щ3'] } # скорость, стартовых, стоповых, чётность, таймаут в мкс + + +func _ready() -> void: + Log.info('Модуль настроек готов') +>>>>>>> sasha/master diff --git a/scripts/threats.gd b/scripts/threats.gd index 209db54..75717a8 100644 --- a/scripts/threats.gd +++ b/scripts/threats.gd @@ -1,8 +1,15 @@ extends Node +enum ThreatSrc { + SIGMA, + RLKS, + RPB, + MP405 } + class Threat: +<<<<<<< HEAD enum FFlags { # Допустимые значения для Threat.fflags NONE = 0, TMOD = 1, BAUD = 2, PROTO = 4, SLON = 8, SLAT = 16, SALT = 32, LAT = 64, @@ -27,3 +34,52 @@ class Threat: var lon: float # Текущие координаты, широта в градусах. Достоверность задана значением Threat.fflags var alt: float # Текущая высота, метры. Достоверность задана значением Threat.fflags var fflags: FFlags # Флаги достоверности полей +======= + enum FFlags { # Допустимые значения для Threat.fflags + TMOD = 1 << 0, + BAUD = 1 << 1, + PROTO = 1 << 2, + SLON = 1 << 3, + SLAT = 1 << 4, + SALT = 1 << 5, + LAT = 1 << 6, + LON = 1 << 7, + ALT = 1 << 8, + AOA = 1 << 9, + FREQ = 1 << 10, + WIDTH = 1 << 11, + } + + var aoa: float # Курсовой угол на источник сигнала, градусы. + var freq: float # Частота несущей или центральная частота, МГц + var width: float # Ширина занимаемого диапазона частот, МГц + var pow_rx: float # Уровень принимаемого сигнала, дБм + var tick: int # Время приёма сигнала, мс + var freqm: String # Режим смены частоты + var rkrp: String # Рекомендуемый режим помехи + var rparams: String # Рекомендуемые параметры помехи + var tmod: String # Тип модуляции + var baud: float # Модуляционная скорость + var proto: String # Тип протокола источника сигнала + var slon: float # Координаты старта, долгота в градусах. Достоверность задана значением Threat.fflags + var slat: float # Координаты старта, широта в градусах. Достоверность задана значением Threat.fflags + var salt: float # Координаты старта, высота от уровня моря. метры. Достоверность задана значением Threat.fflags + var lat: float # Текущие координаты, долгота в градусах. Достоверность задана значением Threat.fflags + var lon: float # Текущие координаты, широта в градусах. Достоверность задана значением Threat.fflags + var alt: float # Текущая высота, метры. Достоверность задана значением Threat.fflags + var atime: Dictionary # Время обнаружения + var utime: Dictionary # Время крайнего обновления + var fflags: FFlags # Флаги достоверности полей + + +var _threats = {} +""" +Список целей. Индекс - <источник цели>:<номер цели> +Источник цели может быть: 'RPB', 'SIGMA', 'RLKS', 'MP405' +""" + + +func _ready() -> void: + Log.info('Модуль обработки целей готов') + +>>>>>>> sasha/master diff --git a/scripts/tools.gd b/scripts/tools.gd index 0f7019e..b536fbe 100644 --- a/scripts/tools.gd +++ b/scripts/tools.gd @@ -1,6 +1,13 @@ extends Node +func assert_array_ipaddr(val: Array): + """ Выкидывает исключение, если массив не содержит ip-адрес """ + assert(val[0] is String) + assert(val[1] is int) + assert((0 < val[1]) and (val[1] < 65536)) + + func map_dec_to_rad(pos0: Vector2, pos: Vector2) -> Vector2: """ Преобразует декартовые координаты в полярные """ var x1: float = pos.x - pos0.x diff --git a/scripts/yau07.gd b/scripts/yau07.gd index d851418..acda9c0 100644 --- a/scripts/yau07.gd +++ b/scripts/yau07.gd @@ -1,11 +1,14 @@ extends Node +# Протокол ячейки ЯУ-07 + const ONLINE_TIMEOUT = 5.0 # Время ожидания пакета от ячейки, секунды const RESEND_TIMEOUT = 0.3 # Задержка для повторной отправки команды, секунды const RETRY_COUNT = 5 # Количество повторных отправок -const DEFAULT_ADDR = ['localhost', 50000] const BUFFER_SIZE = 2048 + + # Ячейка ЯУ-07 class YaU07: @@ -20,12 +23,11 @@ class YaU07: DONE, # Команда выполнена FAIL } # Команда не выполнена - signal online_changed(yau07: YaU07) - signal command_done(yau07: YaU07) - signal command_fail(yau07: YaU07) - signal net_error(message: String) + signal line_changed(unit: YaU07) + signal command_done(unit: YaU07) + signal command_fail(unit: YaU07) - var src_addr: = DEFAULT_ADDR # Адрес источника + var name: = String() var cmd_num_rx: = 0 # Номер команды принятый var cmd_num_tx: = 0 # Номер команды переданный var cmd_state = CmdState.UNCK # Состояние выполнения команды @@ -41,39 +43,39 @@ class YaU07: var isa_ports = {} # Результат выполнения команды "читать порт" var online = false - func _to_string() -> String: - return '%s %s:%d cmd_num:%d' % [['отключен', 'на связи'][int(online)], src_addr[0], src_addr[1], cmd_num_rx] + func _to_string() -> String: return String('яу07: %s %s' % [self.name, ['отключен', 'на связи'][int(online)]]) - func _init(addr: Array): - src_addr = addr + func _init(nm): + self.name = nm tx_data.resize(BUFFER_SIZE) tx_data.fill(0) + tick = 0.0 - func process(delta: float, sock: PacketPeerUDP): + func process(delta: float): tick += delta + if online and ((tick - cmd_tick_rx) > ONLINE_TIMEOUT): + online = false + emit_signal('line_changed', self) + + var rc = Error.ERR_BUSY if cmd_state == CmdState.SEND: - sock.set_dest_address(src_addr[0], src_addr[1]) - if sock.put_packet(tx_data.slice(0, tx_len)) == OK: - cmd_tick_tx = tick - cmd_state = CmdState.WAIT - cmd_retry = RETRY_COUNT + rc = rc.OK + cmd_tick_tx = tick + cmd_state = CmdState.WAIT + cmd_retry = RETRY_COUNT elif cmd_state == CmdState.WAIT: if cmd_retry: if (tick - cmd_tick_tx) > RESEND_TIMEOUT: - sock.set_dest_address(src_addr[0], src_addr[1]) - if sock.put_packet(tx_data.slice(0, tx_len)) == OK: - cmd_tick_tx = tick - else: - emit_signal('socket_error', 'ошибка: пакет не отправлен на: %s' % src_addr) + rc = Error.OK + cmd_tick_tx = tick cmd_retry -= 1 else: cmd_state = CmdState.FAIL emit_signal('command_fail', self) - if online and ((tick - cmd_tick_rx) > ONLINE_TIMEOUT): - online = false - emit_signal('online_changed', self) + rc = Error.FAILED + return rc func send_isa(cmd_code: int, ports_data: Array) -> bool: @@ -151,7 +153,7 @@ class YaU07: if not online: online = true - emit_signal('online_changed', self) + emit_signal('line_changed', self) var rx_data_len = rx_data.size() if rx_data_len < 11: @@ -187,7 +189,7 @@ class YaU07: if cmd_result != 1: # Команда не выполнена return false - var cmd_code: CmdCode = rx_data[cmd_code_pos] # "код команды" + var cmd_code: CmdCode = rx_data[cmd_code_pos] as CmdCode # "код команды" if (cmd_code == CmdCode.READ_ISA) or (cmd_code == CmdCode.WRITE_ISA): parse_isa(rx_data, status_len) diff --git a/table/header.tscn b/table/header.tscn index b65e7dc..24b90a1 100644 --- a/table/header.tscn +++ b/table/header.tscn @@ -3,8 +3,10 @@ [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_2thpi"] bg_color = Color(0.8, 0.533333, 0.27451, 1) -[node name="heder" type="Label"] +[node name="header" type="Label"] offset_right = 128.0 offset_bottom = 23.0 theme_override_colors/font_color = Color(0, 0, 0, 1) theme_override_styles/normal = SubResource("StyleBoxFlat_2thpi") +horizontal_alignment = 1 +vertical_alignment = 1 diff --git a/table/node.tscn b/table/node.tscn index 96c26f5..120347d 100644 --- a/table/node.tscn +++ b/table/node.tscn @@ -1,10 +1,10 @@ -[gd_scene load_steps=2 format=3 uid="uid://c1i4rwaajq7d5"] +[gd_scene format=3 uid="uid://c1i4rwaajq7d5"] -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_7jiwk"] - -[node name="Label" type="Label"] +[node name="Label" type="LineEdit"] offset_right = 121.0 offset_bottom = 23.0 theme_override_colors/font_color = Color(1, 0.596078, 0.4, 1) -theme_override_styles/normal = SubResource("StyleBoxFlat_7jiwk") -clip_text = true +editable = false +context_menu_enabled = false +caret_blink = true +caret_blink_interval = 0.1 diff --git a/table/table.gd b/table/table.gd index 105eb27..fb62c3c 100644 --- a/table/table.gd +++ b/table/table.gd @@ -32,6 +32,19 @@ var header: GridContainer # Заголовок таблицы signal row_pressed(i_row: int) # Вызывается при нажатии кнопкой мыши на строку signal selected_changed(i_row: int) # Вызывается при изменении выбранного ряда. i_row - текущий выбранный ряд +var scroll: Control +var scroll_adj: = Vector2(0, 0) + + +func pin_header(scrl: ScrollContainer, prnt): + scrl.remove_child(header) + prnt.add_child(header) + # TODO: Это значение следует получить из темы + var v_separation: = 3.0 + header.position = scrl.position - Vector2(0, header.size.y + v_separation) + scroll = scrl + scroll_adj = scrl.position + func selector_up(): var i_rows: = [] @@ -93,11 +106,19 @@ func _ready(): assert(ScnNode) +<<<<<<< HEAD func align_to_left_bottom(header, gap: = Vector2(0, 0)): """ Выравнивает по нижнему левому углу. Используется для выравнивания по заголовку """ position.x = header.position.x + gap.x position.y = header.position.y + header.size.y + gap.y +======= +func align_to_left_bottompos(hdr: Control, gap: = Vector2(0, 0)): + """ Выравнивает по нижнему левому углу. + Используется для выравнивания по заголовку """ + position.x = hdr.position.x + gap.x + position.y = hdr.position.y + hdr.size.y + gap.y +>>>>>>> sasha/master func _assert_meta(i_col: int, i_row: int, pname: String, node): @@ -156,6 +177,7 @@ func set_columns_aligment(alignments: Array) -> void: func _input(event) -> void: +<<<<<<< HEAD if event is InputEventKey: if in_focus and event.pressed: if event.keycode == selector_key_up: @@ -192,6 +214,41 @@ func _init() -> void: assert(selector_color_proc.is_valid()) selector_size_proc = Callable(self, 'default_selector_size_proc') assert(selector_size_proc.is_valid()) +======= + if event is InputEventKey: + if in_focus and event.pressed: + if event.keycode == selector_key_up: + selector_up() + elif event.keycode == selector_key_down: + selector_down() + elif event is InputEventMouseButton: + if not event.pressed: + return + if check_event_pos(event.position, scroll): + if not in_focus: + in_focus = true + emit_signal('focus_entered') + elif not check_event_pos(event.position, scroll): + if in_focus: + in_focus = false + emit_signal('focus_exited') + + +func _init() -> void: + selector_color_proc = Callable(self, 'defaultselector_color_proc') + assert(selector_color_proc.is_valid()) + selector_size_proc = Callable(self, 'default_selector_size_proc') + assert(selector_size_proc.is_valid()) + scroll = self + + +func check_event_pos(event_pos: Vector2, obj: Control): + return \ + (event_pos.x > obj.position.x) \ + and (event_pos.x < (obj.position.x + obj.size.x)) \ + and (event_pos.y > obj.position.y) \ + and (event_pos.y < (obj.position.y + obj.size.y)) +>>>>>>> sasha/master func defaultselector_color_proc(_i_row: int): @@ -209,11 +266,19 @@ func set_selector_size_proc(instance: Object, function: String) -> void: func default_selector_size_proc(i_row: int, rect: Array) -> void: +<<<<<<< HEAD get_row_rect(i_row, rect) rect[0] = rect[0] + position.x - node_gap.x / 2.0 rect[1] = rect[1] + position.y - node_gap.y / 2.0 rect[2] = rect[2] + node_gap.x rect[3] = rect[3] + node_gap.y +======= + get_row_rect(i_row, rect) + rect[0] += position.x - node_gap.x / 2.0 + rect[1] += position.y - node_gap.y / 2.0 + rect[2] += node_gap.x + rect[3] += node_gap.y +>>>>>>> sasha/master func clear_rows_selected(): @@ -223,6 +288,7 @@ func clear_rows_selected(): func set_row_selected(i_row: int, selected: bool = true) -> void: +<<<<<<< HEAD var key: = ROW_SELECTOR_KEY_FORMAT % [i_row, 0] var parent = get_parent() if nodes.has(key) and (not selected): @@ -253,6 +319,37 @@ func get_selected_rows(rows: Array) -> void: if SLCT_PREFIX in key: var indexes = get_key_indexes(key) rows.append(indexes[1]) +======= + var key: = ROW_SELECTOR_KEY_FORMAT % [i_row, 0] + var node = nodes[NODE_KEY_FORMAT % [i_row, 0]] + if nodes.has(key) and (not selected): + var selector = nodes[key] + node.remove_child(selector) + selector.queue_free() + nodes.erase(key) + elif (not nodes.has(key)) and selected: + var selector = ScnSelector.instantiate() + var rect: = [0, 0, 0, 0] + selector_size_proc.call(i_row, rect) + selector.size.x = rect[2] + selector.size.y = rect[3] + selector.modulate = selector_color_proc.call(i_row) + selector.z_index = z_index + 1 + nodes[key] = selector + node.add_child(selector) + + +func is_row_selected(i_row: int) -> bool: + var key: = ROW_SELECTOR_KEY_FORMAT % [i_row, 0] + return nodes.has(key) + + +func get_selected_rows(i_rows: Array) -> void: + for key in nodes.keys(): + if SLCT_PREFIX in key: + var indexes = get_key_indexes(key) + i_rows.append(indexes[1]) +>>>>>>> sasha/master func get_rows_count() -> int: @@ -273,6 +370,7 @@ func set_node_user_data(i_col: int, i_row: int, user_data: Object) -> void: func add_row(row_types: Array) -> void: +<<<<<<< HEAD assert(row_types.size() < MAX_INDEX, 'ошибка: слишком много колонок, больше %d' % (MAX_INDEX + 1)) if columns == 1: set_columns(row_types.size()) @@ -319,6 +417,63 @@ func set_header(header_types: Array): var rect = [0, 0, 0, 0] get_node_rect(0, 0, rect, HEAD_KEY_FORMAT) position.y += rect[3] +======= + assert(row_types.size() < MAX_INDEX, 'ошибка: слишком много колонок, больше %d' % (MAX_INDEX + 1)) + if columns == 1: + set_columns(row_types.size()) + else: + assert(columns == row_types.size(), 'ошибка: %s количество колонок установлено ранее - %d, но требуется %d' % [self, columns, row_types.size()]) + var rows_count: int = get_rows_count() + assert(rows_count < MAX_INDEX, 'ошибка: слишком много рядов, больше %d' % (MAX_INDEX + 1)) + for i_col in columns: + var node = row_types[i_col].instantiate() + var head = nodes[HEAD_KEY_FORMAT % [0, i_col]] + node.custom_minimum_size.x = head.custom_minimum_size.x + node.size.x = head.size.x + var key: String = NODE_KEY_FORMAT % [rows_count, i_col] + node.name = key + add_child(node) + nodes[key] = node + node.connect('focus_entered', Callable(self, '_on_focus_entered').bind(key)) + + +func _on_focus_entered(key): + var indexes = get_key_indexes(key) + emit_signal('row_pressed', indexes[1]) + + +func set_header(header_types: Array): + assert(header_types.size() < MAX_INDEX, 'ошибка: слишком много колонок, больше %d' % (MAX_INDEX + 1)) + if columns == 1: + set_columns(header_types.size()) + else: + assert(columns == header_types.size()) + var do_adj: = false + if not header: + header = GridContainer.new() + header.position = position + header.columns = header_types.size() + header.size.x = size.x + var parent = scroll.get_parent() + parent.add_child(header) + do_adj = true + else: + var childrens = header.get_children() + for node in childrens: + childrens.erase(node.name) + childrens.remove_child(node) + node.queue_free() + for i_col in columns: + var node = header_types[i_col].instantiate() + var key: String = HEAD_KEY_FORMAT % [0, i_col] + node.name = key + nodes[key] = node + header.add_child(node) + if do_adj: + var rect = [0, 0, 0, 0] + get_node_rect(0, 0, rect, HEAD_KEY_FORMAT) + position.y += rect[3] +>>>>>>> sasha/master func set_header_text(headers: Array): @@ -332,6 +487,7 @@ func get_node_user_data(i_col: int, i_row: int) -> Object: func remove_row(i_row: int): +<<<<<<< HEAD var sel_key: String = ROW_SELECTOR_KEY_FORMAT % [i_row, 0] if nodes.has(sel_key): var selector = nodes[sel_key] @@ -355,6 +511,33 @@ func remove_row(i_row: int): var dest_node = conn[1] node.disconnect('pressed', Callable(dest_node, callback)) nodes.erase(conn_key) +======= + var sel_key: String = ROW_SELECTOR_KEY_FORMAT % [i_row, 0] + if nodes.has(sel_key): + var selector = nodes[sel_key] + var node_key: String = get_node_key(NODE_KEY_FORMAT, 0, i_row) + var node = nodes[node_key] + node.remove_child(selector) + selector.queue_free() + nodes.erase(sel_key) + for i_col in columns: + var node_key: String = get_node_key(NODE_KEY_FORMAT, i_col, i_row) + var conn_key: String = CONNECTED_KEY_FORMAT % [i_row, i_col] + var data_key: String = DATA_KEY_FORMAT % [i_row, i_col] + var node = nodes[node_key] + nodes.erase(node_key) + remove_child(node) + node.queue_free() + + if nodes.has(data_key): + nodes.erase(data_key) + if nodes.has(conn_key): + var conn = nodes[conn_key] + var callback = conn[0] + var dest_node = conn[1] + node.disconnect('pressed', Callable(dest_node, callback)) + nodes.erase(conn_key) +>>>>>>> sasha/master func rehash(swaps: Array): @@ -405,6 +588,7 @@ func clear_rows() -> void: remove_row(i_row) +<<<<<<< HEAD func set_callbacks(dest_node: Node, event_name: String, callback: String, clmns: Array, user_data: Array) -> void: """ Настраивает обратные вызовы для колонок. :dest_node: Получатель события @@ -426,6 +610,29 @@ func set_callbacks(dest_node: Node, event_name: String, callback: String, clmns: node.disconnect(event_name, Callable(prev_dest_node, prev_callback)) assert (OK == node.connect(event_name, Callable(dest_node, callback).bind([node] + user_data))) nodes[conn_key] = [callback, dest_node] +======= +func connect_columns(dest_node: Node, event_name: String, callback: String, clmns: Array, user_data: Array) -> void: + """ Настраивает обратные вызовы для колонок. + :dest_node: Получатель события + :event_name: Имя события + :callback: Имя функции получателя события + :clmns: Индексы колонок + :user_data: Аргументы функции получателя события """ + var rows_count = get_rows_count() + for i_row in rows_count: + for i_col in clmns: + assert(i_col >= 0 and i_col < columns, 'ошибка: нет колонки %d' % i_col) + var node_key: String = NODE_KEY_FORMAT % [i_row, i_col] + var conn_key: String = CONNECTED_KEY_FORMAT % [i_row, i_col] + var node = nodes[node_key] + if nodes.has(conn_key): + var conn = nodes[conn_key] + var prev_callback = conn[0] + var prev_dest_node = conn[1] + node.disconnect(event_name, Callable(prev_dest_node, prev_callback)) + assert (OK == node.connect(event_name, Callable(dest_node, callback).bind([node] + user_data))) + nodes[conn_key] = [callback, dest_node] +>>>>>>> sasha/master func set_rows_text(rows: Array) -> void: @@ -496,9 +703,17 @@ func get_row_text(i_row: int) -> Array: func set_row_text(i_row: int, row: Array, i_begin: int = 0, key_format: String = NODE_KEY_FORMAT) -> void: +<<<<<<< HEAD for i_col in columns - i_begin: var key: = get_node_key(key_format, i_col + i_begin, i_row) nodes[key].text = row[i_col] +======= + assert(i_begin >= 0) + assert((columns - i_begin) <= row.size()) + for i_col in columns - i_begin: + var key: = get_node_key(key_format, i_col + i_begin, i_row) + nodes[key].text = row[i_col] +>>>>>>> sasha/master func get_rows_text() -> Array: @@ -529,6 +744,7 @@ func get_node_rect(i_col: int, i_row: int, rect: Array, key_format: String = NOD func get_row_rect(i_row: int, rect: Array, key_format: String = NODE_KEY_FORMAT) -> void: +<<<<<<< HEAD assert(rect.size() >= 4, 'ошибка: мало элементов для возврата результата') var cell0 = nodes[get_node_key(key_format, 0, i_row)] var cell1 = nodes[get_node_key(key_format, columns - 1, i_row)] @@ -536,3 +752,12 @@ func get_row_rect(i_row: int, rect: Array, key_format: String = NODE_KEY_FORMAT) rect[1] = cell0.position.y rect[2] = (cell1.position.x - cell0.position.x) + cell1.size.x rect[3] = cell0.size.y +======= + assert(rect.size() >= 4, 'ошибка: мало элементов для возврата результата') + var cell0 = nodes[get_node_key(key_format, 0, i_row)] + var cell1 = nodes[get_node_key(key_format, columns - 1, i_row)] + rect[0] = cell0.position.x + scroll_adj.x + rect[1] = cell0.position.y + scroll_adj.y + rect[2] = (cell1.position.x - cell0.position.x) + cell1.size.x + rect[3] = cell0.size.y +>>>>>>> sasha/master