Доработка. Улучшение документации.
This commit is contained in:
@@ -33,7 +33,7 @@ Log.fatal(text)
|
||||
const CUSTOM = Log.MAX << 1 # Bitwise left shift the MAX value for a custom level.
|
||||
|
||||
func _ready() -> void:
|
||||
Log.add_level(CUSTOM, "Level Name")
|
||||
Log.add_level(CUSTOM, "Level Name")
|
||||
```
|
||||
|
||||
## Calling the custom level:
|
||||
|
||||
@@ -14,36 +14,36 @@ const LOGGER_OUTPUT_ICON = "res://addons/godot-logger/icons/logger.svg"
|
||||
|
||||
|
||||
func _def_settings(pname: String, default: Variant) -> void:
|
||||
if not ProjectSettings.has_setting(pname):
|
||||
ProjectSettings.set_setting(pname, default)
|
||||
if not ProjectSettings.has_setting(pname):
|
||||
ProjectSettings.set_setting(pname, default)
|
||||
|
||||
ProjectSettings.set_initial_value(pname, default)
|
||||
ProjectSettings.set_initial_value(pname, default)
|
||||
|
||||
|
||||
func _enter_tree() -> void:
|
||||
_def_settings("plugins/logger/log_enabled", true)
|
||||
_def_settings("plugins/logger/default_output", false)
|
||||
_def_settings("plugins/logger/log_enabled", true)
|
||||
_def_settings("plugins/logger/default_output", false)
|
||||
|
||||
_def_settings("plugins/logger/level", 31) # The magic number is - INFO | DEBUG | WARNING | ERROR | FATAL
|
||||
ProjectSettings.add_property_info(
|
||||
{
|
||||
"name": "plugins/logger/level",
|
||||
"type": TYPE_INT,
|
||||
"hint": PROPERTY_HINT_FLAGS,
|
||||
"hint_string": "Info,Debug,Warning,Error,Fatal",
|
||||
}
|
||||
)
|
||||
_def_settings("plugins/logger/level", 31) # The magic number is - INFO | DEBUG | WARNING | ERROR | FATAL
|
||||
ProjectSettings.add_property_info(
|
||||
{
|
||||
"name": "plugins/logger/level",
|
||||
"type": TYPE_INT,
|
||||
"hint": PROPERTY_HINT_FLAGS,
|
||||
"hint_string": "Info,Debug,Warning,Error,Fatal",
|
||||
}
|
||||
)
|
||||
|
||||
_def_settings("plugins/logger/file/file_path", "user://uarep-ctl.log")
|
||||
_def_settings("plugins/logger/file/log_file_write", true)
|
||||
_def_settings("plugins/logger/file/file_path", "user://uarep-ctl.log")
|
||||
_def_settings("plugins/logger/file/log_file_write", true)
|
||||
|
||||
_def_settings("plugins/logger/default_output_format", "[{year}-{month}-{day} {hour}:{minute}:{second}][{level}]{text}")
|
||||
_def_settings("plugins/logger/file_format", "[{year}-{month}-{day} {hour}:{minute}:{second}][{level}]{text}")
|
||||
_def_settings("plugins/logger/default_output_format", "[{year}-{month}-{day} {hour}:{minute}:{second}][{level}]{text}")
|
||||
_def_settings("plugins/logger/file_format", "[{year}-{month}-{day} {hour}:{minute}:{second}][{level}]{text}")
|
||||
|
||||
add_autoload_singleton(AUTOLOAD_NAME, AUTOLOAD_PATH)
|
||||
add_custom_type(LOGGER_OUTPUT, "RichTextLabel", load(LOGGER_OUTPUT_SCRIPT), load(LOGGER_OUTPUT_ICON))
|
||||
add_autoload_singleton(AUTOLOAD_NAME, AUTOLOAD_PATH)
|
||||
add_custom_type(LOGGER_OUTPUT, "RichTextLabel", load(LOGGER_OUTPUT_SCRIPT), load(LOGGER_OUTPUT_ICON))
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
remove_custom_type(LOGGER_OUTPUT)
|
||||
remove_autoload_singleton(AUTOLOAD_NAME)
|
||||
remove_custom_type(LOGGER_OUTPUT)
|
||||
remove_autoload_singleton(AUTOLOAD_NAME)
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
# Copyright (c) 2020-2023 Mansur Isaev and contributors - MIT License
|
||||
# See `LICENSE.md` included in the source distribution for details.
|
||||
|
||||
## Logger class.
|
||||
class_name Logger
|
||||
extends Node
|
||||
## Класс журнал событий.
|
||||
class_name Logger extends Node
|
||||
|
||||
## Emitted when the logger create a message.
|
||||
## Выдается, когда журнал событий создаёт сообщение.
|
||||
signal logged(message: Dictionary)
|
||||
|
||||
|
||||
enum {
|
||||
INFO = 1, ## Info level.
|
||||
DEBUG = 1<<1, ## Warning level.
|
||||
WARNING = 1<<2, ## Debug level.
|
||||
ERROR = 1<<3, ## Error level.
|
||||
FATAL = 1<<4, ## Fatal level.
|
||||
MAX = FATAL, ## Bitwise left shift for custom levels.
|
||||
INFO = 1, ## Информационный уровень.
|
||||
DEBUG = 1<<1, ## Уровень предупреждения.
|
||||
WARNING = 1<<2, ## Уровень отладки.
|
||||
ERROR = 1<<3, ## Уровень ошибок.
|
||||
FATAL = 1<<4, ## Критический уровень.
|
||||
MAX = FATAL, ## Побитовый сдвиг влево для пользовательских уровней.
|
||||
}
|
||||
|
||||
|
||||
@@ -32,235 +31,235 @@ var _format_default_output : String
|
||||
var _format_file : String
|
||||
|
||||
var _names = {
|
||||
INFO: "ИНФО",
|
||||
DEBUG: "ОТЛАДКА",
|
||||
WARNING: "ВНИМАНИЕ",
|
||||
ERROR: "ОШИБКА",
|
||||
FATAL: "АВАРИЯ"
|
||||
INFO: "ИНФО",
|
||||
DEBUG: "ОТЛАДКА",
|
||||
WARNING: "ВНИМАНИЕ",
|
||||
ERROR: "ОШИБКА",
|
||||
FATAL: "АВАРИЯ"
|
||||
}
|
||||
var _msg_array: Array
|
||||
var _filters: Array
|
||||
|
||||
# Can be overridden to define custom default values.
|
||||
## Преопределение пользовательских значений по умолчанию.
|
||||
func _enter_tree() -> void:
|
||||
set_log_enabled(ProjectSettings.get_setting("plugins/logger/log_enabled", true))
|
||||
set_default_output_enabled(ProjectSettings.get_setting("plugins/logger/default_output", false))
|
||||
set_log_enabled(ProjectSettings.get_setting("plugins/logger/log_enabled", true))
|
||||
set_default_output_enabled(ProjectSettings.get_setting("plugins/logger/default_output", false))
|
||||
|
||||
_level = ProjectSettings.get_setting("plugins/logger/level", INFO | DEBUG | WARNING | ERROR | FATAL)
|
||||
_level = ProjectSettings.get_setting("plugins/logger/level", INFO | DEBUG | WARNING | ERROR | FATAL)
|
||||
|
||||
set_file_path(ProjectSettings.get_setting("plugins/logger/file/file_path", "user://uarep-ctl.log"))
|
||||
set_file_write_enabled(ProjectSettings.get_setting("plugins/logger/file/log_file_write", true))
|
||||
set_file_path(ProjectSettings.get_setting("plugins/logger/file/file_path", "user://uarep-ctl.log"))
|
||||
set_file_write_enabled(ProjectSettings.get_setting("plugins/logger/file/log_file_write", true))
|
||||
|
||||
_format_default_output = ProjectSettings.get_setting("plugins/logger/default_output_format", "[{year}-{month}-{day} {hour}:{minute}:{second}][{level}]{text}")
|
||||
_format_file = ProjectSettings.get_setting("plugins/logger/file_format", "[{year}-{month}-{day} {hour}:{minute}:{second}][{level}]{text}")
|
||||
_format_default_output = ProjectSettings.get_setting("plugins/logger/default_output_format", "[{year}-{month}-{day} {hour}:{minute}:{second}][{level}]{text}")
|
||||
_format_file = ProjectSettings.get_setting("plugins/logger/file_format", "[{year}-{month}-{day} {hour}:{minute}:{second}][{level}]{text}")
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
_close_file()
|
||||
_close_file()
|
||||
|
||||
## Return [param true] if logger has level.
|
||||
## Возвращает [param true], если у журнала события есть уровень.
|
||||
func has_level(level: int) -> bool:
|
||||
return _names.has(level)
|
||||
return _names.has(level)
|
||||
|
||||
## Set the level enabled.
|
||||
## Установить включенный уровень.
|
||||
func set_level(level: int, enabled: bool) -> void:
|
||||
assert(has_level(level), "Invalid level.")
|
||||
if not has_level(level):
|
||||
return
|
||||
assert(has_level(level), "Invalid level.")
|
||||
if not has_level(level):
|
||||
return
|
||||
|
||||
if enabled:
|
||||
_level |= level
|
||||
else:
|
||||
_level &= ~level
|
||||
if enabled:
|
||||
_level |= level
|
||||
else:
|
||||
_level &= ~level
|
||||
|
||||
## Add a custom log level. The level value must be unique and be greater than [member MAX].
|
||||
## To call the custom level use [method message] method.
|
||||
## Добавить пользовательский уровень журнала. Значение уровня должно быть уникальным и превышать [member MAX].
|
||||
## Для вызова пользовательского уровня используйте метод - [method message].
|
||||
func add_level(level: int, nm: String) -> void:
|
||||
assert(not has_level(level), "Has level.")
|
||||
assert(level > MAX and not level % 2, "Invalid level.")
|
||||
assert(name, "Invalid name.")
|
||||
assert(not has_level(level), "Has level.")
|
||||
assert(level > MAX and not level % 2, "Invalid level.")
|
||||
assert(name, "Invalid name.")
|
||||
|
||||
if not has_level(level) and level > MAX and not level % MAX and not name.is_empty():
|
||||
_names[level] = nm
|
||||
set_level(level, true)
|
||||
if not has_level(level) and level > MAX and not level % MAX and not name.is_empty():
|
||||
_names[level] = nm
|
||||
set_level(level, true)
|
||||
|
||||
## Return the level name.
|
||||
## Возвращает имя уровня.
|
||||
func get_level_name(level: int) -> String:
|
||||
return _names[level]
|
||||
return _names[level]
|
||||
|
||||
## Set Log enabled. Disable ALL messages.
|
||||
## Установить включенный журнал. Отключить ВСЕ сообщения.
|
||||
func set_log_enabled(enabled: bool) -> void:
|
||||
_log_enabled = enabled
|
||||
_log_enabled = enabled
|
||||
|
||||
## Return [param true] if Log enabled.
|
||||
## Возвращает [param true], если журнал включен.
|
||||
func is_log_enabled() -> bool:
|
||||
return _log_enabled
|
||||
return _log_enabled
|
||||
|
||||
## Set default output enabled.
|
||||
## Установка выхода по умолчанию включена.
|
||||
func set_default_output_enabled(enabled: bool) -> void:
|
||||
_default_output_enabled = enabled
|
||||
_default_output_enabled = enabled
|
||||
|
||||
## Returns [param true] if default output is enabled.
|
||||
## Возвращает [param true], если вывод по умолчанию включен.
|
||||
func is_default_output_enabled() -> bool:
|
||||
return _default_output_enabled
|
||||
return _default_output_enabled
|
||||
|
||||
## Set file write enabled.
|
||||
## Установить разрешение на запись файла.
|
||||
func set_file_write_enabled(enabled: bool) -> void:
|
||||
if _file_write_enabled == enabled:
|
||||
return
|
||||
if _file_write_enabled == enabled:
|
||||
return
|
||||
|
||||
_file_write_enabled = enabled
|
||||
_file_write_enabled = enabled
|
||||
|
||||
if enabled:
|
||||
_open_file()
|
||||
else:
|
||||
_close_file()
|
||||
if enabled:
|
||||
_open_file()
|
||||
else:
|
||||
_close_file()
|
||||
|
||||
## Returns [param true] if write to a file is enabled.
|
||||
## Возвращает [param true], если запись в файл разрешена.
|
||||
func is_file_write_enabled() -> bool:
|
||||
return _file_write_enabled
|
||||
return _file_write_enabled
|
||||
|
||||
## Set the path to the log file.
|
||||
## Задать путь к файлу журнала.
|
||||
func set_file_path(path: String) -> void:
|
||||
assert(path.is_absolute_path(), "Invalid path.")
|
||||
if not path.is_absolute_path() or _file_path == path:
|
||||
return
|
||||
assert(path.is_absolute_path(), "Invalid path.")
|
||||
if not path.is_absolute_path() or _file_path == path:
|
||||
return
|
||||
|
||||
_file_path = path
|
||||
_file_path = path
|
||||
|
||||
if is_file_write_enabled():
|
||||
_open_file()
|
||||
if is_file_write_enabled():
|
||||
_open_file()
|
||||
|
||||
## Return path to log file.
|
||||
## Возвращает путь к файлу журнала.
|
||||
func get_file_path() -> String:
|
||||
return _file_path
|
||||
return _file_path
|
||||
|
||||
## Create an info message.
|
||||
## Создать информационное сообщение.
|
||||
func info(text: String) -> void:
|
||||
message(INFO, text)
|
||||
message(INFO, text)
|
||||
|
||||
## Create a debug message. Debug build only.
|
||||
## Создать отладочное сообщение. Только для отладочной сборки.
|
||||
func debug(text: String) -> void:
|
||||
if OS.is_debug_build():
|
||||
message(DEBUG, text)
|
||||
if OS.is_debug_build():
|
||||
message(DEBUG, text)
|
||||
|
||||
## Create a warning message.
|
||||
## Создать предупреждающее сообщение.
|
||||
func warning(text: String) -> void:
|
||||
message(WARNING, text)
|
||||
message(WARNING, text)
|
||||
|
||||
## Create an error message.
|
||||
## Создать сообщение об ошибке.
|
||||
func error(text: String) -> void:
|
||||
message(ERROR, text)
|
||||
message(ERROR, text)
|
||||
|
||||
## Create a fatal error message.
|
||||
## Создать сообщение о критической ошибке.
|
||||
func fatal(text: String) -> void:
|
||||
message(FATAL, text)
|
||||
message(FATAL, text)
|
||||
|
||||
## Format string for log file.
|
||||
## Форматировать строку для файла.
|
||||
func format_file(msg: Dictionary) -> String:
|
||||
return _format_file.format(
|
||||
{
|
||||
"year": "%02d" % msg["year"],
|
||||
"month": "%02d" % msg["month"],
|
||||
"day": "%02d" % msg["day"],
|
||||
"hour": "%02d" % msg["hour"],
|
||||
"minute":"%02d" % msg["minute"],
|
||||
"second":"%02d" % msg["second"],
|
||||
"level": _names[msg["level"]],
|
||||
"text": msg["text"],
|
||||
}
|
||||
)
|
||||
return _format_file.format(
|
||||
{
|
||||
"year": "%02d" % msg["year"],
|
||||
"month": "%02d" % msg["month"],
|
||||
"day": "%02d" % msg["day"],
|
||||
"hour": "%02d" % msg["hour"],
|
||||
"minute":"%02d" % msg["minute"],
|
||||
"second":"%02d" % msg["second"],
|
||||
"level": _names[msg["level"]],
|
||||
"text": msg["text"],
|
||||
}
|
||||
)
|
||||
|
||||
## Format string for editor output.
|
||||
## Форматировать строку для вывода редактора.
|
||||
func format_stdout(msg: Dictionary) -> String:
|
||||
return _format_default_output.format(
|
||||
{
|
||||
"year": "%02d" % msg["year"],
|
||||
"month": "%02d" % msg["month"],
|
||||
"day": "%02d" % msg["day"],
|
||||
"hour": "%02d" % msg["hour"],
|
||||
"minute":"%02d" % msg["minute"],
|
||||
"second":"%02d" % msg["second"],
|
||||
"level": _names[msg["level"]],
|
||||
"text": msg["text"],
|
||||
}
|
||||
)
|
||||
return _format_default_output.format(
|
||||
{
|
||||
"year": "%02d" % msg["year"],
|
||||
"month": "%02d" % msg["month"],
|
||||
"day": "%02d" % msg["day"],
|
||||
"hour": "%02d" % msg["hour"],
|
||||
"minute":"%02d" % msg["minute"],
|
||||
"second":"%02d" % msg["second"],
|
||||
"level": _names[msg["level"]],
|
||||
"text": msg["text"],
|
||||
}
|
||||
)
|
||||
|
||||
## Create a message with a custom level.
|
||||
## Создать сообщение с пользовательским уровнем.
|
||||
func message(level: int, text: String) -> void:
|
||||
assert(has_level(level), "Has not level.")
|
||||
assert(text, "Invalid message text.")
|
||||
assert(has_level(level), "Has not level.")
|
||||
assert(text, "Invalid message text.")
|
||||
|
||||
if _log_enabled and _level & level:
|
||||
var msg : Dictionary = Time.get_datetime_dict_from_system()
|
||||
msg["level"] = level
|
||||
msg["level_name"] = _names[level]
|
||||
msg["text"] = " " + text
|
||||
if _log_enabled and _level & level:
|
||||
var msg : Dictionary = Time.get_datetime_dict_from_system()
|
||||
msg["level"] = level
|
||||
msg["level_name"] = _names[level]
|
||||
msg["text"] = " " + text
|
||||
|
||||
_msg_array.append(msg)
|
||||
if (_flt_msg(msg)):
|
||||
logged.emit(msg)
|
||||
_msg_array.append(msg)
|
||||
if (_flt_msg(msg)):
|
||||
logged.emit(msg)
|
||||
|
||||
|
||||
if _file_write_enabled:
|
||||
_file.store_line(format_file(msg))
|
||||
_file.call_deferred('flush')
|
||||
if _file_write_enabled:
|
||||
_file.store_line(format_file(msg))
|
||||
_file.call_deferred('flush')
|
||||
|
||||
if _default_output_enabled:
|
||||
print(format_stdout(msg))
|
||||
if _default_output_enabled:
|
||||
print(format_stdout(msg))
|
||||
|
||||
|
||||
func _open_file() -> void:
|
||||
if is_instance_valid(_file) and _file.is_open():
|
||||
_file.close()
|
||||
if is_instance_valid(_file) and _file.is_open():
|
||||
_file.close()
|
||||
|
||||
_file = FileAccess.open(get_file_path(), FileAccess.READ_WRITE)
|
||||
_file = FileAccess.open(get_file_path(), FileAccess.READ_WRITE)
|
||||
|
||||
var err := FileAccess.get_open_error()
|
||||
if err:
|
||||
_file = FileAccess.open(get_file_path(), FileAccess.WRITE)
|
||||
_file.close()
|
||||
_file = FileAccess.open(get_file_path(), FileAccess.READ_WRITE)
|
||||
return print_debug(error_string(err))
|
||||
var err := FileAccess.get_open_error()
|
||||
if err:
|
||||
_file = FileAccess.open(get_file_path(), FileAccess.WRITE)
|
||||
_file.close()
|
||||
_file = FileAccess.open(get_file_path(), FileAccess.READ_WRITE)
|
||||
return print_debug(error_string(err))
|
||||
|
||||
err = _file.get_error()
|
||||
if err:
|
||||
return print_debug(error_string(err))
|
||||
_file.seek_end(0)
|
||||
err = _file.get_error()
|
||||
if err:
|
||||
return print_debug(error_string(err))
|
||||
_file.seek_end(0)
|
||||
|
||||
|
||||
func _close_file() -> void:
|
||||
if is_instance_valid(_file) and _file.is_open():
|
||||
_file = null
|
||||
if is_instance_valid(_file) and _file.is_open():
|
||||
_file = null
|
||||
|
||||
|
||||
func save_file(path):
|
||||
var f = FileAccess.open(path, FileAccess.WRITE)
|
||||
var err := FileAccess.get_open_error()
|
||||
if err:
|
||||
print_debug(error_string(err))
|
||||
var log_text = _file.get_as_text()
|
||||
f.store_line(log_text)
|
||||
f.close()
|
||||
var f = FileAccess.open(path, FileAccess.WRITE)
|
||||
var err := FileAccess.get_open_error()
|
||||
if err:
|
||||
print_debug(error_string(err))
|
||||
var log_text = _file.get_as_text()
|
||||
f.store_line(log_text)
|
||||
f.close()
|
||||
|
||||
|
||||
func set_filtrs(flt_array: Array):
|
||||
_filters = flt_array
|
||||
_filters = flt_array
|
||||
|
||||
|
||||
func _flt_msg(msg):
|
||||
var flt_arr: Array = []
|
||||
for item in _filters:
|
||||
if item.button_pressed:
|
||||
flt_arr.append(item.get_meta('filter'))
|
||||
if msg['text'].find(item.get_meta('filter')) != -1:
|
||||
return true
|
||||
if msg['level_name'] in flt_arr:
|
||||
return true
|
||||
return false
|
||||
var flt_arr: Array = []
|
||||
for item in _filters:
|
||||
if item.button_pressed:
|
||||
flt_arr.append(item.get_meta('filter'))
|
||||
if msg['text'].find(item.get_meta('filter')) != -1:
|
||||
return true
|
||||
if msg['level_name'] in flt_arr:
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func add_msgs():
|
||||
for msg in _msg_array:
|
||||
if (_flt_msg(msg)):
|
||||
logged.emit(msg)
|
||||
for msg in _msg_array:
|
||||
if (_flt_msg(msg)):
|
||||
logged.emit(msg)
|
||||
|
||||
@@ -2,21 +2,20 @@
|
||||
# See `LICENSE.md` included in the source distribution for details.
|
||||
|
||||
@tool
|
||||
## LoggerOutput class.
|
||||
class_name LoggerOutput
|
||||
extends RichTextLabel
|
||||
## Класс вывода журнала событий.
|
||||
class_name LoggerOutput extends RichTextLabel
|
||||
|
||||
## Emited when handle [signal Logger.logged] signal.
|
||||
## Выдаётся при ошибке сигнала - [signal Logger.logged].
|
||||
signal handled()
|
||||
|
||||
|
||||
@export var format_text : String = "[{year}-{month}-{day} {hour}:{minute}:{second}][{level}]{text}"
|
||||
@export var colors : Dictionary = {
|
||||
Logger.INFO: Color.WHITE,
|
||||
Logger.DEBUG: Color.GRAY,
|
||||
Logger.WARNING: Color.YELLOW,
|
||||
Logger.ERROR: Color.RED,
|
||||
Logger.FATAL: Color.RED,
|
||||
Logger.INFO: Color.WHITE,
|
||||
Logger.DEBUG: Color.GRAY,
|
||||
Logger.WARNING: Color.YELLOW,
|
||||
Logger.ERROR: Color.RED,
|
||||
Logger.FATAL: Color.RED,
|
||||
}
|
||||
|
||||
|
||||
@@ -24,55 +23,55 @@ var _logger : Logger
|
||||
|
||||
|
||||
func _enter_tree() -> void:
|
||||
var logger := get_node_or_null("/root/log") as Logger
|
||||
if is_instance_valid(logger):
|
||||
set_logger(logger)
|
||||
var logger := get_node_or_null("/root/log") as Logger
|
||||
if is_instance_valid(logger):
|
||||
set_logger(logger)
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
if is_instance_valid(_logger) and _logger.logged.is_connected(handle_message):
|
||||
_logger.logged.disconnect(handle_message)
|
||||
if is_instance_valid(_logger) and _logger.logged.is_connected(handle_message):
|
||||
_logger.logged.disconnect(handle_message)
|
||||
|
||||
## Return the level color or [member Color.WHITE].
|
||||
## Вернуть цвет уровня или [member Color.WHITE].
|
||||
func get_color(level: int) -> Color:
|
||||
return colors.get(level, Color.WHITE)
|
||||
return colors.get(level, Color.WHITE)
|
||||
|
||||
## Set the logger.
|
||||
## Установить журнал событий.
|
||||
func set_logger(logger: Logger) -> void:
|
||||
assert(is_instance_valid(logger), "Invalid Logger.")
|
||||
if not is_instance_valid(logger) or is_same(_logger, logger):
|
||||
return
|
||||
assert(is_instance_valid(logger), "Invalid Logger.")
|
||||
if not is_instance_valid(logger) or is_same(_logger, logger):
|
||||
return
|
||||
|
||||
if is_instance_valid(_logger) and _logger.logged.is_connected(handle_message):
|
||||
_logger.logged.disconnect(handle_message)
|
||||
if is_instance_valid(_logger) and _logger.logged.is_connected(handle_message):
|
||||
_logger.logged.disconnect(handle_message)
|
||||
|
||||
if not logger.logged.is_connected(handle_message):
|
||||
logger.logged.connect(handle_message)
|
||||
if not logger.logged.is_connected(handle_message):
|
||||
logger.logged.connect(handle_message)
|
||||
|
||||
_logger = logger
|
||||
_logger = logger
|
||||
|
||||
## Return the logger.
|
||||
## Вернуть журнал событий.
|
||||
func get_logger() -> Logger:
|
||||
return _logger
|
||||
return _logger
|
||||
|
||||
## Return formatted string from message.
|
||||
## Вернуть строку после форматирования из сообщения.
|
||||
func format(message: Dictionary) -> String:
|
||||
return format_text.format(
|
||||
{
|
||||
"year": "%02d" % message["year"],
|
||||
"month": "%02d" % message["month"],
|
||||
"day": "%02d" % message["day"],
|
||||
"hour": "%02d" % message["hour"],
|
||||
"minute": "%02d" % message["minute"],
|
||||
"second": "%02d" % message["second"],
|
||||
"level": message["level_name"],
|
||||
"text": message["text"],
|
||||
}
|
||||
)
|
||||
return format_text.format(
|
||||
{
|
||||
"year": "%02d" % message["year"],
|
||||
"month": "%02d" % message["month"],
|
||||
"day": "%02d" % message["day"],
|
||||
"hour": "%02d" % message["hour"],
|
||||
"minute": "%02d" % message["minute"],
|
||||
"second": "%02d" % message["second"],
|
||||
"level": message["level_name"],
|
||||
"text": message["text"],
|
||||
}
|
||||
)
|
||||
|
||||
## Handle the message.
|
||||
## Обработать сообщение.
|
||||
func handle_message(message: Dictionary) -> void:
|
||||
push_color(get_color(message["level"]))
|
||||
append_text(format(message) + "\n")
|
||||
pop()
|
||||
handled.emit()
|
||||
push_color(get_color(message["level"]))
|
||||
append_text(format(message) + "\n")
|
||||
pop()
|
||||
handled.emit()
|
||||
|
||||
@@ -111,6 +111,29 @@ theme/default_font_subpixel_positioning=3
|
||||
theme/lcd_subpixel_layout=0
|
||||
common/drop_mouse_on_gui_input_disabled=true
|
||||
|
||||
[input]
|
||||
|
||||
up={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
down={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
left={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
right={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
|
||||
[input_devices]
|
||||
|
||||
buffering/agile_event_flushing=true
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
extends Control
|
||||
class_name bip_ extends Control
|
||||
|
||||
var selected: bool
|
||||
|
||||
# Функция присваивает заданое значение видимости селектору
|
||||
## Функция присваивает заданое значение видимости селектору.
|
||||
func set_sel_visible(value: bool):
|
||||
selected = value
|
||||
$selector.visible = value
|
||||
selected = value
|
||||
$selector.visible = value
|
||||
|
||||
|
||||
# Функция присваивает заданое значение видимости селектору
|
||||
## Функция присваивает заданое значение видимости селектору.
|
||||
func set_track_visible(value: bool): $track.visible = value
|
||||
# Функция присваивает заданое значение видимости индикатору выполнения
|
||||
## Функция присваивает заданое значение видимости индикатору выполнения.
|
||||
func set_ecm_visible(value: bool): $ecm_done.visible = value
|
||||
|
||||
|
||||
func _on_bip_gui_input(event):
|
||||
if event is InputEventMouseButton and event.pressed:
|
||||
match event.button_index:
|
||||
MOUSE_BUTTON_LEFT:
|
||||
signaller.emit_signal('bip_pressed', name.to_int())
|
||||
MOUSE_BUTTON_RIGHT:
|
||||
if selected:
|
||||
signaller.emit_signal('rto_threat_unsel', name.to_int())
|
||||
if event is InputEventMouseButton and event.pressed:
|
||||
match event.button_index:
|
||||
MOUSE_BUTTON_LEFT:
|
||||
signaller.emit_signal('bip_pressed', name.to_int())
|
||||
MOUSE_BUTTON_RIGHT:
|
||||
if selected:
|
||||
signaller.emit_signal('rto_threat_unsel', name.to_int())
|
||||
|
||||
|
||||
@@ -12,66 +12,66 @@ func is_toggle_mode(): return $button.is_toggle_mode()
|
||||
|
||||
|
||||
@export var texture_state0: Texture2D = preload('res://data/кнопка-квадрат-0.png'):
|
||||
set(val): $state.set_texture(val)
|
||||
set(val): $state.set_texture(val)
|
||||
|
||||
|
||||
@export var texture_state1: Texture2D = preload('res://data/кнопка-квадрат-1.png'):
|
||||
set(val): $state.set_texture(val)
|
||||
set(val): $state.set_texture(val)
|
||||
|
||||
|
||||
@export var strips_rotation: float = 0.0:
|
||||
set(val):
|
||||
strips_rotation = val
|
||||
$back.strips_rotation = deg_to_rad(val)
|
||||
get: return strips_rotation
|
||||
set(val):
|
||||
strips_rotation = val
|
||||
$back.strips_rotation = deg_to_rad(val)
|
||||
get: return strips_rotation
|
||||
|
||||
|
||||
@export var text: String = '':
|
||||
set(val): $button.set_text(val)
|
||||
get: return $button.get_text()
|
||||
set(val): $button.set_text(val)
|
||||
get: return $button.get_text()
|
||||
|
||||
|
||||
@export var disabled: bool = false:
|
||||
set(val):
|
||||
disabled = val
|
||||
$button.set_disabled(val)
|
||||
$back.disabled = val
|
||||
$state.modulate.a = 0.5 if val else 1.0
|
||||
get: return disabled
|
||||
set(val):
|
||||
disabled = val
|
||||
$button.set_disabled(val)
|
||||
$back.disabled = val
|
||||
$state.modulate.a = 0.5 if val else 1.0
|
||||
get: return disabled
|
||||
|
||||
|
||||
@export var pressed: bool = false:
|
||||
set(val):
|
||||
pressed = val
|
||||
$button.set_pressed(val)
|
||||
get:
|
||||
return pressed
|
||||
set(val):
|
||||
pressed = val
|
||||
$button.set_pressed(val)
|
||||
get:
|
||||
return pressed
|
||||
|
||||
|
||||
@export var toggle_mode: bool = false:
|
||||
set(val):
|
||||
toggle_mode = val
|
||||
$button.set_toggle_mode(val)
|
||||
get:
|
||||
return toggle_mode
|
||||
set(val):
|
||||
toggle_mode = val
|
||||
$button.set_toggle_mode(val)
|
||||
get:
|
||||
return toggle_mode
|
||||
|
||||
|
||||
func _on_resized() -> void:
|
||||
$back.scale = size
|
||||
$back.material.set('shader_parameter/scale', size / Vector2(20.0, 20.0))
|
||||
$back.scale = size
|
||||
$back.material.set('shader_parameter/scale', size / Vector2(20.0, 20.0))
|
||||
|
||||
|
||||
func _enter_tree() -> void:
|
||||
$back.scale = size
|
||||
$back.material.set('shader_parameter/scale', size / Vector2(20.0, 20.0))
|
||||
$button.set_toggle_mode(true)
|
||||
$button.connect('toggled', Callable(self, '_on_button_toggled'))
|
||||
$back.scale = size
|
||||
$back.material.set('shader_parameter/scale', size / Vector2(20.0, 20.0))
|
||||
$button.set_toggle_mode(true)
|
||||
$button.connect('toggled', Callable(self, '_on_button_toggled'))
|
||||
|
||||
|
||||
func set_toggle_mode(val: bool):
|
||||
$button.set_toggle_mode(val)
|
||||
$button.set_toggle_mode(val)
|
||||
|
||||
|
||||
func _on_button_toggled(val: bool):
|
||||
if val: $state.set_texture(texture_state1)
|
||||
else: $state.set_texture(texture_state0)
|
||||
if val: $state.set_texture(texture_state1)
|
||||
else: $state.set_texture(texture_state0)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
extends Control
|
||||
|
||||
@export var text: String = '':
|
||||
set(val): $label.set_text(val)
|
||||
get: return $label.get_text()
|
||||
set(val): $label.set_text(val)
|
||||
get: return $label.get_text()
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
extends Sprite2D
|
||||
class_name Diagram extends Sprite2D
|
||||
|
||||
var fs_default_colors: Array # Цвета по умолчанию для блоков ФС
|
||||
var fs_default_colors: Array ## Цвета по умолчанию для блоков ФС.
|
||||
|
||||
func _ready() -> void:
|
||||
signaller.connect('map_mode_changed', Callable(self, 'set_view_mode'))
|
||||
set_def_colors()
|
||||
signaller.connect('map_mode_changed', Callable(self, 'set_view_mode'))
|
||||
set_def_colors()
|
||||
|
||||
|
||||
func sv(val: float) -> float: return val / ($строб.scale.x / 2.0) * 0.125
|
||||
@@ -30,15 +30,15 @@ func get_radius_inner_1() -> float: return material.get('shader_parameter/radiu
|
||||
func set_view_mode(val: int): material.set('shader_parameter/mode', val);
|
||||
func set_band_colors(val: Array): material.set('shader_parameter/ant_band_c', val)
|
||||
|
||||
## Закрашивание по умолчанию блоков ФС цветами из настроек
|
||||
## Закрашивание по умолчанию блоков ФС цветами из настроек.
|
||||
func set_def_colors():
|
||||
var color0: Vector3 = ProjectSettings.get_setting('application/interfer/default_color0', Vector3(0.38, 0.47, 0.51))
|
||||
var color1: Vector3 = ProjectSettings.get_setting('application/interfer/default_color1', Vector3(0.39, 0.44, 0.50))
|
||||
var col_arr: Array = [color0, color1]
|
||||
var col = false
|
||||
for i in range(7):
|
||||
for j in range (4):
|
||||
fs_default_colors.append(col_arr[int(col)])
|
||||
col = not col
|
||||
col = not col
|
||||
set_band_colors(fs_default_colors)
|
||||
var color0: Vector3 = ProjectSettings.get_setting('application/interfer/default_color0', Vector3(0.38, 0.47, 0.51))
|
||||
var color1: Vector3 = ProjectSettings.get_setting('application/interfer/default_color1', Vector3(0.39, 0.44, 0.50))
|
||||
var col_arr: Array = [color0, color1]
|
||||
var col = false
|
||||
for i in range(7):
|
||||
for j in range (4):
|
||||
fs_default_colors.append(col_arr[int(col)])
|
||||
col = not col
|
||||
col = not col
|
||||
set_band_colors(fs_default_colors)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
extends NinePatchRect
|
||||
class_name frm_ecm_list extends NinePatchRect
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
## Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
$grd_forced/btn_cancel.button_connect('pressed', Callable(self, 'on_btn_cancel_pressed').bind($grd_forced/btn_cancel))
|
||||
$grd_forced/btn_cancel.button_connect('pressed', Callable(self, 'on_btn_cancel_pressed').bind($grd_forced/btn_cancel))
|
||||
|
||||
|
||||
func on_btn_cancel_pressed(btn):
|
||||
signaller.emit_signal('interfer_off_all')
|
||||
await get_tree().create_timer(0.1).timeout
|
||||
btn.pressed = false
|
||||
signaller.emit_signal('interfer_off_all')
|
||||
await get_tree().create_timer(0.1).timeout
|
||||
btn.pressed = false
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
extends ScrollContainer
|
||||
class_name scroll_ecm_params extends ScrollContainer
|
||||
|
||||
## Отображает список параметров помехи в таблице.
|
||||
|
||||
@@ -11,82 +11,82 @@ const TABLE_HEADERS_TEXT = ['Параметр', 'Значение' ] ##
|
||||
const TABLE_COLUMN_SIZE = [ 370, 85 ] ## Ширины колонок.
|
||||
|
||||
const TABLE_PARAMS = {
|
||||
'kni': [0, 'Курсовой угол, гр.', false, 0.0, 360.0],
|
||||
'powp': [1, 'Мощность, %', true, 0.0, 100.0],
|
||||
'freq': [2, 'Частота, МГц', true, 400.0, 6000.0],
|
||||
'width': [3, 'Занимая полоса частот, МГц', true, 0.0, 120.0],
|
||||
'dur': [4, 'Длительность импульса, мкс', true, 0.0, 1000000.0],
|
||||
'period': [5, 'Период повтора, мкс', true, 0.0, 1000000.0] }
|
||||
'kni': [0, 'Курсовой угол, гр.', false, 0.0, 360.0],
|
||||
'powp': [1, 'Мощность, %', true, 0.0, 100.0],
|
||||
'freq': [2, 'Частота, МГц', true, 400.0, 6000.0],
|
||||
'width': [3, 'Занимая полоса частот, МГц', true, 0.0, 120.0],
|
||||
'dur': [4, 'Длительность импульса, мкс', true, 0.0, 1000000.0],
|
||||
'period': [5, 'Период повтора, мкс', true, 0.0, 1000000.0] }
|
||||
|
||||
|
||||
func init_table():
|
||||
for i in TABLE_PARAMS.size(): $table.add_row(TABLE_ROW)
|
||||
for key in TABLE_PARAMS.keys():
|
||||
var p = TABLE_PARAMS[key]
|
||||
$table.set_node_text(0, p[0], p[1])
|
||||
$table.set_node_alligment(0, p[0], HORIZONTAL_ALIGNMENT_LEFT)
|
||||
$table.set_node_editable(0, p[0], false)
|
||||
$table.set_node_editable(1, p[0], false)
|
||||
$table.set_node_user_data(1, p[0], key)
|
||||
$table.connect_columns(self, 'text_submitted', 'on_edit_entry', [1], [])
|
||||
$table.set_columns_min_size(TABLE_COLUMN_SIZE)
|
||||
$table.set_meta('id', 0)
|
||||
for i in TABLE_PARAMS.size(): $table.add_row(TABLE_ROW)
|
||||
for key in TABLE_PARAMS.keys():
|
||||
var p = TABLE_PARAMS[key]
|
||||
$table.set_node_text(0, p[0], p[1])
|
||||
$table.set_node_alligment(0, p[0], HORIZONTAL_ALIGNMENT_LEFT)
|
||||
$table.set_node_editable(0, p[0], false)
|
||||
$table.set_node_editable(1, p[0], false)
|
||||
$table.set_node_user_data(1, p[0], key)
|
||||
$table.connect_columns(self, 'text_submitted', 'on_edit_entry', [1], [])
|
||||
$table.set_columns_min_size(TABLE_COLUMN_SIZE)
|
||||
$table.set_meta('id', 0)
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
## Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
signaller.connect('interfer_selected', Callable(self, 'on_interfer_selected'))
|
||||
signaller.connect('rto_threat_unsel', Callable(self, 'on_rto_threat_unsel'))
|
||||
call_deferred('init_table')
|
||||
signaller.connect('interfer_selected', Callable(self, 'on_interfer_selected'))
|
||||
signaller.connect('rto_threat_unsel', Callable(self, 'on_rto_threat_unsel'))
|
||||
call_deferred('init_table')
|
||||
|
||||
|
||||
func on_edit_entry(text : String, entry):
|
||||
var ecm = $table.get_meta('ecm')
|
||||
if $table.has_meta('ecm') == false: return
|
||||
var indexis = $table.get_key_indexes(entry[0].name)
|
||||
var row_i = indexis[1]
|
||||
var param = $table.get_node_user_data(1, row_i)
|
||||
var p = TABLE_PARAMS[param]
|
||||
var old_val = ecm.get_value(param)
|
||||
var val = check_value(text, p[3], p[4], old_val)
|
||||
ecm.set_value(val, param)
|
||||
signaller.emit_signal('interfer_new', ecm)
|
||||
var ecm = $table.get_meta('ecm')
|
||||
if $table.has_meta('ecm') == false: return
|
||||
var indexis = $table.get_key_indexes(entry[0].name)
|
||||
var row_i = indexis[1]
|
||||
var param = $table.get_node_user_data(1, row_i)
|
||||
var p = TABLE_PARAMS[param]
|
||||
var old_val = ecm.get_value(param)
|
||||
var val = check_value(text, p[3], p[4], old_val)
|
||||
ecm.set_value(val, param)
|
||||
signaller.emit_signal('interfer_new', ecm)
|
||||
|
||||
|
||||
func check_value(val, min_val, max_val, old_val):
|
||||
if val.is_valid_float():
|
||||
if float(val) < min_val: return min_val
|
||||
if float(val) > max_val: return max_val
|
||||
return float(val)
|
||||
else: return old_val
|
||||
if val.is_valid_float():
|
||||
if float(val) < min_val: return min_val
|
||||
if float(val) > max_val: return max_val
|
||||
return float(val)
|
||||
else: return old_val
|
||||
|
||||
|
||||
func on_interfer_selected(ecm):
|
||||
if ecm != null:
|
||||
$table.set_meta('ecm', ecm)
|
||||
else:
|
||||
$table.set_meta('ecm', null)
|
||||
on_ecm_update()
|
||||
if ecm != null:
|
||||
$table.set_meta('ecm', ecm)
|
||||
else:
|
||||
$table.set_meta('ecm', null)
|
||||
on_ecm_update()
|
||||
|
||||
|
||||
func on_ecm_update():
|
||||
for item in len(TABLE_PARAMS):
|
||||
$table.set_node_text(1, item, '')
|
||||
$table.set_node_editable(1, item, false)
|
||||
if $table.has_meta('ecm') == false: return
|
||||
var ecm: interfer.Interfer = $table.get_meta('ecm')
|
||||
var mnms = tools.get_members_names(ecm)
|
||||
for item in ecm['params'].keys():
|
||||
mnms.append(item)
|
||||
for member_name in mnms:
|
||||
if not TABLE_PARAMS.has(member_name): continue
|
||||
var p = TABLE_PARAMS[member_name]
|
||||
var val = ecm.get_value(member_name)
|
||||
$table.set_node_text(1, p[0], '%s' % val)
|
||||
$table.set_node_editable(1, p[0], p[2])
|
||||
for item in len(TABLE_PARAMS):
|
||||
$table.set_node_text(1, item, '')
|
||||
$table.set_node_editable(1, item, false)
|
||||
if $table.has_meta('ecm') == false: return
|
||||
var ecm: interfer.Interfer = $table.get_meta('ecm')
|
||||
var mnms = tools.get_members_names(ecm)
|
||||
for item in ecm['params'].keys():
|
||||
mnms.append(item)
|
||||
for member_name in mnms:
|
||||
if not TABLE_PARAMS.has(member_name): continue
|
||||
var p = TABLE_PARAMS[member_name]
|
||||
var val = ecm.get_value(member_name)
|
||||
$table.set_node_text(1, p[0], '%s' % val)
|
||||
$table.set_node_editable(1, p[0], p[2])
|
||||
|
||||
|
||||
func on_rto_threat_unsel(_th_id):
|
||||
for item in range(len(TABLE_PARAMS)):
|
||||
$table.set_node_text(1, item, '')
|
||||
$table.set_node_editable(1, item, false)
|
||||
for item in range(len(TABLE_PARAMS)):
|
||||
$table.set_node_text(1, item, '')
|
||||
$table.set_node_editable(1, item, false)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
extends ScrollContainer
|
||||
class_name scroll_params extends ScrollContainer
|
||||
|
||||
## Отображение параметров цели
|
||||
## Отображение параметров цели.
|
||||
|
||||
const CellLineEdit = preload('res://table/ячейка-2.tscn') ## Ячейка таблицы.
|
||||
const TableHeader = preload('res://table/header.tscn') ## Ячейка заголовок таблицы.
|
||||
@@ -15,51 +15,51 @@ const TABLE_COLUMN_SIZE = [ 370, 85 ] ## Ширины к
|
||||
## Параметры цели для отображения в таблице.[br]
|
||||
## [b]val[0][/b] - Индекс строки.[br][b]val[1][/b] - Содержание.
|
||||
const TABLE_PARAMS = {
|
||||
'baud': [0, 'Модуляционная скорость, бод'],
|
||||
'freqm': [1, 'Режим смены частоты.'],
|
||||
'power': [2, 'Уровень сигнала, дБм.'],
|
||||
'tmod': [3, 'Тип модуляции'],
|
||||
'width': [4, 'Занимая полоса частот, МГц.'],
|
||||
'rkrp': [5, 'Рекомендуемая помеха'] }
|
||||
'baud': [0, 'Модуляционная скорость, бод'],
|
||||
'freqm': [1, 'Режим смены частоты.'],
|
||||
'power': [2, 'Уровень сигнала, дБм.'],
|
||||
'tmod': [3, 'Тип модуляции'],
|
||||
'width': [4, 'Занимая полоса частот, МГц.'],
|
||||
'rkrp': [5, 'Рекомендуемая помеха'] }
|
||||
|
||||
|
||||
## Обрабатывает сигнал [signal threats.threat_selected]
|
||||
## Обрабатывает сигнал [signal threats.threat_selected].
|
||||
func on_threat_selected(th):
|
||||
$table.set_meta('id', th.id)
|
||||
on_threat_update(th)
|
||||
$table.set_meta('id', th.id)
|
||||
on_threat_update(th)
|
||||
|
||||
|
||||
func init_table():
|
||||
for i in TABLE_PARAMS.size(): $table.add_row(TABLE_ROW)
|
||||
for p in TABLE_PARAMS.values():
|
||||
$table.set_node_text(0, p[0], p[1])
|
||||
$table.set_node_alligment(0, p[0], HORIZONTAL_ALIGNMENT_LEFT)
|
||||
$table.set_node_editable(0, p[0], false)
|
||||
$table.set_node_editable(1, p[0], false)
|
||||
$table.set_columns_min_size(TABLE_COLUMN_SIZE)
|
||||
$table.set_meta('id', 0)
|
||||
for i in TABLE_PARAMS.size(): $table.add_row(TABLE_ROW)
|
||||
for p in TABLE_PARAMS.values():
|
||||
$table.set_node_text(0, p[0], p[1])
|
||||
$table.set_node_alligment(0, p[0], HORIZONTAL_ALIGNMENT_LEFT)
|
||||
$table.set_node_editable(0, p[0], false)
|
||||
$table.set_node_editable(1, p[0], false)
|
||||
$table.set_columns_min_size(TABLE_COLUMN_SIZE)
|
||||
$table.set_meta('id', 0)
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
signaller.connect('threat_selected', Callable(self, 'on_threat_selected'))
|
||||
signaller.connect('rto_threat_unsel', Callable(self, 'on_rto_threat_unsel'))
|
||||
threats.connect('threat_update', Callable(self, 'on_threat_update'))
|
||||
call_deferred('init_table')
|
||||
signaller.connect('threat_selected', Callable(self, 'on_threat_selected'))
|
||||
signaller.connect('rto_threat_unsel', Callable(self, 'on_rto_threat_unsel'))
|
||||
threats.connect('threat_update', Callable(self, 'on_threat_update'))
|
||||
call_deferred('init_table')
|
||||
|
||||
|
||||
## Обрабатывает сигнал [signal threats.threat_update].
|
||||
## Обновляет отображение только для выбранной цели.
|
||||
func on_threat_update(th):
|
||||
if th.selected == false: return
|
||||
if th.id != $table.get_meta('id'): return
|
||||
var mnms = tools.get_members_names(th)
|
||||
for member_name in mnms:
|
||||
if not TABLE_PARAMS.has(member_name): continue
|
||||
var p = TABLE_PARAMS[member_name]
|
||||
var val = th.get(member_name)
|
||||
$table.set_node_text(1, p[0], '%s' % val)
|
||||
if th.selected == false: return
|
||||
if th.id != $table.get_meta('id'): return
|
||||
var mnms = tools.get_members_names(th)
|
||||
for member_name in mnms:
|
||||
if not TABLE_PARAMS.has(member_name): continue
|
||||
var p = TABLE_PARAMS[member_name]
|
||||
var val = th.get(member_name)
|
||||
$table.set_node_text(1, p[0], '%s' % val)
|
||||
|
||||
|
||||
func on_rto_threat_unsel(_th_id):
|
||||
for item in range(len(TABLE_PARAMS)):
|
||||
$table.set_node_text(1, item, '')
|
||||
for item in range(len(TABLE_PARAMS)):
|
||||
$table.set_node_text(1, item, '')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
extends ScrollContainer
|
||||
class_name scroll_threats extends ScrollContainer
|
||||
|
||||
## Отображает список целей в таблице.
|
||||
|
||||
@@ -16,89 +16,89 @@ const TABLE_COLUMN_SIZE = [ 65, 145, 145, 90 ]
|
||||
|
||||
## Вызывается при нажатии указателем мыши на выбранный ряд.
|
||||
func on_row_pressed(i_row: int):
|
||||
row_pressed(i_row)
|
||||
signaller.emit_signal('rto_threat_sel', $table.get_node_user_data(0, i_row).id)
|
||||
row_pressed(i_row)
|
||||
signaller.emit_signal('rto_threat_sel', $table.get_node_user_data(0, i_row).id)
|
||||
|
||||
|
||||
func row_pressed(i_row: int):
|
||||
$table.clear_rows_selected()
|
||||
$table.set_row_selected(i_row, true)
|
||||
$table.ensure_row_visible(i_row)
|
||||
var threat = $table.get_node_user_data(0, i_row)
|
||||
signaller.emit_signal('threat_selected', threat)
|
||||
$table.clear_rows_selected()
|
||||
$table.set_row_selected(i_row, true)
|
||||
$table.ensure_row_visible(i_row)
|
||||
var threat = $table.get_node_user_data(0, i_row)
|
||||
signaller.emit_signal('threat_selected', threat)
|
||||
|
||||
|
||||
func init_table():
|
||||
$table.set_header(TABLE_HEADER)
|
||||
$table.set_header_text(TABLE_HEADERS_TEXT)
|
||||
$table.set_columns_min_size(TABLE_COLUMN_SIZE)
|
||||
$table.pin_header(self, get_parent())
|
||||
$table.set_header(TABLE_HEADER)
|
||||
$table.set_header_text(TABLE_HEADERS_TEXT)
|
||||
$table.set_columns_min_size(TABLE_COLUMN_SIZE)
|
||||
$table.pin_header(self, get_parent())
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
var table_index: = Dictionary()
|
||||
threats.connect('threat_new', Callable(self, 'on_threat_new').bind(table_index))
|
||||
threats.connect('threat_lost', Callable(self, 'on_threat_lost').bind(table_index))
|
||||
threats.connect('threat_update', Callable(self, 'on_threat_update').bind(table_index))
|
||||
signaller.connect('rto_threat_sel', Callable(self, 'on_rto_threat_sel').bind($table))
|
||||
signaller.connect('rto_threat_unsel', Callable(self, 'on_rto_threat_unsel'))
|
||||
$table.connect('row_pressed', Callable(self, 'on_row_pressed'))
|
||||
call_deferred('init_table')
|
||||
var table_index: = Dictionary()
|
||||
threats.connect('threat_new', Callable(self, 'on_threat_new').bind(table_index))
|
||||
threats.connect('threat_lost', Callable(self, 'on_threat_lost').bind(table_index))
|
||||
threats.connect('threat_update', Callable(self, 'on_threat_update').bind(table_index))
|
||||
signaller.connect('rto_threat_sel', Callable(self, 'on_rto_threat_sel').bind($table))
|
||||
signaller.connect('rto_threat_unsel', Callable(self, 'on_rto_threat_unsel'))
|
||||
$table.connect('row_pressed', Callable(self, 'on_row_pressed'))
|
||||
call_deferred('init_table')
|
||||
|
||||
|
||||
## Перестраивает индекс таблицы. Вызывать при удалении строки
|
||||
## Перестраивает индекс таблицы. Вызывать при удалении строки.
|
||||
func rehash(table_index: Dictionary):
|
||||
var rows_count = $table.get_rows_count()
|
||||
for i_row in rows_count:
|
||||
var item = $table.get_node2(0, i_row)
|
||||
table_index[int(item.text)] = i_row
|
||||
var rows_count = $table.get_rows_count()
|
||||
for i_row in rows_count:
|
||||
var item = $table.get_node2(0, i_row)
|
||||
table_index[int(item.text)] = i_row
|
||||
|
||||
|
||||
## Обрабатывает сигнал [b]threat_update[/b]
|
||||
## Обрабатывает сигнал [b]threat_update[/b].
|
||||
func on_threat_update(th, table_index: Dictionary):
|
||||
var row = map_th_to_row(th)
|
||||
var i_row = table_index[th.id]
|
||||
$table.set_row_text(i_row, row)
|
||||
var row = map_th_to_row(th)
|
||||
var i_row = table_index[th.id]
|
||||
$table.set_row_text(i_row, row)
|
||||
|
||||
|
||||
## Обрабатывает сигнал [b]threat_lost[/b]
|
||||
## Обрабатывает сигнал [b]threat_lost[/b].
|
||||
func on_threat_lost(th, table_index: Dictionary):
|
||||
$table.remove_row(table_index[th.id])
|
||||
table_index.clear()
|
||||
rehash(table_index)
|
||||
$table.remove_row(table_index[th.id])
|
||||
table_index.clear()
|
||||
rehash(table_index)
|
||||
|
||||
|
||||
## Обрабатывает сигнал [b]threat_new[/b]
|
||||
## Обрабатывает сигнал [b]threat_new[/b].
|
||||
func on_threat_new(th, table_index):
|
||||
var i_row = $table.get_rows_count()
|
||||
$table.add_row(TABLE_ROW)
|
||||
var row = map_th_to_row(th)
|
||||
$table.set_row_text(i_row, row)
|
||||
$table.set_row_editable(i_row, false)
|
||||
$table.set_node_user_data(0, i_row, th)
|
||||
table_index[th.id] = i_row
|
||||
var i_row = $table.get_rows_count()
|
||||
$table.add_row(TABLE_ROW)
|
||||
var row = map_th_to_row(th)
|
||||
$table.set_row_text(i_row, row)
|
||||
$table.set_row_editable(i_row, false)
|
||||
$table.set_node_user_data(0, i_row, th)
|
||||
table_index[th.id] = i_row
|
||||
|
||||
|
||||
## Преобразует цель в строку таблицы
|
||||
## Преобразует цель в строку таблицы.
|
||||
func map_th_to_row(th) -> Array:
|
||||
var row: = Array()
|
||||
row.resize(TABLE_COLUMN_PARAM.size())
|
||||
var i_col: int = 0
|
||||
for param_name in TABLE_COLUMN_PARAM:
|
||||
row[i_col] = '%s' % th.get(param_name)
|
||||
i_col += 1
|
||||
return row
|
||||
var row: = Array()
|
||||
row.resize(TABLE_COLUMN_PARAM.size())
|
||||
var i_col: int = 0
|
||||
for param_name in TABLE_COLUMN_PARAM:
|
||||
row[i_col] = '%s' % th.get(param_name)
|
||||
i_col += 1
|
||||
return row
|
||||
|
||||
|
||||
## Выделяет выбранную цель в таблице
|
||||
## Выделяет выбранную цель в таблице.
|
||||
func on_rto_threat_sel(th_id, tbl):
|
||||
for i in tbl.get_rows_count():
|
||||
var node = tbl.get_node2(0, i)
|
||||
if node.text.to_int() == th_id:
|
||||
row_pressed(i)
|
||||
break
|
||||
for i in tbl.get_rows_count():
|
||||
var node = tbl.get_node2(0, i)
|
||||
if node.text.to_int() == th_id:
|
||||
row_pressed(i)
|
||||
break
|
||||
|
||||
|
||||
## Снимает выделение цели
|
||||
## Снимает выделение цели.
|
||||
func on_rto_threat_unsel(_th_id): $table.clear_rows_selected()
|
||||
|
||||
|
||||
@@ -4,15 +4,15 @@ extends NinePatchRect
|
||||
|
||||
|
||||
@export var horizontal_alignment: HorizontalAlignment = HorizontalAlignment.HORIZONTAL_ALIGNMENT_CENTER:
|
||||
get: return $header.horizontal_alignment if is_inside_tree() else HorizontalAlignment.HORIZONTAL_ALIGNMENT_CENTER
|
||||
set(val): if is_inside_tree(): $header.horizontal_alignment = val
|
||||
get: return $header.horizontal_alignment if is_inside_tree() else HorizontalAlignment.HORIZONTAL_ALIGNMENT_CENTER
|
||||
set(val): if is_inside_tree(): $header.horizontal_alignment = val
|
||||
|
||||
|
||||
@export var vertical_alignment: VerticalAlignment = VerticalAlignment.VERTICAL_ALIGNMENT_CENTER:
|
||||
get: return $header.vertical_alignment if is_inside_tree() else VerticalAlignment.VERTICAL_ALIGNMENT_CENTER
|
||||
set(val): if is_inside_tree(): $header.vertical_alignment = val
|
||||
get: return $header.vertical_alignment if is_inside_tree() else VerticalAlignment.VERTICAL_ALIGNMENT_CENTER
|
||||
set(val): if is_inside_tree(): $header.vertical_alignment = val
|
||||
|
||||
|
||||
@export var text: String = 'caption text':
|
||||
get: return $header.text if is_inside_tree() else ''
|
||||
set(val): if is_inside_tree(): $header.text = val
|
||||
get: return $header.text if is_inside_tree() else ''
|
||||
set(val): if is_inside_tree(): $header.text = val
|
||||
|
||||
@@ -6,13 +6,13 @@ var test_addr: = String()
|
||||
var test_data: = {}
|
||||
|
||||
func _ready():
|
||||
test_req = HTTPRequest.new()
|
||||
add_child(test_req)
|
||||
test_req.request_completed.connect(_map_request_completed)
|
||||
test_req = HTTPRequest.new()
|
||||
add_child(test_req)
|
||||
test_req.request_completed.connect(_map_request_completed)
|
||||
|
||||
func _map_request_completed():
|
||||
pass
|
||||
pass
|
||||
|
||||
|
||||
func on_req_test_data_timer():
|
||||
test_req.request(test_addr)
|
||||
test_req.request(test_addr)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
extends "res://scenes/контроль/прибор.gd"
|
||||
class_name pribor_rtr extends "res://scenes/контроль/прибор.gd"
|
||||
|
||||
|
||||
static var json_parser: JSON = JSON.new()
|
||||
@@ -9,94 +9,94 @@ static var json_parser: JSON = JSON.new()
|
||||
## [param paths] - Массив содержащий отдельные элементы пути.[br]
|
||||
## [param tokens] - Разделители используемые во входной строке для разделения элементов пути.[br]
|
||||
func map_solid_to_array(solid: String, paths: Array, tokens: Array = ['[', ']', '.']) -> void:
|
||||
paths.clear()
|
||||
var i_chs = []
|
||||
for sep in tokens:
|
||||
var i = 0
|
||||
while i != -1:
|
||||
i = solid.find(sep, i + 1)
|
||||
i_chs.append(i)
|
||||
i_chs.pop_back()
|
||||
i_chs.sort()
|
||||
paths.clear()
|
||||
var i_chs = []
|
||||
for sep in tokens:
|
||||
var i = 0
|
||||
while i != -1:
|
||||
i = solid.find(sep, i + 1)
|
||||
i_chs.append(i)
|
||||
i_chs.pop_back()
|
||||
i_chs.sort()
|
||||
|
||||
var i0 = 0
|
||||
for i1 in i_chs:
|
||||
var ss: = [String()]
|
||||
tools.get_string_slice(solid, ss, i0, i1)
|
||||
if ss[0].is_valid_int():
|
||||
paths.append(ss[0].to_int())
|
||||
else:
|
||||
if ss[0]:
|
||||
paths.append(ss[0])
|
||||
i0 = i1 + 1
|
||||
var i0 = 0
|
||||
for i1 in i_chs:
|
||||
var ss: = [String()]
|
||||
tools.get_string_slice(solid, ss, i0, i1)
|
||||
if ss[0].is_valid_int():
|
||||
paths.append(ss[0].to_int())
|
||||
else:
|
||||
if ss[0]:
|
||||
paths.append(ss[0])
|
||||
i0 = i1 + 1
|
||||
|
||||
|
||||
func _on_request_rtr_request_completed(result, _response_code, headers, body: PackedByteArray):
|
||||
if result != 0:
|
||||
var rs = $request_rtr.get_result_string(result)
|
||||
log.error('ошибка: \"%s\"' % rs)
|
||||
return
|
||||
if result != 0:
|
||||
var rs = $request_rtr.get_result_string(result)
|
||||
log.error('ошибка: \"%s\"' % rs)
|
||||
return
|
||||
|
||||
var json_str: String = body.get_string_from_utf8()
|
||||
if not json_str:
|
||||
push_error('ошибка: не удаётся получить строку utf8 из данных (%s)' % headers)
|
||||
return
|
||||
var json_str: String = body.get_string_from_utf8()
|
||||
if not json_str:
|
||||
push_error('ошибка: не удаётся получить строку utf8 из данных (%s)' % headers)
|
||||
return
|
||||
|
||||
var rc = json_parser.parse(json_str)
|
||||
if rc != Error.OK:
|
||||
var err = json_parser.get_error_message()
|
||||
push_error('ошибка: разбор json прерван - \"%s\" (%s)' % [err, headers])
|
||||
return
|
||||
var rc = json_parser.parse(json_str)
|
||||
if rc != Error.OK:
|
||||
var err = json_parser.get_error_message()
|
||||
push_error('ошибка: разбор json прерван - \"%s\" (%s)' % [err, headers])
|
||||
return
|
||||
|
||||
var pp = ['DeviceDescription', 'DeviceName']
|
||||
var ret_val = [null, false]
|
||||
var pp_copy = pp.duplicate(true)
|
||||
tools.get_value_by_path(json_parser.data, pp, ret_val)
|
||||
if not ret_val[1]:
|
||||
push_error('ошибка: путь %s не найден (%s)' % [pp_copy, headers])
|
||||
return
|
||||
var pp = ['DeviceDescription', 'DeviceName']
|
||||
var ret_val = [null, false]
|
||||
var pp_copy = pp.duplicate(true)
|
||||
tools.get_value_by_path(json_parser.data, pp, ret_val)
|
||||
if not ret_val[1]:
|
||||
push_error('ошибка: путь %s не найден (%s)' % [pp_copy, headers])
|
||||
return
|
||||
|
||||
var bort_rtr_name_left: StringName = $left.get_meta('DeviceName', '')
|
||||
var bort_rtr_name_right: StringName = $right.get_meta('DeviceName', '')
|
||||
var bb = {bort_rtr_name_left: $left, bort_rtr_name_right: $right}
|
||||
if not bb.has(ret_val[0]):
|
||||
return
|
||||
var bort_rtr_name_left: StringName = $left.get_meta('DeviceName', '')
|
||||
var bort_rtr_name_right: StringName = $right.get_meta('DeviceName', '')
|
||||
var bb = {bort_rtr_name_left: $left, bort_rtr_name_right: $right}
|
||||
if not bb.has(ret_val[0]):
|
||||
return
|
||||
|
||||
var bort_rtr = bb[ret_val[0]]
|
||||
for child in bort_rtr.get_node('konverter/grid').get_children():
|
||||
map_value_to_item(json_parser.data, child, 'value0')
|
||||
map_value_to_item(json_parser.data, child, 'value1')
|
||||
map_value_to_item(json_parser.data, child, 'value2')
|
||||
map_error_codes_to_item(json_parser.data, child, 'state')
|
||||
for child in bort_rtr.get_node('antenna1/grid').get_children():
|
||||
map_value_to_item(json_parser.data, child, 'value0')
|
||||
map_value_to_item(json_parser.data, child, 'value1')
|
||||
map_error_codes_to_item(json_parser.data, child, 'state')
|
||||
for child in bort_rtr.get_node('antenna2/grid').get_children():
|
||||
map_value_to_item(json_parser.data, child, 'value0')
|
||||
map_value_to_item(json_parser.data, child, 'value1')
|
||||
map_error_codes_to_item(json_parser.data, child, 'state')
|
||||
for child in bort_rtr.get_children():
|
||||
map_value_to_item(json_parser.data, child, 'value0')
|
||||
map_value_to_item(json_parser.data, child, 'value1')
|
||||
map_error_codes_to_item(json_parser.data, child, 'state')
|
||||
var bort_rtr = bb[ret_val[0]]
|
||||
for child in bort_rtr.get_node('konverter/grid').get_children():
|
||||
map_value_to_item(json_parser.data, child, 'value0')
|
||||
map_value_to_item(json_parser.data, child, 'value1')
|
||||
map_value_to_item(json_parser.data, child, 'value2')
|
||||
map_error_codes_to_item(json_parser.data, child, 'state')
|
||||
for child in bort_rtr.get_node('antenna1/grid').get_children():
|
||||
map_value_to_item(json_parser.data, child, 'value0')
|
||||
map_value_to_item(json_parser.data, child, 'value1')
|
||||
map_error_codes_to_item(json_parser.data, child, 'state')
|
||||
for child in bort_rtr.get_node('antenna2/grid').get_children():
|
||||
map_value_to_item(json_parser.data, child, 'value0')
|
||||
map_value_to_item(json_parser.data, child, 'value1')
|
||||
map_error_codes_to_item(json_parser.data, child, 'state')
|
||||
for child in bort_rtr.get_children():
|
||||
map_value_to_item(json_parser.data, child, 'value0')
|
||||
map_value_to_item(json_parser.data, child, 'value1')
|
||||
map_error_codes_to_item(json_parser.data, child, 'state')
|
||||
|
||||
|
||||
func map_value_to_item(data, item, value_name: StringName):
|
||||
var meta = item.get_meta(value_name, '')
|
||||
if meta == '':
|
||||
return
|
||||
if not (meta is String):
|
||||
return
|
||||
var paths: = Array()
|
||||
map_solid_to_array(meta, paths)
|
||||
var ret_val: = [null, false]
|
||||
var paths_copy = paths.duplicate(true)
|
||||
tools.get_value_by_path(data, paths, ret_val)
|
||||
if ret_val[1]:
|
||||
item.set(value_name, ret_val[0])
|
||||
else:
|
||||
push_error('ошибка: путь %s для $%s.%s не найден' % [paths_copy, item.name, value_name])
|
||||
var meta = item.get_meta(value_name, '')
|
||||
if meta == '':
|
||||
return
|
||||
if not (meta is String):
|
||||
return
|
||||
var paths: = Array()
|
||||
map_solid_to_array(meta, paths)
|
||||
var ret_val: = [null, false]
|
||||
var paths_copy = paths.duplicate(true)
|
||||
tools.get_value_by_path(data, paths, ret_val)
|
||||
if ret_val[1]:
|
||||
item.set(value_name, ret_val[0])
|
||||
else:
|
||||
push_error('ошибка: путь %s для $%s.%s не найден' % [paths_copy, item.name, value_name])
|
||||
|
||||
|
||||
## 1. Поле [b]'ErCode'[/b] содержит [b]0[/b] - если нет ошибки, и другое значение - если есть ошибка.[br]
|
||||
@@ -105,29 +105,29 @@ func map_value_to_item(data, item, value_name: StringName):
|
||||
## 4. [i]Нет результата порверки[/i] - поле [param state] принимает значение [b]0[/b], [i]всё
|
||||
## исправно[/i] - [b]1[/b], [i]хотябы один[/i] параметр с ошибкой - [b]2[/b].[br]
|
||||
func map_error_codes_to_item(data, item, value_name: StringName):
|
||||
var metas = item.get_meta(value_name, '')
|
||||
if not (metas is Array):
|
||||
return
|
||||
var paths: = Array()
|
||||
var values: = Array()
|
||||
for meta in metas:
|
||||
map_solid_to_array(meta, paths)
|
||||
var ret_val: = [null, false]
|
||||
var paths_copy = paths.duplicate(true)
|
||||
tools.get_value_by_path(data, paths, ret_val)
|
||||
if ret_val[1]:
|
||||
values.append(int(ret_val[0]))
|
||||
else:
|
||||
push_error('ошибка: путь %s для $%s.%s не найден' % [paths_copy, item.name, value_name])
|
||||
var test_res = 1 if values.count(int(0)) == values.size() else 2
|
||||
item.set(value_name, test_res)
|
||||
var metas = item.get_meta(value_name, '')
|
||||
if not (metas is Array):
|
||||
return
|
||||
var paths: = Array()
|
||||
var values: = Array()
|
||||
for meta in metas:
|
||||
map_solid_to_array(meta, paths)
|
||||
var ret_val: = [null, false]
|
||||
var paths_copy = paths.duplicate(true)
|
||||
tools.get_value_by_path(data, paths, ret_val)
|
||||
if ret_val[1]:
|
||||
values.append(int(ret_val[0]))
|
||||
else:
|
||||
push_error('ошибка: путь %s для $%s.%s не найден' % [paths_copy, item.name, value_name])
|
||||
var test_res = 1 if values.count(int(0)) == values.size() else 2
|
||||
item.set(value_name, test_res)
|
||||
|
||||
|
||||
## Вызывается при клике мыши на элементе контроля
|
||||
## [param block_a] - Кликнутый элемент контроля
|
||||
## Вызывается при клике мыши на элементе контроля.
|
||||
## [param block_a] - Кликнутый элемент контроля.
|
||||
func _on_item_pressed(block_a: Control):
|
||||
var metas = block_a.get_meta_list()
|
||||
print_debug(block_a)
|
||||
for n in metas:
|
||||
var v = block_a.get_meta(n)
|
||||
print('%s:%s' % [n, v])
|
||||
var metas = block_a.get_meta_list()
|
||||
print_debug(block_a)
|
||||
for n in metas:
|
||||
var v = block_a.get_meta(n)
|
||||
print('%s:%s' % [n, v])
|
||||
|
||||
@@ -4,9 +4,9 @@ const TAB_TOSIGNAL_NAME = {0: 'режим_работа', 1: 'режим_конт
|
||||
|
||||
|
||||
func _enter_tree() -> void:
|
||||
repnetwork.logger_page = $Журнал
|
||||
repnetwork.logger_page = $Журнал
|
||||
|
||||
|
||||
func _on_tab_changed(tab) -> void:
|
||||
if TAB_TOSIGNAL_NAME.has(tab):
|
||||
signaller.emit_signal(TAB_TOSIGNAL_NAME[tab])
|
||||
if TAB_TOSIGNAL_NAME.has(tab):
|
||||
signaller.emit_signal(TAB_TOSIGNAL_NAME[tab])
|
||||
|
||||
@@ -1,173 +1,174 @@
|
||||
extends Sprite2D
|
||||
class_name main_tilemap extends Sprite2D
|
||||
|
||||
## Возможные состояния конечного автомата заданий
|
||||
## Возможные состояния конечного автомата заданий.
|
||||
enum TASK_STATE {
|
||||
DONE, ## Выполнено
|
||||
WAIT, ## Ожидание плитки
|
||||
RUN, ## Запуск выполнения
|
||||
CHECK, ## Проверка пустого места
|
||||
ERROR ## Ошибка
|
||||
DONE, ## Выполнено.
|
||||
WAIT, ## Ожидание плитки.
|
||||
RUN, ## Запуск выполнения.
|
||||
CHECK, ## Проверка пустого места.
|
||||
ERROR ## Ошибка.
|
||||
}
|
||||
|
||||
|
||||
## Координаты для проверок [lng, lat]
|
||||
## Координаты для проверок [lng, lat].
|
||||
const TEST_DATA: = {
|
||||
'Калиниград': [ 20.51095, 54.70649 ],
|
||||
'Москва': [ 37.6156, 55.7522 ],
|
||||
'Нью-Йорк': [ -74.006, 40.7143 ],
|
||||
'Сидней': [ 151.20732, -33.8678500 ],
|
||||
'Таганрог': [ 38.8969, 47.2362 ],
|
||||
'Хельсинки': [ 24.9354, 60.1695 ],
|
||||
'Азорские о-ва': [ 28.3996582, 38.5397568 ],
|
||||
'Мехико': [ -99.12766, 19.42847 ],
|
||||
'Белое море': [ 68.136606, 42.045546 ],
|
||||
'море Беллинсгаузена': [ -72.406587, -74.857997 ],
|
||||
'Фиджи': [ 178.065032, -17.713371 ],
|
||||
'Ноль': [ 0.0, 0.0 ],
|
||||
'Точка1': [ 170.0, 0.0 ],
|
||||
'Точка2': [-170.0, 0.0 ],
|
||||
'Море' : [ 19.4, 54.91 ] }
|
||||
'Калиниград': [ 20.51095, 54.70649 ],
|
||||
'Москва': [ 37.6156, 55.7522 ],
|
||||
'Нью-Йорк': [ -74.006, 40.7143 ],
|
||||
'Сидней': [ 151.20732, -33.8678500 ],
|
||||
'Таганрог': [ 38.8969, 47.2362 ],
|
||||
'Хельсинки': [ 24.9354, 60.1695 ],
|
||||
'Азорские о-ва': [ 28.3996582, 38.5397568 ],
|
||||
'Мехико': [ -99.12766, 19.42847 ],
|
||||
'Белое море': [ 68.136606, 42.045546 ],
|
||||
'море Беллинсгаузена': [ -72.406587, -74.857997 ],
|
||||
'Фиджи': [ 178.065032, -17.713371 ],
|
||||
'Ноль': [ 0.0, 0.0 ],
|
||||
'Точка1': [ 170.0, 0.0 ],
|
||||
'Точка2': [-170.0, 0.0 ],
|
||||
'Море' : [ 19.4, 54.91 ] }
|
||||
|
||||
|
||||
const MAP_MODES: = {
|
||||
0: 'application/config/map_image_size_rto',
|
||||
1: 'application/config/map_image_size_rls' }
|
||||
0: 'application/config/map_image_size_rto',
|
||||
1: 'application/config/map_image_size_rls' }
|
||||
|
||||
|
||||
const MAP_RELATIVE_RADIUSES: = {
|
||||
0: 0.39,
|
||||
1: 0.466
|
||||
0: 0.39,
|
||||
1: 0.466
|
||||
}
|
||||
|
||||
|
||||
var map_image: Image ## Изображение с картой
|
||||
var map_tile_state: TASK_STATE ## Текущее состояние конечного автомата плитки
|
||||
var map_bcs: Vector3 ## Яркость, контраст насыщенность
|
||||
var map_server_addr: String ## Адрес сервера изображений карт в проекции Меркатора
|
||||
var map_image: Image ## Изображение с картой.
|
||||
var map_tile_state: TASK_STATE ## Текущее состояние конечного автомата плитки.
|
||||
var map_bcs: Vector3 ## Яркость, контраст насыщенность.
|
||||
var map_server_addr: String ## Адрес сервера изображений карт в проекции Меркатора.
|
||||
var map_tile_format: String ##
|
||||
var map_tile_stack: Array ## Стек для хранения плиток карты
|
||||
var map_request: HTTPRequest ## Обработчик запросов http
|
||||
var map_zoom: int ## Уровень детализации карты
|
||||
var map_tile: Rect2i ## Область одной плитки: [x-координата области, y-координата области, x-индекс плитки, y-индекс плитки]
|
||||
var map_mode: int ## Режим карты: 0 - приоритет РТО, 1 - приоритет РЛС
|
||||
var map_tile_stack: Array ## Стек для хранения плиток карты.
|
||||
var map_request: HTTPRequest ## Обработчик запросов http.
|
||||
var map_zoom: int ## Уровень детализации карты.
|
||||
var map_tile: Rect2i ## Область одной плитки: [x-координата области, y-координата области, x-индекс плитки, y-индекс плитки].
|
||||
var map_mode: int ## Режим карты: 0 - приоритет РТО, 1 - приоритет РЛС.
|
||||
var prev_tiles_dic: Dictionary ##
|
||||
var lnglat: Array ## Текущие координаты
|
||||
var lnglat: Array ## Текущие координаты.
|
||||
var root_rect: Rect2i
|
||||
|
||||
|
||||
func _ready():
|
||||
lnglat = TEST_DATA['Таганрог']
|
||||
map_tile_state = TASK_STATE.DONE
|
||||
map_request = HTTPRequest.new()
|
||||
add_child(map_request)
|
||||
map_request.request_completed.connect(self._map_request_completed)
|
||||
map_bcs = ProjectSettings.get_setting('application/config/map_bcs', Vector3(1.0, 1.0, 1.0))
|
||||
map_server_addr = ProjectSettings.get_setting('application/config/map_server_addr')
|
||||
map_tile_format = ProjectSettings.get_setting('application/config/map_tile_format', '%s/%d/%d/%d.png')
|
||||
var map_image_size = ProjectSettings.get_setting(MAP_MODES[0], Vector2i(512, 512))
|
||||
var map_tile_size = ProjectSettings.get_setting('application/config/map_tile_size', 256)
|
||||
map_image = Image.create(map_image_size.x, map_image_size.y, true, Image.FORMAT_RGB8)
|
||||
map_tile = Rect2i(0, 0, map_tile_size, map_tile_size)
|
||||
signaller.connect('zoom_changed', Callable(self, '_on_zoom_changed'))
|
||||
signaller.connect('map_mode_changed', Callable(self, '_on_map_mode_changed'))
|
||||
log.info('Адрес сервера поставщика карт: \"%s\"' % map_server_addr)
|
||||
log.info('Модуль географической карты готов')
|
||||
lnglat = TEST_DATA['Таганрог']
|
||||
map_tile_state = TASK_STATE.DONE
|
||||
map_request = HTTPRequest.new()
|
||||
add_child(map_request)
|
||||
map_request.request_completed.connect(self._map_request_completed)
|
||||
map_bcs = ProjectSettings.get_setting('application/config/map_bcs', Vector3(1.0, 1.0, 1.0))
|
||||
map_server_addr = ProjectSettings.get_setting('application/config/map_server_addr')
|
||||
map_tile_format = ProjectSettings.get_setting('application/config/map_tile_format', '%s/%d/%d/%d.png')
|
||||
var map_image_size = ProjectSettings.get_setting(MAP_MODES[0], Vector2i(512, 512))
|
||||
var map_tile_size = ProjectSettings.get_setting('application/config/map_tile_size', 256)
|
||||
map_image = Image.create(map_image_size.x, map_image_size.y, true, Image.FORMAT_RGB8)
|
||||
map_tile = Rect2i(0, 0, map_tile_size, map_tile_size)
|
||||
signaller.connect('zoom_changed', Callable(self, '_on_zoom_changed'))
|
||||
signaller.connect('map_mode_changed', Callable(self, '_on_map_mode_changed'))
|
||||
log.info('Адрес сервера поставщика карт: \"%s\"' % map_server_addr)
|
||||
log.info('Модуль географической карты готов')
|
||||
|
||||
|
||||
|
||||
func _on_map_mode_changed(mode: int) -> void:
|
||||
var map_image_size = ProjectSettings.get_setting(MAP_MODES[mode])
|
||||
material.set('shader_parameter/radius', MAP_RELATIVE_RADIUSES[mode])
|
||||
map_image.fill(Color(0, 0, 0, 0))
|
||||
map_image.resize(map_image_size.x, map_image_size.y)
|
||||
map_tile_state = TASK_STATE.DONE
|
||||
map_mode = mode
|
||||
var tile: = mercator.create_tile(lnglat[0], lnglat[1], map_zoom)
|
||||
map_tile_stack.clear()
|
||||
map_tile_stack.append(tile)
|
||||
prev_tiles_dic.clear()
|
||||
var map_image_size = ProjectSettings.get_setting(MAP_MODES[mode])
|
||||
material.set('shader_parameter/radius', MAP_RELATIVE_RADIUSES[mode])
|
||||
map_image.fill(Color(0, 0, 0, 0))
|
||||
map_image.resize(map_image_size.x, map_image_size.y)
|
||||
map_tile_state = TASK_STATE.DONE
|
||||
map_mode = mode
|
||||
var tile: = mercator.create_tile(lnglat[0], lnglat[1], map_zoom)
|
||||
map_tile_stack.clear()
|
||||
map_tile_stack.append(tile)
|
||||
prev_tiles_dic.clear()
|
||||
|
||||
|
||||
func mark_image_center(image: Image, color: Color = Color.RED):
|
||||
var c = image.get_size() / 2
|
||||
map_image.set_pixel(c.x - 1, c.y - 1, color)
|
||||
map_image.set_pixel(c.x - 1, c.y, color)
|
||||
map_image.set_pixel(c.x, c.y - 1, color)
|
||||
map_image.set_pixel(c.x, c.y, color)
|
||||
var c = image.get_size() / 2
|
||||
map_image.set_pixel(c.x - 1, c.y - 1, color)
|
||||
map_image.set_pixel(c.x - 1, c.y, color)
|
||||
map_image.set_pixel(c.x, c.y - 1, color)
|
||||
map_image.set_pixel(c.x, c.y, color)
|
||||
|
||||
|
||||
func _on_zoom_changed(zoom: int):
|
||||
if map_tile_stack.size() != 0:
|
||||
return
|
||||
map_zoom = zoom
|
||||
var tile: = mercator.create_tile(lnglat[0], lnglat[1], zoom)
|
||||
map_tile_stack.clear()
|
||||
map_tile_stack.append(tile)
|
||||
prev_tiles_dic.clear()
|
||||
if map_tile_stack.size() != 0:
|
||||
return
|
||||
map_zoom = zoom
|
||||
var tile: = mercator.create_tile(lnglat[0], lnglat[1], zoom)
|
||||
map_tile_stack.clear()
|
||||
map_tile_stack.append(tile)
|
||||
prev_tiles_dic.clear()
|
||||
|
||||
|
||||
func img_tile_to_map_image(image: Image, dst_pos: Vector2i):
|
||||
image.adjust_bcs(map_bcs.x, map_bcs.y, map_bcs.z)
|
||||
map_image.blit_rect(image, map_tile, dst_pos)
|
||||
image.adjust_bcs(map_bcs.x, map_bcs.y, map_bcs.z)
|
||||
map_image.blit_rect(image, map_tile, dst_pos)
|
||||
|
||||
|
||||
func _process(_delta: float):
|
||||
if (map_tile_state == TASK_STATE.DONE) and map_tile_stack.size():
|
||||
var tile: mercator.Tile = map_tile_stack[-1]
|
||||
var tile_addr: = map_tile_format % [map_server_addr, tile.z, tile.x , tile.y]
|
||||
var rc = map_request.request(tile_addr)
|
||||
if rc == OK:
|
||||
map_tile_state = TASK_STATE.WAIT
|
||||
else:
|
||||
log.error('%s: Невозможно сформировать запрос HTTP' % self)
|
||||
map_tile_state = TASK_STATE.ERROR
|
||||
elif map_tile_state == TASK_STATE.CHECK:
|
||||
var root_tile: = mercator.Tile.new(root_rect.size.x, root_rect.size.y, map_zoom)
|
||||
var neighbors_tiles = mercator.get_perimetr_tiles(root_tile, (map_image.get_size().x / map_tile.size.x) / 2)
|
||||
var neighbors_tiles_dic = {}
|
||||
for tile in neighbors_tiles:
|
||||
neighbors_tiles_dic[[tile.x, tile.y]] = false
|
||||
if neighbors_tiles_dic != prev_tiles_dic:
|
||||
for tile in neighbors_tiles:
|
||||
tile.is_root = false
|
||||
map_tile_stack.push_front(tile)
|
||||
prev_tiles_dic[[tile.x, tile.y]] = false
|
||||
else:
|
||||
if map_tile_stack.size() == 0:
|
||||
signaller.emit_signal('zoom_complete', map_zoom)
|
||||
map_tile_state = TASK_STATE.DONE
|
||||
if (map_tile_state == TASK_STATE.DONE) and map_tile_stack.size():
|
||||
var tile: mercator.Tile = map_tile_stack[-1]
|
||||
var tile_addr: = map_tile_format % [map_server_addr, tile.z, tile.x , tile.y]
|
||||
var rc = map_request.request(tile_addr)
|
||||
if rc == OK:
|
||||
map_tile_state = TASK_STATE.WAIT
|
||||
else:
|
||||
log.error('%s: Невозможно сформировать запрос HTTP' % self)
|
||||
map_tile_state = TASK_STATE.ERROR
|
||||
elif map_tile_state == TASK_STATE.CHECK:
|
||||
var root_tile: = mercator.Tile.new(root_rect.size.x, root_rect.size.y, map_zoom)
|
||||
var neighbors_tiles = mercator.get_perimetr_tiles(root_tile, (map_image.get_size().x / map_tile.size.x) / 2)
|
||||
var neighbors_tiles_dic = {}
|
||||
for tile in neighbors_tiles:
|
||||
neighbors_tiles_dic[[tile.x, tile.y]] = false
|
||||
if neighbors_tiles_dic != prev_tiles_dic:
|
||||
for tile in neighbors_tiles:
|
||||
tile.is_root = false
|
||||
map_tile_stack.push_front(tile)
|
||||
prev_tiles_dic[[tile.x, tile.y]] = false
|
||||
else:
|
||||
if map_tile_stack.size() == 0:
|
||||
signaller.emit_signal('zoom_complete', map_zoom)
|
||||
map_tile_state = TASK_STATE.DONE
|
||||
|
||||
|
||||
func _map_request_completed(result, response_code, headers, data):
|
||||
if result != HTTPRequest.RESULT_SUCCESS:
|
||||
log.error('%s: Запрос не обработан. result: \"%s\", response_code: \"%s\", headers: \"%s\"' % [self, result, response_code, headers])
|
||||
map_tile_state = TASK_STATE.ERROR
|
||||
return
|
||||
if result != HTTPRequest.RESULT_SUCCESS:
|
||||
log.error('%s: Запрос не обработан. result: \"%s\", response_code: \"%s\", headers: \"%s\"' % [self, result, response_code, headers])
|
||||
map_tile_state = TASK_STATE.ERROR
|
||||
return
|
||||
|
||||
var img_tile = Image.new()
|
||||
var error = img_tile.load_png_from_buffer(data)
|
||||
if error != OK:
|
||||
log.error('%s: Полученые данные невозможно использовать для формироания изображения. result: \"%s\", response_code: \"%s\", headers: \"%s\"' % [self, result, response_code, headers])
|
||||
map_tile_state = TASK_STATE.ERROR
|
||||
return
|
||||
var img_tile = Image.new()
|
||||
var error = img_tile.load_png_from_buffer(data)
|
||||
if error != OK:
|
||||
log.error('%s: Полученые данные невозможно использовать для формироания изображения. result: \"%s\", response_code: \"%s\", headers: \"%s\"' % [self, result, response_code, headers])
|
||||
map_tile_state = TASK_STATE.ERROR
|
||||
return
|
||||
|
||||
var tile = map_tile_stack.pop_back()
|
||||
map_tile_state = TASK_STATE.CHECK
|
||||
var tile = map_tile_stack.pop_back()
|
||||
map_tile_state = TASK_STATE.CHECK
|
||||
|
||||
if tile.is_root:
|
||||
# Отображение корневой плитки
|
||||
map_image.fill(Color(0, 0, 0, 0))
|
||||
var bounds: = mercator.bounds(tile)
|
||||
var lng_c = (bounds.east + bounds.west) / 2.0
|
||||
var lat_c = (bounds.north + bounds.south) / 2.0
|
||||
var sx: float = float(map_tile.size.x) / (bounds.east - bounds.west) * (lng_c - tile.lng) + map_tile.size.x / 2.0 # Cмещение в пискселях центра плитки от заданной точки по горизонтали.
|
||||
var sy: float = float(map_tile.size.y) / (bounds.north - bounds.south) * (lat_c - tile.lat) - map_tile.size.y / 2.0 # Cмещение в пискселях центра плитки от заданной точки по вертикали.
|
||||
var dst_pos: Vector2i = Vector2i(int(sx), int(-sy)) + map_tile.size * map_mode
|
||||
img_tile_to_map_image(img_tile, dst_pos)
|
||||
root_rect = Rect2i(dst_pos.x, dst_pos.y, tile.x, tile.y)
|
||||
else:
|
||||
# Отображение соседних плиток
|
||||
var delta: = Vector2i(tile.x - root_rect.size.x, tile.y - root_rect.size.y)
|
||||
var dst_pos: Vector2i = root_rect.position + delta * map_tile.size
|
||||
img_tile_to_map_image(img_tile, dst_pos)
|
||||
mark_image_center(map_image)
|
||||
texture = ImageTexture.create_from_image(map_image)
|
||||
|
||||
if tile.is_root:
|
||||
# Отображение корневой плитки
|
||||
map_image.fill(Color(0, 0, 0, 0))
|
||||
var bounds: = mercator.bounds(tile)
|
||||
var lng_c = (bounds.east + bounds.west) / 2.0
|
||||
var lat_c = (bounds.north + bounds.south) / 2.0
|
||||
var sx: float = float(map_tile.size.x) / (bounds.east - bounds.west) * (lng_c - tile.lng) + map_tile.size.x / 2.0 # Cмещение в пискселях центра плитки от заданной точки по горизонтали.
|
||||
var sy: float = float(map_tile.size.y) / (bounds.north - bounds.south) * (lat_c - tile.lat) - map_tile.size.y / 2.0 # Cмещение в пискселях центра плитки от заданной точки по вертикали.
|
||||
var dst_pos: Vector2i = Vector2i(int(sx), int(-sy)) + map_tile.size * map_mode
|
||||
img_tile_to_map_image(img_tile, dst_pos)
|
||||
root_rect = Rect2i(dst_pos.x, dst_pos.y, tile.x, tile.y)
|
||||
else:
|
||||
# Отображение соседних плиток
|
||||
var delta: = Vector2i(tile.x - root_rect.size.x, tile.y - root_rect.size.y)
|
||||
var dst_pos: Vector2i = root_rect.position + delta * map_tile.size
|
||||
img_tile_to_map_image(img_tile, dst_pos)
|
||||
mark_image_center(map_image)
|
||||
texture = ImageTexture.create_from_image(map_image)
|
||||
|
||||
@@ -1,14 +1,41 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://bbq6nklh36yij"]
|
||||
[gd_scene load_steps=6 format=3 uid="uid://bbq6nklh36yij"]
|
||||
|
||||
[ext_resource type="Script" path="res://scenes/tilemap/tilemap.gd" id="1_mkfgj"]
|
||||
[ext_resource type="Shader" path="res://shaders/tilemap.gdshader" id="1_tsdui"]
|
||||
[ext_resource type="Script" path="res://scenes/tilemap/Node2D.gd" id="3_lr4ti"]
|
||||
|
||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_pmqvj"]
|
||||
resource_local_to_scene = true
|
||||
shader = ExtResource("1_tsdui")
|
||||
shader_parameter/radius = 0.39
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ys5v4"]
|
||||
|
||||
[node name="tilemap" type="Sprite2D"]
|
||||
material = SubResource("ShaderMaterial_pmqvj")
|
||||
position = Vector2(560, 560)
|
||||
script = ExtResource("1_mkfgj")
|
||||
|
||||
[node name="Panel" type="Panel" parent="."]
|
||||
offset_left = -563.0
|
||||
offset_top = -557.0
|
||||
offset_right = 1022.0
|
||||
offset_bottom = 641.0
|
||||
theme_override_styles/panel = SubResource("StyleBoxEmpty_ys5v4")
|
||||
|
||||
[node name="Node2D" type="Node2D" parent="."]
|
||||
script = ExtResource("3_lr4ti")
|
||||
|
||||
[node name="LineEdit" type="LineEdit" parent="Node2D"]
|
||||
offset_left = -490.0
|
||||
offset_top = 518.0
|
||||
offset_right = -244.0
|
||||
offset_bottom = 565.0
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="Node2D"]
|
||||
offset_left = -499.0
|
||||
offset_top = 200.0
|
||||
offset_right = -239.0
|
||||
offset_bottom = 430.0
|
||||
|
||||
[connection signal="gui_input" from="Panel" to="." method="_on_panel_gui_input"]
|
||||
|
||||
@@ -9,58 +9,58 @@ func on_interfer_off(ecm, _ecms, _thrs,msg: String): log.message(Logger.INFO, '%
|
||||
func on_set_program_mode(msg: String): log.message(Logger.INFO, msg)
|
||||
|
||||
func on_interfer_new(ecm, msg: String):
|
||||
if ecm.krp != interfer.INTERFER_OFF:
|
||||
log.message(Logger.INFO, '%s: %s' % [msg, ecm.to_string()])
|
||||
if ecm.krp != interfer.INTERFER_OFF:
|
||||
log.message(Logger.INFO, '%s: %s' % [msg, ecm.to_string()])
|
||||
|
||||
|
||||
func _enter_tree():
|
||||
var flts: Array = []
|
||||
for item in $filtrs.get_children():
|
||||
flts.append(item)
|
||||
log.set_filtrs(flts)
|
||||
var flts: Array = []
|
||||
for item in $filtrs.get_children():
|
||||
flts.append(item)
|
||||
log.set_filtrs(flts)
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
log.info('Модуль журнала работы готов')
|
||||
log.info('Аргументы коммандной строки: \"%s\"' % OS.get_cmdline_args())
|
||||
log.info('Операционная система: %s' % [OS.get_distribution_name()])
|
||||
log.info('Текущая версия ПО УАРЭП: %s' % commit.VCS_HEAD)
|
||||
threats.connect('threat_new', Callable(self, 'on_threats_changed').bind('Цель обнаружена'))
|
||||
threats.connect('threat_lost', Callable(self, 'on_threats_changed').bind('Цель потеряна'))
|
||||
signaller.conn(signaller.interfer_new, Callable(self, 'on_interfer_new').bind('Создан сеанс помехи'))
|
||||
signaller.conn(signaller.interfer_off, Callable(self, 'on_interfer_off').bind('Сеанс помехи отключен'))
|
||||
signaller.conn(signaller.режим_работа, Callable(log, 'info').bind('Программа в режиме \"Работа\"'))
|
||||
signaller.conn(signaller.режим_настройки, Callable(log, 'info').bind('Программа в режиме \"Настройки\"'))
|
||||
signaller.conn(signaller.режим_эмс, Callable(log, 'info').bind('Программа в режиме \"ЭМС\"'))
|
||||
signaller.conn(signaller.режим_журнал, Callable(log, 'info').bind('Программа в режиме \"Журнал\"'))
|
||||
signaller.conn(signaller.режим_контроль, Callable(log, 'info').bind('Программа в режиме \"Контроль\"'))
|
||||
log.info('Модуль журнала работы готов')
|
||||
log.info('Аргументы коммандной строки: \"%s\"' % OS.get_cmdline_args())
|
||||
log.info('Операционная система: %s' % [OS.get_distribution_name()])
|
||||
log.info('Текущая версия ПО УАРЭП: %s' % commit.VCS_HEAD)
|
||||
threats.connect('threat_new', Callable(self, 'on_threats_changed').bind('Цель обнаружена'))
|
||||
threats.connect('threat_lost', Callable(self, 'on_threats_changed').bind('Цель потеряна'))
|
||||
signaller.conn(signaller.interfer_new, Callable(self, 'on_interfer_new').bind('Создан сеанс помехи'))
|
||||
signaller.conn(signaller.interfer_off, Callable(self, 'on_interfer_off').bind('Сеанс помехи отключен'))
|
||||
signaller.conn(signaller.режим_работа, Callable(log, 'info').bind('Программа в режиме \"Работа\"'))
|
||||
signaller.conn(signaller.режим_настройки, Callable(log, 'info').bind('Программа в режиме \"Настройки\"'))
|
||||
signaller.conn(signaller.режим_эмс, Callable(log, 'info').bind('Программа в режиме \"ЭМС\"'))
|
||||
signaller.conn(signaller.режим_журнал, Callable(log, 'info').bind('Программа в режиме \"Журнал\"'))
|
||||
signaller.conn(signaller.режим_контроль, Callable(log, 'info').bind('Программа в режиме \"Контроль\"'))
|
||||
|
||||
|
||||
func _on_clear_button_down() -> void:
|
||||
$content.clear()
|
||||
log.info('Cодержание журнала очищено оператором')
|
||||
$content.clear()
|
||||
log.info('Cодержание журнала очищено оператором')
|
||||
|
||||
|
||||
func _on_btn_save_button_down() -> void:
|
||||
$content.hide()
|
||||
$btn_clear.hide()
|
||||
$btn_save.hide()
|
||||
$filtrs.hide()
|
||||
$dlg_file.show()
|
||||
$content.hide()
|
||||
$btn_clear.hide()
|
||||
$btn_save.hide()
|
||||
$filtrs.hide()
|
||||
$dlg_file.show()
|
||||
|
||||
|
||||
func _on_dlg_file_confirmed() -> void:
|
||||
$content.show()
|
||||
$btn_clear.show()
|
||||
$btn_save.show()
|
||||
$filtrs.show()
|
||||
$dlg_file.hide()
|
||||
$content.show()
|
||||
$btn_clear.show()
|
||||
$btn_save.show()
|
||||
$filtrs.show()
|
||||
$dlg_file.hide()
|
||||
|
||||
|
||||
func _on_dlg_file_file_selected(path):
|
||||
log.save_file(path)
|
||||
log.save_file(path)
|
||||
|
||||
|
||||
func _on_check_box_pressed():
|
||||
$content.clear()
|
||||
log.add_msgs()
|
||||
$content.clear()
|
||||
log.add_msgs()
|
||||
|
||||
@@ -7,11 +7,11 @@ extends NinePatchRect
|
||||
"""
|
||||
|
||||
@export var fname: String:
|
||||
set(v):
|
||||
fname = v
|
||||
$lbl_fname.text = v
|
||||
set(v):
|
||||
fname = v
|
||||
$lbl_fname.text = v
|
||||
|
||||
|
||||
@export var rname: String:
|
||||
set(v):
|
||||
rname = v
|
||||
set(v):
|
||||
rname = v
|
||||
|
||||
@@ -7,7 +7,7 @@ extends Node
|
||||
func _on_toggled(toggled_on): $frame.visible = toggled_on
|
||||
|
||||
@export var state: int:
|
||||
set(v):
|
||||
v = 0 if v < 0 else v % state_colors.size()
|
||||
state = v
|
||||
$label.self_modulate = state_colors[v]
|
||||
set(v):
|
||||
v = 0 if v < 0 else v % state_colors.size()
|
||||
state = v
|
||||
$label.self_modulate = state_colors[v]
|
||||
|
||||
@@ -6,50 +6,50 @@ extends Panel
|
||||
|
||||
const PRIBORS_RES = \
|
||||
{
|
||||
'pribor_afsp_l': ['res://scenes/pribor-afsp/pribor-afsp.tscn', 'Контроль исправности прибора АФСП левый'],
|
||||
'pribor_afsp_r': ['res://scenes/pribor-afsp/pribor-afsp.tscn', 'Контроль исправности прибора АФСП правый'],
|
||||
'pribor_prd_k_1': ['res://scenes/pribor-prd-k/pribor-prd-k.tscn', 'Контроль исправности прибора ПРД-К 1'],
|
||||
'pribor_prd_k_2': ['res://scenes/pribor-prd-k/pribor-prd-k.tscn', 'Контроль исправности прибора ПРД-К 2'],
|
||||
'pribor_prd_k_3': ['res://scenes/pribor-prd-k/pribor-prd-k.tscn', 'Контроль исправности прибора ПРД-К 3'],
|
||||
'pribor_prd_k_4': ['res://scenes/pribor-prd-k/pribor-prd-k.tscn', 'Контроль исправности прибора ПРД-К 4'],
|
||||
'pribor_prd_n_1': ['res://scenes/pribor-prd-n/pribor-prd-n.tscn', 'Контроль исправности прибора ПРД-Н 1'],
|
||||
'pribor_prd_n_2': ['res://scenes/pribor-prd-n/pribor-prd-n.tscn', 'Контроль исправности прибора ПРД-Н 2'],
|
||||
'pribor_prd_n_3': ['res://scenes/pribor-prd-n/pribor-prd-n.tscn', 'Контроль исправности прибора ПРД-Н 3'],
|
||||
'pribor_prd_n_4': ['res://scenes/pribor-prd-n/pribor-prd-n.tscn', 'Контроль исправности прибора ПРД-Н 4'],
|
||||
'pribor_prd_v_1': ['res://scenes/pribor-prd-v/pribor-prd-v.tscn', 'Контроль исправности прибора ПРД-В 1'],
|
||||
'pribor_prd_v_2': ['res://scenes/pribor-prd-v/pribor-prd-v.tscn', 'Контроль исправности прибора ПРД-В 2'],
|
||||
'pribor_prd_v_3': ['res://scenes/pribor-prd-v/pribor-prd-v.tscn', 'Контроль исправности прибора ПРД-В 3'],
|
||||
'pribor_prd_v_4': ['res://scenes/pribor-prd-v/pribor-prd-v.tscn', 'Контроль исправности прибора ПРД-В 4'],
|
||||
'pribor_rtr': ['res://scenes/pribor-rtr/pribor-rtr.tscn', 'Контроль исправности прибора РТР'],
|
||||
'pribor_uf': ['res://scenes/pribor-uf/pribor-uf.tscn', 'Контроль исправности прибора УФ'],
|
||||
'pribor_uyep': ['res://scenes/pribor-uyep/pribor-uyep.tscn', 'Контроль исправности прибора УЭП'],
|
||||
}
|
||||
'pribor_afsp_l': ['res://scenes/pribor-afsp/pribor-afsp.tscn', 'Контроль исправности прибора АФСП левый'],
|
||||
'pribor_afsp_r': ['res://scenes/pribor-afsp/pribor-afsp.tscn', 'Контроль исправности прибора АФСП правый'],
|
||||
'pribor_prd_k_1': ['res://scenes/pribor-prd-k/pribor-prd-k.tscn', 'Контроль исправности прибора ПРД-К 1'],
|
||||
'pribor_prd_k_2': ['res://scenes/pribor-prd-k/pribor-prd-k.tscn', 'Контроль исправности прибора ПРД-К 2'],
|
||||
'pribor_prd_k_3': ['res://scenes/pribor-prd-k/pribor-prd-k.tscn', 'Контроль исправности прибора ПРД-К 3'],
|
||||
'pribor_prd_k_4': ['res://scenes/pribor-prd-k/pribor-prd-k.tscn', 'Контроль исправности прибора ПРД-К 4'],
|
||||
'pribor_prd_n_1': ['res://scenes/pribor-prd-n/pribor-prd-n.tscn', 'Контроль исправности прибора ПРД-Н 1'],
|
||||
'pribor_prd_n_2': ['res://scenes/pribor-prd-n/pribor-prd-n.tscn', 'Контроль исправности прибора ПРД-Н 2'],
|
||||
'pribor_prd_n_3': ['res://scenes/pribor-prd-n/pribor-prd-n.tscn', 'Контроль исправности прибора ПРД-Н 3'],
|
||||
'pribor_prd_n_4': ['res://scenes/pribor-prd-n/pribor-prd-n.tscn', 'Контроль исправности прибора ПРД-Н 4'],
|
||||
'pribor_prd_v_1': ['res://scenes/pribor-prd-v/pribor-prd-v.tscn', 'Контроль исправности прибора ПРД-В 1'],
|
||||
'pribor_prd_v_2': ['res://scenes/pribor-prd-v/pribor-prd-v.tscn', 'Контроль исправности прибора ПРД-В 2'],
|
||||
'pribor_prd_v_3': ['res://scenes/pribor-prd-v/pribor-prd-v.tscn', 'Контроль исправности прибора ПРД-В 3'],
|
||||
'pribor_prd_v_4': ['res://scenes/pribor-prd-v/pribor-prd-v.tscn', 'Контроль исправности прибора ПРД-В 4'],
|
||||
'pribor_rtr': ['res://scenes/pribor-rtr/pribor-rtr.tscn', 'Контроль исправности прибора РТР'],
|
||||
'pribor_uf': ['res://scenes/pribor-uf/pribor-uf.tscn', 'Контроль исправности прибора УФ'],
|
||||
'pribor_uyep': ['res://scenes/pribor-uyep/pribor-uyep.tscn', 'Контроль исправности прибора УЭП'],
|
||||
}
|
||||
|
||||
|
||||
func _ready():
|
||||
var group = ButtonGroup.new()
|
||||
for k in PRIBORS_RES:
|
||||
var pribor_node = get_node(k)
|
||||
assert(pribor_node)
|
||||
var pribor_path = PRIBORS_RES[k][0]
|
||||
var header_text = PRIBORS_RES[k][1]
|
||||
pribor_node.set_button_group(group)
|
||||
pribor_node.connect('button_down', Callable(self, 'on_pribor_press').bind(pribor_path, header_text))
|
||||
log.info('Модуль контроля работы готов')
|
||||
var group = ButtonGroup.new()
|
||||
for k in PRIBORS_RES:
|
||||
var pribor_node = get_node(k)
|
||||
assert(pribor_node)
|
||||
var pribor_path = PRIBORS_RES[k][0]
|
||||
var header_text = PRIBORS_RES[k][1]
|
||||
pribor_node.set_button_group(group)
|
||||
pribor_node.connect('button_down', Callable(self, 'on_pribor_press').bind(pribor_path, header_text))
|
||||
log.info('Модуль контроля работы готов')
|
||||
|
||||
|
||||
func on_pribor_press(pribor_path, header_text):
|
||||
clear_obj($mnemo_container)
|
||||
var pribor_obj = load(pribor_path)
|
||||
assert(pribor_obj)
|
||||
var pribor = pribor_obj.instantiate()
|
||||
assert(pribor)
|
||||
pribor.set_header_text(header_text)
|
||||
$mnemo_container.add_child(pribor)
|
||||
clear_obj($mnemo_container)
|
||||
var pribor_obj = load(pribor_path)
|
||||
assert(pribor_obj)
|
||||
var pribor = pribor_obj.instantiate()
|
||||
assert(pribor)
|
||||
pribor.set_header_text(header_text)
|
||||
$mnemo_container.add_child(pribor)
|
||||
|
||||
|
||||
func clear_obj(obj: Object):
|
||||
var items = obj.get_children()
|
||||
for item in items:
|
||||
obj.remove_child(item)
|
||||
item.queue_free()
|
||||
var items = obj.get_children()
|
||||
for item in items:
|
||||
obj.remove_child(item)
|
||||
item.queue_free()
|
||||
|
||||
@@ -7,20 +7,20 @@ extends Control
|
||||
"""
|
||||
|
||||
@export var fname: String:
|
||||
set(v):
|
||||
fname = v
|
||||
get:
|
||||
return fname
|
||||
set(v):
|
||||
fname = v
|
||||
get:
|
||||
return fname
|
||||
|
||||
@export var rname: String:
|
||||
set(v):
|
||||
rname = v
|
||||
get:
|
||||
return rname
|
||||
set(v):
|
||||
rname = v
|
||||
get:
|
||||
return rname
|
||||
|
||||
|
||||
func set_header_text(header_text: String):
|
||||
$lbl_header.text = header_text
|
||||
$lbl_header.text = header_text
|
||||
|
||||
|
||||
@export var nodes_mask: String = ''
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
extends Panel
|
||||
class_name setting extends Panel
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
## Вызывается, когда узел впервые попадает в дерево сцены.
|
||||
func _ready() -> void:
|
||||
$lbl_commit.text = 'Текущая версия ПО УАРЭП: \"%s\"' % commit.VCS_HEAD
|
||||
if not OS.get_cmdline_args().has('++ограниченный'):
|
||||
return
|
||||
$Label2.text = 'Текущий режим доступа: ограниченный'
|
||||
for node in $GridContainer.get_children().filter(func(b): return b is Button):
|
||||
node.disabled = true
|
||||
$lbl_commit.text = 'Текущая версия ПО УАРЭП: \"%s\"' % commit.VCS_HEAD
|
||||
if not OS.get_cmdline_args().has('++ограниченный'):
|
||||
return
|
||||
$Label2.text = 'Текущий режим доступа: ограниченный'
|
||||
for node in $GridContainer.get_children().filter(func(b): return b is Button):
|
||||
node.disabled = true
|
||||
|
||||
|
||||
func _on_external_cu_btn_pressed() -> void:
|
||||
var state = $GridContainer2/external_cu_btn.button_pressed
|
||||
ProjectSettings.set_setting('application/config/external_cu', state)
|
||||
if state:
|
||||
signaller.emit_signal('interfer_off_all')
|
||||
var state = $GridContainer2/external_cu_btn.button_pressed
|
||||
ProjectSettings.set_setting('application/config/external_cu', state)
|
||||
if state:
|
||||
signaller.emit_signal('interfer_off_all')
|
||||
|
||||
@@ -7,10 +7,10 @@ func _ready(): _on_value_changed(3)
|
||||
|
||||
|
||||
func _on_value_changed(val):
|
||||
val = int(val)
|
||||
for nm in VAL_TO_LABEL.values():
|
||||
var lbl0 = get_node(nm)
|
||||
lbl0.self_modulate.a = 0.45
|
||||
var lbl1 = get_node(VAL_TO_LABEL[val])
|
||||
lbl1.self_modulate.a = 1.0
|
||||
signaller.emit_signal(VAL_TO_EVENT[val])
|
||||
val = int(val)
|
||||
for nm in VAL_TO_LABEL.values():
|
||||
var lbl0 = get_node(nm)
|
||||
lbl0.self_modulate.a = 0.45
|
||||
var lbl1 = get_node(VAL_TO_LABEL[val])
|
||||
lbl1.self_modulate.a = 1.0
|
||||
signaller.emit_signal(VAL_TO_EVENT[val])
|
||||
|
||||
@@ -1,477 +1,492 @@
|
||||
@tool
|
||||
|
||||
extends Panel
|
||||
class_name work extends Panel
|
||||
|
||||
## Основной скрипт для режима "Работа"
|
||||
## Основной скрипт для режима "Работа".
|
||||
|
||||
@export var Bip: PackedScene ## Индикатор излучения цели
|
||||
@export var col_grey: Color ## Второй цвет для фона
|
||||
@export var col_red: Color ## Первый цвет для фона
|
||||
@export var drag_scale_band: float ## Масштаб изменения параметра от движения мыши для строба по радиальному размеру
|
||||
@export var drag_scale_width: float ## Масштаб изменения параметра от движения мыши для строба по угловому размеру
|
||||
@export var Bip: PackedScene ## Индикатор излучения цели.
|
||||
@export var col_grey: Color ## Второй цвет для фона.
|
||||
@export var col_red: Color ## Первый цвет для фона.
|
||||
@export var drag_scale_band: float ## Масштаб изменения параметра от движения мыши для строба по радиальному размеру.
|
||||
@export var drag_scale_width: float ## Масштаб изменения параметра от движения мыши для строба по угловому размеру.
|
||||
@export var freq_high: float ## Верхняя рабочая частота, МГЦ.
|
||||
@export var freq_low: float ## Нижняя рабочая частота, МГЦ.
|
||||
@export var radius_center: Vector2 ## Координаты центра диаграммы пеленг-частота
|
||||
@export var radius_internal: float ## Внутренний радиус диаграммы пеленг-частота
|
||||
@export var radius_outter: float ## Внешний радиус диаграммы пеленг-частота
|
||||
@export var strob_max_band: float ## Максимальная ширина строба по углу
|
||||
@export var strob_max_width: float ## Максимальная ширина строба по углу
|
||||
@export var strob_min_band: float ## Минимальная ширина строба по частоте
|
||||
@export var strob_min_width: float ## Минимальная ширина строба по углу
|
||||
@export var window_0_id: int ## Идетификатор окна. Присваивается godot от 0 до количества созданных окон
|
||||
@export var radius_center: Vector2 ## Координаты центра диаграммы пеленг-частота.
|
||||
@export var radius_internal: float ## Внутренний радиус диаграммы пеленг-частота.
|
||||
@export var radius_outter: float ## Внешний радиус диаграммы пеленг-частота.
|
||||
@export var strob_max_band: float ## Максимальная ширина строба по углу.
|
||||
@export var strob_max_width: float ## Максимальная ширина строба по углу.
|
||||
@export var strob_min_band: float ## Минимальная ширина строба по частоте.
|
||||
@export var strob_min_width: float ## Минимальная ширина строба по углу.
|
||||
@export var window_0_id: int ## Идетификатор окна. Присваивается godot от 0 до количества созданных окон.
|
||||
|
||||
|
||||
var drag_button: MouseButton ## Кнопка мыши нажатая при перетаскивании
|
||||
var drag_fsm: DragFSM = DragFSM.IDLE ## Текущее состояние перетаскивания
|
||||
var btn_select: BtnSel = BtnSel.THREAT ## Текущее состояние кнопки выбора цели
|
||||
var drag_pos_begin: Vector2 ## Точка начала перетаскивания
|
||||
var max_zoom: int ## Максимальный уровень детализации
|
||||
var min_zoom: int ## Минимальный уровень детализации
|
||||
var shift_pressed: bool ## Кнопка SHIFT нажата
|
||||
var strob_band_begin: float ## Ширина строба в момент начала перетаскивания
|
||||
var strob_dir_begin: float ## Направление антенны в момент начала перетаскивания
|
||||
var strob_width_begin: float ## Ширина строба по углу в момент начала перетаскивания
|
||||
var drag_button: MouseButton ## Кнопка мыши нажатая при перетаскивании.
|
||||
var drag_fsm: DragFSM = DragFSM.IDLE ## Текущее состояние перетаскивания.
|
||||
var btn_select: BtnSel = BtnSel.THREAT ## Текущее состояние кнопки выбора цели.
|
||||
var drag_pos_begin: Vector2 ## Точка начала перетаскивания.
|
||||
var max_zoom: int ## Максимальный уровень детализации.
|
||||
var min_zoom: int ## Минимальный уровень детализации.
|
||||
var shift_pressed: bool ## Кнопка SHIFT нажата.
|
||||
var strob_band_begin: float ## Ширина строба в момент начала перетаскивания.
|
||||
var strob_dir_begin: float ## Направление антенны в момент начала перетаскивания.
|
||||
var strob_width_begin: float ## Ширина строба по углу в момент начала перетаскивания.
|
||||
|
||||
|
||||
signal drag_begin ## Вызывается в момент начала перетаскивания
|
||||
signal drag_continue ## Вызывается во время продолжения перетаскивания
|
||||
signal drag_end ## Вызывается в момент завершения перетаскивания
|
||||
signal drag_begin ## Вызывается в момент начала перетаскивания.
|
||||
signal drag_continue ## Вызывается во время продолжения перетаскивания.
|
||||
signal drag_end ## Вызывается в момент завершения перетаскивания.
|
||||
|
||||
## Границы секторов блоков ФС по частоте в режиме РТО
|
||||
## Границы секторов блоков ФС по частоте в режиме РТО.
|
||||
const fs_band_rto: Dictionary = {
|
||||
0: [200.0, 250.0],
|
||||
1: [250.0, 300.0],
|
||||
2: [300.0, 350.0],
|
||||
3: [350.0, 400.0],
|
||||
4: [400.0, 450.0],
|
||||
5: [450.0, 500.0],
|
||||
6: [500.0, 550.0] }
|
||||
0: [200.0, 250.0],
|
||||
1: [250.0, 300.0],
|
||||
2: [300.0, 350.0],
|
||||
3: [350.0, 400.0],
|
||||
4: [400.0, 450.0],
|
||||
5: [450.0, 500.0],
|
||||
6: [500.0, 550.0] }
|
||||
|
||||
## Границы секторов блоков ФС по частоте в режиме РЛС
|
||||
## Границы секторов блоков ФС по частоте в режиме РЛС.
|
||||
const fs_band_rls: Dictionary = {
|
||||
0: [480.0, 490.0],
|
||||
1: [490.0, 500.0],
|
||||
2: [500.0, 510.0],
|
||||
3: [510.0, 520.0],
|
||||
4: [520.0, 530.0],
|
||||
5: [530.0, 540.0],
|
||||
6: [540.0, 550.0] }
|
||||
0: [480.0, 490.0],
|
||||
1: [490.0, 500.0],
|
||||
2: [500.0, 510.0],
|
||||
3: [510.0, 520.0],
|
||||
4: [520.0, 530.0],
|
||||
5: [530.0, 540.0],
|
||||
6: [540.0, 550.0] }
|
||||
|
||||
## Границы секторов блоков ФС по пеленгу
|
||||
## Границы секторов блоков ФС по пеленгу.
|
||||
const fs_sectors: Dictionary = {
|
||||
0: [0.0, 90.0],
|
||||
3: [90.0, 180.0],
|
||||
2: [180.0, 270.0],
|
||||
1: [270.0, 360.0] }
|
||||
0: [0.0, 90.0],
|
||||
3: [90.0, 180.0],
|
||||
2: [180.0, 270.0],
|
||||
1: [270.0, 360.0] }
|
||||
|
||||
const fs_freq: Dictionary = {
|
||||
0: [400.0, 1200.0],
|
||||
1: [1200.0, 2000.0],
|
||||
2: [2000.0, 2800.0],
|
||||
3: [2800.0, 3600.0],
|
||||
4: [3600.0, 4400.0],
|
||||
5: [4400.0, 5200.0],
|
||||
6: [5200.0, 6000.0] }
|
||||
0: [400.0, 1200.0],
|
||||
1: [1200.0, 2000.0],
|
||||
2: [2000.0, 2800.0],
|
||||
3: [2800.0, 3600.0],
|
||||
4: [3600.0, 4400.0],
|
||||
5: [4400.0, 5200.0],
|
||||
6: [5200.0, 6000.0] }
|
||||
|
||||
var fs_band = fs_band_rto # Текущий режим блоков ФС по частоте
|
||||
var fs_selected: Dictionary # Словарь выбранных секторов
|
||||
var fs_active: Dictionary # Словарь секторов назначенных на подавление
|
||||
|
||||
## Состояние перетаскивания
|
||||
## Состояние перетаскивания.
|
||||
enum DragFSM {
|
||||
DRAG, ## В процессе
|
||||
IDLE, ## Не активно, ожидание
|
||||
OFF ## Выключено
|
||||
}
|
||||
DRAG, ## В процессе.
|
||||
IDLE, ## Не активно, ожидание.
|
||||
OFF ## Выключено.
|
||||
}
|
||||
|
||||
## Состояние перетаскивания
|
||||
## Состояние перетаскивания.
|
||||
enum BtnSel {
|
||||
SECTOR, ## В процессе
|
||||
THREAT, ## Не активно, ожидание
|
||||
FS ## Выключено
|
||||
}
|
||||
SECTOR, ## В процессе.
|
||||
THREAT, ## Не активно, ожидание.
|
||||
FS ## Выключено.
|
||||
}
|
||||
|
||||
## Обработчик сигнала изменения списка целей
|
||||
## Обработчик сигнала изменения списка целей.
|
||||
func on_threats_resized(threats: Dictionary): $count_all_pad/count_all.text = '%02d' % threats.size()
|
||||
|
||||
|
||||
## Обработчик выбора цели
|
||||
## Обработчик выбора цели.
|
||||
func on_threat_selected(th, ecm_btns): on_rto_threat_sel(th.id, ecm_btns)
|
||||
|
||||
|
||||
## Обработчик нажатия на кнопку вид
|
||||
## Обработчик нажатия на кнопку вид.
|
||||
func on_button_view_toggled(toggled: bool):
|
||||
signaller.emit_signal('map_mode_changed', int(toggled))
|
||||
if toggled:
|
||||
fs_band = fs_band_rls
|
||||
else:
|
||||
fs_band = fs_band_rto
|
||||
signaller.emit_signal('map_mode_changed', int(toggled))
|
||||
if toggled:
|
||||
fs_band = fs_band_rls
|
||||
else:
|
||||
fs_band = fs_band_rto
|
||||
|
||||
|
||||
##
|
||||
func _enter_tree() -> void:
|
||||
var timer1 = Timer.new()
|
||||
timer1.name = 'timer1'
|
||||
add_child(timer1)
|
||||
timer1.one_shot = true
|
||||
timer1.connect('timeout', Callable(self, 'on_enter_tree'))
|
||||
timer1.start(1.0)
|
||||
var timer1 = Timer.new()
|
||||
timer1.name = 'timer1'
|
||||
add_child(timer1)
|
||||
timer1.one_shot = true
|
||||
timer1.connect('timeout', Callable(self, 'on_enter_tree'))
|
||||
timer1.start(1.0)
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
var timer1 = get_node('timer1')
|
||||
remove_child(timer1)
|
||||
timer1.queue_free()
|
||||
var timer1 = get_node('timer1')
|
||||
remove_child(timer1)
|
||||
timer1.queue_free()
|
||||
|
||||
|
||||
## Производит инициализацию
|
||||
## Производит инициализацию.
|
||||
func _ready():
|
||||
min_zoom = ProjectSettings.get_setting('application/config/map_minimum_zoom', 5)
|
||||
max_zoom = ProjectSettings.get_setting('application/config/map_maximum_zoom', 19)
|
||||
drag_fsm = DragFSM.OFF
|
||||
$btn_zoom.set_meta('zoom', min_zoom - 1)
|
||||
var btns_select: Array = $btns_select.get_children()
|
||||
btns_select.any(func(btn): btn.button_connect('pressed', Callable(self, 'on_button_select').bind(btn, btns_select)))
|
||||
$btn_view.button_connect('toggled', Callable(self, 'on_button_view_toggled'))
|
||||
var nodes: Array = get_tree().get_nodes_in_group('группа-режим-помехи')
|
||||
nodes.any(func(btn): btn.button_connect('pressed', Callable(self, 'on_button_pressed').bind(btn, nodes)))
|
||||
threats.connect('threat_new', Callable(self, 'on_threat_new'))
|
||||
threats.connect('threat_lost', Callable(self, 'on_threat_lost'))
|
||||
threats.connect('threats_resized', Callable(self, 'on_threats_resized'))
|
||||
threats.connect('threat_update', Callable(self, 'on_threat_update'))
|
||||
signaller.connect('zoom_complete', Callable(self, '_on_zoom_complete'))
|
||||
signaller.connect('rto_threat_sel', Callable(self, 'on_rto_threat_sel').bind(nodes))
|
||||
signaller.connect('bip_pressed', Callable(self, 'on_bip_pressed').bind(nodes))
|
||||
signaller.connect('rto_threat_unsel', Callable(self, 'on_rto_threat_unsel').bind(nodes))
|
||||
signaller.connect('threat_selected', Callable(self, 'on_threat_selected').bind(nodes))
|
||||
signaller.connect('interfer_selected', Callable(self, 'on_interfer_selected').bind(nodes))
|
||||
signaller.connect('interfer_new', Callable(self, 'on_interfer_new'))
|
||||
signaller.connect('interfer_off_all', Callable(self, 'on_interfer_off_all'))
|
||||
signaller.connect('fs_selected', Callable(self, 'on_fs_selected'))
|
||||
interfer.connect('interfer_update', Callable(self, 'on_interfer_new'))
|
||||
min_zoom = ProjectSettings.get_setting('application/config/map_minimum_zoom', 5)
|
||||
max_zoom = ProjectSettings.get_setting('application/config/map_maximum_zoom', 19)
|
||||
drag_fsm = DragFSM.OFF
|
||||
$btn_zoom.set_meta('zoom', min_zoom - 1)
|
||||
var btns_select: Array = $btns_select.get_children()
|
||||
btns_select.any(func(btn): btn.button_connect('pressed', Callable(self, 'on_button_select').bind(btn, btns_select)))
|
||||
$btn_view.button_connect('toggled', Callable(self, 'on_button_view_toggled'))
|
||||
var nodes: Array = get_tree().get_nodes_in_group('группа-режим-помехи')
|
||||
nodes.any(func(btn): btn.button_connect('pressed', Callable(self, 'on_button_pressed').bind(btn, nodes)))
|
||||
threats.connect('threat_new', Callable(self, 'on_threat_new'))
|
||||
threats.connect('threat_lost', Callable(self, 'on_threat_lost'))
|
||||
threats.connect('threats_resized', Callable(self, 'on_threats_resized'))
|
||||
threats.connect('threat_update', Callable(self, 'on_threat_update'))
|
||||
signaller.connect('zoom_complete', Callable(self, '_on_zoom_complete'))
|
||||
signaller.connect('rto_threat_sel', Callable(self, 'on_rto_threat_sel').bind(nodes))
|
||||
signaller.connect('bip_pressed', Callable(self, 'on_bip_pressed').bind(nodes))
|
||||
signaller.connect('rto_threat_unsel', Callable(self, 'on_rto_threat_unsel').bind(nodes))
|
||||
signaller.connect('threat_selected', Callable(self, 'on_threat_selected').bind(nodes))
|
||||
signaller.connect('interfer_selected', Callable(self, 'on_interfer_selected').bind(nodes))
|
||||
signaller.connect('interfer_new', Callable(self, 'on_interfer_new'))
|
||||
signaller.connect('interfer_off_all', Callable(self, 'on_interfer_off_all'))
|
||||
signaller.connect('fs_selected', Callable(self, 'on_fs_selected'))
|
||||
interfer.connect('interfer_update', Callable(self, 'on_interfer_new'))
|
||||
var items_list = []
|
||||
recurse(get_tree().get_root(), items_list)
|
||||
print_debug(items_list)
|
||||
|
||||
func recurse(obj, items_list: Array):
|
||||
var childrens = obj.get_children()
|
||||
for ch in childrens:
|
||||
items_list.append(ch)
|
||||
recurse(ch, items_list)
|
||||
|
||||
func get_all_nodes(root):
|
||||
var nodes = []
|
||||
nodes.append(root)
|
||||
for child in root.get_children():
|
||||
nodes.append_array(get_all_nodes(child))
|
||||
return nodes
|
||||
|
||||
func on_enter_tree() -> void:
|
||||
call_deferred('_on_btn_scale_pressed')
|
||||
call_deferred('on_button_strobe_pressed')
|
||||
$tilemap.position = $canvas.get_strob_center()
|
||||
call_deferred('_on_btn_scale_pressed')
|
||||
call_deferred('on_button_strobe_pressed')
|
||||
$tilemap.position = $canvas.get_strob_center()
|
||||
|
||||
|
||||
## Производит отображение цели на диаграмму
|
||||
## Производит отображение цели на диаграмму.
|
||||
func map_threat_to_bip(th: threats.Threat, bip: Control):
|
||||
bip.position = tools.pos_calc(
|
||||
th.freq,
|
||||
th.aoa,
|
||||
radius_center,
|
||||
radius_internal,
|
||||
radius_outter,
|
||||
freq_low,
|
||||
freq_high) - bip.size / 2
|
||||
bip.position = tools.pos_calc(
|
||||
th.freq,
|
||||
th.aoa,
|
||||
radius_center,
|
||||
radius_internal,
|
||||
radius_outter,
|
||||
freq_low,
|
||||
freq_high) - bip.size / 2
|
||||
|
||||
|
||||
## Обработчик сигнала обновления цели
|
||||
## Обработчик сигнала обновления цели.
|
||||
func on_threat_update(th):
|
||||
var bip = get_node('%d' % th.id)
|
||||
map_threat_to_bip(th, bip)
|
||||
var bip = get_node('%d' % th.id)
|
||||
map_threat_to_bip(th, bip)
|
||||
|
||||
|
||||
## Обработчик выбора помехи для цели
|
||||
## Обработчик выбора помехи для цели.
|
||||
func on_interfer_new(ecm):
|
||||
if interfer.thrs.has(ecm.ispp):
|
||||
if interfer.thrs.has(ecm.ispp):
|
||||
var th_id = interfer.thrs[ecm.ispp]
|
||||
var bip = get_node('%d' % th_id)
|
||||
if ecm.krp != interfer.INTERFER_OFF:
|
||||
bip.set_track_visible(true)
|
||||
if ecm.svk == 1:
|
||||
bip.set_ecm_visible(true)
|
||||
else: bip.set_ecm_visible(false)
|
||||
else:
|
||||
bip.set_ecm_visible(false)
|
||||
bip.set_track_visible(false)
|
||||
set_fs_color(ecm)
|
||||
if interfer.thrs.has(ecm.ispp):
|
||||
if interfer.thrs.has(ecm.ispp):
|
||||
var th_id = interfer.thrs[ecm.ispp]
|
||||
var bip = get_node('%d' % th_id)
|
||||
if ecm.krp != interfer.INTERFER_OFF:
|
||||
bip.set_track_visible(true)
|
||||
if ecm.svk == 1:
|
||||
bip.set_ecm_visible(true)
|
||||
else: bip.set_ecm_visible(false)
|
||||
else:
|
||||
bip.set_ecm_visible(false)
|
||||
bip.set_track_visible(false)
|
||||
set_fs_color(ecm)
|
||||
|
||||
|
||||
## Обработчик выключения всех помех
|
||||
## Обработчик выключения всех помех.
|
||||
func on_interfer_off_all():
|
||||
var bips: Array = get_children().filter(func(item): return item.name.is_valid_int())
|
||||
for bip in bips:
|
||||
bip.set_ecm_visible(false)
|
||||
bip.set_track_visible(false)
|
||||
fs_active.clear()
|
||||
update_fs_colors()
|
||||
var bips: Array = get_children().filter(func(item): return item.name.is_valid_int())
|
||||
for bip in bips:
|
||||
bip.set_ecm_visible(false)
|
||||
bip.set_track_visible(false)
|
||||
fs_active.clear()
|
||||
update_fs_colors()
|
||||
|
||||
|
||||
## Обработчик сигнала обнаружения цели
|
||||
## Обработчик сигнала обнаружения цели.
|
||||
func on_threat_new(th) -> void:
|
||||
var bip = Bip.instantiate()
|
||||
bip.name = '%d' % th.id
|
||||
map_threat_to_bip(th, bip)
|
||||
add_child(bip)
|
||||
var bip = Bip.instantiate()
|
||||
bip.name = '%d' % th.id
|
||||
map_threat_to_bip(th, bip)
|
||||
add_child(bip)
|
||||
|
||||
|
||||
## Обработчик сигнала потери цели
|
||||
## Обработчик сигнала потери цели.
|
||||
func on_threat_lost(th) -> void:
|
||||
var bip = get_node('%d' % th.id)
|
||||
remove_child(bip)
|
||||
bip.free()
|
||||
var bip = get_node('%d' % th.id)
|
||||
remove_child(bip)
|
||||
bip.free()
|
||||
|
||||
|
||||
## обработчик нажатия на цель на экране
|
||||
## обработчик нажатия на цель на экране.
|
||||
func on_bip_pressed(th_id, _ecm_btns):
|
||||
if btn_select == BtnSel.THREAT:
|
||||
signaller.emit_signal('rto_threat_sel', th_id)
|
||||
if btn_select == BtnSel.THREAT:
|
||||
signaller.emit_signal('rto_threat_sel', th_id)
|
||||
|
||||
|
||||
## Обработчик выбора РТО цели
|
||||
## Обработчик выбора РТО цели.
|
||||
func on_rto_threat_sel(th_id, ecm_btns):
|
||||
var bips: Array = get_children().filter(func(item): return item.name.is_valid_int())
|
||||
for item in bips:
|
||||
if th_id == item.name.to_int():
|
||||
item.set_sel_visible(true)
|
||||
unsel_fs_all(false)
|
||||
else:
|
||||
item.set_sel_visible(false)
|
||||
for btn in ecm_btns:
|
||||
set_btns_disabled(false, btn)
|
||||
var bips: Array = get_children().filter(func(item): return item.name.is_valid_int())
|
||||
for item in bips:
|
||||
if th_id == item.name.to_int():
|
||||
item.set_sel_visible(true)
|
||||
unsel_fs_all(false)
|
||||
else:
|
||||
item.set_sel_visible(false)
|
||||
for btn in ecm_btns:
|
||||
set_btns_disabled(false, btn)
|
||||
|
||||
|
||||
## Обработчик снятия выбора РТО цели
|
||||
## Обработчик снятия выбора РТО цели.
|
||||
func on_rto_threat_unsel(th_id, _ecm_btns):
|
||||
var bips: Array = get_children().filter(func(item): return item.name.is_valid_int())
|
||||
for item in bips:
|
||||
if th_id == item.name.to_int():
|
||||
item.set_sel_visible(false)
|
||||
break
|
||||
set_ecm_btns_state(true)
|
||||
var bips: Array = get_children().filter(func(item): return item.name.is_valid_int())
|
||||
for item in bips:
|
||||
if th_id == item.name.to_int():
|
||||
item.set_sel_visible(false)
|
||||
break
|
||||
set_ecm_btns_state(true)
|
||||
|
||||
|
||||
## Обработчик нажатия кнопки "Строб". Управляет отображением строба
|
||||
## Обработчик нажатия кнопки "Строб". Управляет отображением строба.
|
||||
func on_button_strobe_pressed() -> void:
|
||||
drag_fsm = DragFSM.IDLE if $btns_select/btn_strob.is_pressed() else DragFSM.OFF
|
||||
$canvas.set_strob_visible(drag_fsm == DragFSM.IDLE)
|
||||
drag_fsm = DragFSM.IDLE if $btns_select/btn_strob.is_pressed() else DragFSM.OFF
|
||||
$canvas.set_strob_visible(drag_fsm == DragFSM.IDLE)
|
||||
|
||||
|
||||
## Поведение радиокнопок в группе. Управляет состоянием кнопок выбора целей
|
||||
## Поведение радиокнопок в группе. Управляет состоянием кнопок выбора целей.
|
||||
func on_button_select(btn_this, btn_others) -> void:
|
||||
for btn_other in btn_others: btn_other.set_pressed(btn_this == btn_other)
|
||||
btn_select = btn_this.get_meta('state')
|
||||
on_button_strobe_pressed()
|
||||
signaller.emit_signal('rto_threat_unsel_all')
|
||||
unsel_fs_all(true)
|
||||
set_ecm_btns_state(true)
|
||||
for btn_other in btn_others: btn_other.set_pressed(btn_this == btn_other)
|
||||
btn_select = btn_this.get_meta('state')
|
||||
on_button_strobe_pressed()
|
||||
signaller.emit_signal('rto_threat_unsel_all')
|
||||
unsel_fs_all(true)
|
||||
set_ecm_btns_state(true)
|
||||
|
||||
|
||||
## Поведение радиокнопок в группе. Управляет состоянием кнопок в радиогруппе
|
||||
## Поведение радиокнопок в группе. Управляет состоянием кнопок в радиогруппе.
|
||||
func on_button_pressed(btn_this, btn_others) -> void:
|
||||
var fs_arr: Array = []
|
||||
for btn_other in btn_others: btn_other.set_pressed(btn_this == btn_other)
|
||||
for key in fs_selected.keys():
|
||||
fs_arr.append(get_fs_param(key))
|
||||
signaller.emit_signal('interfer_init', btn_this, fs_arr)
|
||||
var fs_arr: Array = []
|
||||
for btn_other in btn_others: btn_other.set_pressed(btn_this == btn_other)
|
||||
for key in fs_selected.keys():
|
||||
fs_arr.append(get_fs_param(key))
|
||||
signaller.emit_signal('interfer_init', btn_this, fs_arr)
|
||||
|
||||
|
||||
## Управляет состоянием кнопок в радиогруппе при выборе помехи
|
||||
## Управляет состоянием кнопок в радиогруппе при выборе помехи.
|
||||
func on_interfer_selected(ecm, btns) -> void:
|
||||
var ecm_name: String
|
||||
if ecm != null:
|
||||
ecm_name = ecm.krp
|
||||
else:
|
||||
ecm_name = interfer.INTERFER_OFF
|
||||
for btn in btns:
|
||||
set_btns_disabled(false, btn)
|
||||
btn.get_meta('rfi_name')
|
||||
if ecm_name == btn.get_meta('rfi_name'):
|
||||
btn.set_pressed(true)
|
||||
else:
|
||||
btn.set_pressed(false)
|
||||
var ecm_name: String
|
||||
if ecm != null:
|
||||
ecm_name = ecm.krp
|
||||
else:
|
||||
ecm_name = interfer.INTERFER_OFF
|
||||
for btn in btns:
|
||||
set_btns_disabled(false, btn)
|
||||
btn.get_meta('rfi_name')
|
||||
if ecm_name == btn.get_meta('rfi_name'):
|
||||
btn.set_pressed(true)
|
||||
else:
|
||||
btn.set_pressed(false)
|
||||
|
||||
|
||||
## Возвращает ширину строба по направлению
|
||||
## Возвращает ширину строба по направлению.
|
||||
func get_strob_width(pos: Vector2, prev: float) -> float:
|
||||
var strob_dir_width: float = prev + (drag_pos_begin.y - pos.y) * drag_scale_width
|
||||
strob_dir_width = tools.clip_value(strob_dir_width, strob_min_width, strob_max_width)
|
||||
return strob_dir_width
|
||||
var strob_dir_width: float = prev + (drag_pos_begin.y - pos.y) * drag_scale_width
|
||||
strob_dir_width = tools.clip_value(strob_dir_width, strob_min_width, strob_max_width)
|
||||
return strob_dir_width
|
||||
|
||||
|
||||
## Возвращает ширину строба по частоте
|
||||
## Возвращает ширину строба по частоте.
|
||||
func get_strob_band(pos: Vector2, prev: float) -> float:
|
||||
var strob_dir_band: float = prev - (drag_pos_begin.y - pos.y) * drag_scale_band
|
||||
strob_dir_band = tools.clip_value(strob_dir_band, strob_min_band, strob_max_band)
|
||||
return strob_dir_band
|
||||
var strob_dir_band: float = prev - (drag_pos_begin.y - pos.y) * drag_scale_band
|
||||
strob_dir_band = tools.clip_value(strob_dir_band, strob_min_band, strob_max_band)
|
||||
return strob_dir_band
|
||||
|
||||
|
||||
## Устанавливает центр строба по частоте и направлению
|
||||
## Устанавливает центр строба по частоте и направлению.
|
||||
func set_strob(pos: Vector2) -> void:
|
||||
var radp: Vector2 = tools.map_dec_to_rad(radius_center, pos)
|
||||
if radp.y < $canvas.get_radius_outter():
|
||||
$canvas.set_strob_dir(radp.x)
|
||||
$canvas.set_strob_radius(radp.y)
|
||||
var radp: Vector2 = tools.map_dec_to_rad(radius_center, pos)
|
||||
if radp.y < $canvas.get_radius_outter():
|
||||
$canvas.set_strob_dir(radp.x)
|
||||
$canvas.set_strob_radius(radp.y)
|
||||
|
||||
|
||||
## Обработка движения мыши для управления стробом. Вызывается во время движения мыши
|
||||
## Обработка движения мыши для управления стробом. Вызывается во время движения мыши.
|
||||
func _on_drag_continue(event) -> void:
|
||||
if drag_button == MOUSE_BUTTON_RIGHT:
|
||||
if shift_pressed:
|
||||
var strob_width: float = get_strob_width(event.position, strob_width_begin)
|
||||
$canvas.set_strob_width(strob_width)
|
||||
else:
|
||||
var strob_band: float = get_strob_band(event.position, strob_band_begin)
|
||||
$canvas.set_strob_band(strob_band)
|
||||
elif drag_button == MOUSE_BUTTON_LEFT:
|
||||
set_strob(event.position)
|
||||
if drag_button == MOUSE_BUTTON_RIGHT:
|
||||
if shift_pressed:
|
||||
var strob_width: float = get_strob_width(event.position, strob_width_begin)
|
||||
$canvas.set_strob_width(strob_width)
|
||||
else:
|
||||
var strob_band: float = get_strob_band(event.position, strob_band_begin)
|
||||
$canvas.set_strob_band(strob_band)
|
||||
elif drag_button == MOUSE_BUTTON_LEFT:
|
||||
set_strob(event.position)
|
||||
|
||||
|
||||
## Обработка движения мыши для управления стробом. Вызывается при нажатии мыши
|
||||
## Обработка движения мыши для управления стробом. Вызывается при нажатии мыши.
|
||||
func _on_drag_begin(event) -> void:
|
||||
drag_pos_begin = event.position
|
||||
if drag_button == MOUSE_BUTTON_LEFT:
|
||||
set_strob(event.position)
|
||||
elif drag_button == MOUSE_BUTTON_RIGHT:
|
||||
strob_width_begin = $canvas.get_strob_width()
|
||||
strob_band_begin = $canvas.get_strob_band()
|
||||
drag_pos_begin = event.position
|
||||
if drag_button == MOUSE_BUTTON_LEFT:
|
||||
set_strob(event.position)
|
||||
elif drag_button == MOUSE_BUTTON_RIGHT:
|
||||
strob_width_begin = $canvas.get_strob_width()
|
||||
strob_band_begin = $canvas.get_strob_band()
|
||||
|
||||
|
||||
## Обработчик событий ввода. Вызывается godot
|
||||
## Обработчик событий ввода. Вызывается godot.
|
||||
func _input(event) -> void:
|
||||
if not is_visible_in_tree(): return
|
||||
if event is InputEventMouseMotion:
|
||||
if drag_fsm == DragFSM.DRAG:
|
||||
emit_signal('drag_continue', event)
|
||||
elif event is InputEventMouseButton:
|
||||
drag_button = event.button_index
|
||||
if event.pressed:
|
||||
if drag_fsm == DragFSM.IDLE:
|
||||
drag_fsm = DragFSM.DRAG
|
||||
emit_signal('drag_begin', event)
|
||||
else:
|
||||
if btn_select == BtnSel.FS:
|
||||
sel_fs_sector(event)
|
||||
drag_fsm = DragFSM.IDLE
|
||||
emit_signal('drag_end', event)
|
||||
if not is_visible_in_tree(): return
|
||||
if event is InputEventMouseMotion:
|
||||
if drag_fsm == DragFSM.DRAG:
|
||||
emit_signal('drag_continue', event)
|
||||
elif event is InputEventMouseButton:
|
||||
drag_button = event.button_index
|
||||
if event.pressed:
|
||||
if drag_fsm == DragFSM.IDLE:
|
||||
drag_fsm = DragFSM.DRAG
|
||||
emit_signal('drag_begin', event)
|
||||
else:
|
||||
if btn_select == BtnSel.FS:
|
||||
sel_fs_sector(event)
|
||||
drag_fsm = DragFSM.IDLE
|
||||
emit_signal('drag_end', event)
|
||||
|
||||
elif event is InputEventKey:
|
||||
if event.physical_keycode == KEY_SHIFT:
|
||||
shift_pressed = event.pressed
|
||||
elif event is InputEventKey:
|
||||
if event.physical_keycode == KEY_SHIFT:
|
||||
shift_pressed = event.pressed
|
||||
|
||||
|
||||
## Вызывается по нажатию кнопки "Детализация"
|
||||
## Вызывается по нажатию кнопки "Детализация".
|
||||
func _on_btn_scale_pressed() -> void:
|
||||
var zoom = $btn_zoom.get_meta('zoom')
|
||||
zoom = zoom + 1 if zoom < max_zoom else min_zoom
|
||||
signaller.emit_signal('zoom_changed', zoom)
|
||||
var zoom = $btn_zoom.get_meta('zoom')
|
||||
zoom = zoom + 1 if zoom < max_zoom else min_zoom
|
||||
signaller.emit_signal('zoom_changed', zoom)
|
||||
|
||||
|
||||
## Вызывается по завершению изменения детализации карты
|
||||
## Вызывается по завершению изменения детализации карты.
|
||||
func _on_zoom_complete(zoom: int) -> void:
|
||||
var prefix = $btn_zoom.get_meta('prefix')
|
||||
$btn_zoom/lbl.text = '%s %d' % [prefix, zoom]
|
||||
$btn_zoom.set_meta('zoom', zoom)
|
||||
var prefix = $btn_zoom.get_meta('prefix')
|
||||
$btn_zoom/lbl.text = '%s %d' % [prefix, zoom]
|
||||
$btn_zoom.set_meta('zoom', zoom)
|
||||
|
||||
|
||||
# Обработчик нажатия по сектору формирователя сигналов
|
||||
## Обработчик нажатия по сектору формирователя сигналов.
|
||||
func sel_fs_sector(event):
|
||||
if (event.button_index == MOUSE_BUTTON_LEFT) or (event.button_index == MOUSE_BUTTON_RIGHT):
|
||||
var center: Vector2 = $tilemap.position
|
||||
var center_offset: Vector2 = ProjectSettings.get_setting('application/interfer/center_offset', Vector2i(0, 25))
|
||||
var angle: float = event.position.angle_to_point(center + center_offset) * 180/PI - 45.0
|
||||
if angle < 0:
|
||||
angle += 360
|
||||
var distance: float = event.position.distance_to(center + center_offset)
|
||||
var sector: int
|
||||
var band: int
|
||||
var has_band: bool = false
|
||||
for sec in fs_sectors.values():
|
||||
if angle >= sec[0] and angle <= sec[1]:
|
||||
sector = fs_sectors.find_key(sec)
|
||||
for diap in fs_band.values():
|
||||
if distance >= diap[0] and distance <= diap[1]:
|
||||
band = fs_band.find_key(diap)
|
||||
has_band = true
|
||||
if not has_band:
|
||||
return
|
||||
var fs_index = band * 4 + sector
|
||||
if event.button_index == MOUSE_BUTTON_LEFT:
|
||||
fs_selected[fs_index] = null
|
||||
else:
|
||||
fs_selected.erase(fs_index)
|
||||
update_fs_colors()
|
||||
signaller.emit_signal('rto_threat_unsel_all')
|
||||
var btn_state = len(fs_selected) == 0
|
||||
set_ecm_btns_state(btn_state)
|
||||
if (event.button_index == MOUSE_BUTTON_LEFT) or (event.button_index == MOUSE_BUTTON_RIGHT):
|
||||
var center: Vector2 = $tilemap.position
|
||||
var center_offset: Vector2 = ProjectSettings.get_setting('application/interfer/center_offset', Vector2i(0, 25))
|
||||
var angle: float = event.position.angle_to_point(center + center_offset) * 180/PI - 45.0
|
||||
if angle < 0:
|
||||
angle += 360
|
||||
var distance: float = event.position.distance_to(center + center_offset)
|
||||
var sector: int
|
||||
var band: int
|
||||
var has_band: bool = false
|
||||
for sec in fs_sectors.values():
|
||||
if angle >= sec[0] and angle <= sec[1]:
|
||||
sector = fs_sectors.find_key(sec)
|
||||
for diap in fs_band.values():
|
||||
if distance >= diap[0] and distance <= diap[1]:
|
||||
band = fs_band.find_key(diap)
|
||||
has_band = true
|
||||
if not has_band:
|
||||
return
|
||||
var fs_index = band * 4 + sector
|
||||
if event.button_index == MOUSE_BUTTON_LEFT:
|
||||
fs_selected[fs_index] = null
|
||||
else:
|
||||
fs_selected.erase(fs_index)
|
||||
update_fs_colors()
|
||||
signaller.emit_signal('rto_threat_unsel_all')
|
||||
var btn_state = len(fs_selected) == 0
|
||||
set_ecm_btns_state(btn_state)
|
||||
|
||||
|
||||
func set_fs_color(ecm):
|
||||
var fs_index = get_fs_index(ecm)
|
||||
if ecm.krp != interfer.INTERFER_OFF:
|
||||
fs_active[fs_index] = null
|
||||
else:
|
||||
fs_active.erase(fs_index)
|
||||
update_fs_colors()
|
||||
var fs_index = get_fs_index(ecm)
|
||||
if ecm.krp != interfer.INTERFER_OFF:
|
||||
fs_active[fs_index] = null
|
||||
else:
|
||||
fs_active.erase(fs_index)
|
||||
update_fs_colors()
|
||||
|
||||
|
||||
func update_fs_colors():
|
||||
var fs_colors = $canvas.fs_default_colors.duplicate()
|
||||
var color_ecm: Vector3 = ProjectSettings.get_setting('application/interfer/interfer_color', Vector3(0.58, 0.47, 0.51))
|
||||
var color_select: Vector3 = ProjectSettings.get_setting('application/interfer/select_color', Vector3(1.0, 1.0, 1.0))
|
||||
for key in fs_active.keys():
|
||||
fs_colors[key] = color_ecm
|
||||
for key in fs_selected.keys():
|
||||
fs_colors[key] = color_select
|
||||
$canvas.set_band_colors(fs_colors)
|
||||
var fs_colors = $canvas.fs_default_colors.duplicate()
|
||||
var color_ecm: Vector3 = ProjectSettings.get_setting('application/interfer/interfer_color', Vector3(0.58, 0.47, 0.51))
|
||||
var color_select: Vector3 = ProjectSettings.get_setting('application/interfer/select_color', Vector3(1.0, 1.0, 1.0))
|
||||
for key in fs_active.keys():
|
||||
fs_colors[key] = color_ecm
|
||||
for key in fs_selected.keys():
|
||||
fs_colors[key] = color_select
|
||||
$canvas.set_band_colors(fs_colors)
|
||||
|
||||
|
||||
func unsel_fs_all(need_btns_off: bool):
|
||||
fs_selected.clear()
|
||||
update_fs_colors()
|
||||
if need_btns_off:
|
||||
set_ecm_btns_state(true)
|
||||
fs_selected.clear()
|
||||
update_fs_colors()
|
||||
if need_btns_off:
|
||||
set_ecm_btns_state(true)
|
||||
|
||||
|
||||
func set_ecm_btns_state(value: bool):
|
||||
var btns: Array = get_tree().get_nodes_in_group('группа-режим-помехи')
|
||||
for btn in btns:
|
||||
btn.set_pressed(false)
|
||||
set_btns_disabled(value, btn)
|
||||
var btns: Array = get_tree().get_nodes_in_group('группа-режим-помехи')
|
||||
for btn in btns:
|
||||
btn.set_pressed(false)
|
||||
set_btns_disabled(value, btn)
|
||||
|
||||
|
||||
func get_fs_param(index: int) -> Array:
|
||||
var freq = (fs_freq[index / 4][0] + fs_freq[index / 4][1])/2
|
||||
var sector = (fs_sectors[index % 4][0] + fs_sectors[index % 4][1])/2 - 45.0
|
||||
if sector < 0:
|
||||
sector += 360.0
|
||||
var width = fs_freq[index / 4][1] - fs_freq[index / 4][0]
|
||||
return [sector, freq, width, index]
|
||||
var freq = (fs_freq[index / 4][0] + fs_freq[index / 4][1])/2
|
||||
var sector = (fs_sectors[index % 4][0] + fs_sectors[index % 4][1])/2 - 45.0
|
||||
if sector < 0:
|
||||
sector += 360.0
|
||||
var width = fs_freq[index / 4][1] - fs_freq[index / 4][0]
|
||||
return [sector, freq, width, index]
|
||||
|
||||
|
||||
func on_fs_selected(ecm):
|
||||
var fs_index = get_fs_index(ecm)
|
||||
fs_selected.clear()
|
||||
fs_selected[fs_index] = null
|
||||
update_fs_colors()
|
||||
var fs_index = get_fs_index(ecm)
|
||||
fs_selected.clear()
|
||||
fs_selected[fs_index] = null
|
||||
update_fs_colors()
|
||||
|
||||
|
||||
func get_fs_index(ecm):
|
||||
var sector: int
|
||||
var band: int
|
||||
var angle: float = ecm.kni + 45.0
|
||||
if angle > 360.0:
|
||||
angle -= 360.0
|
||||
for sec in fs_sectors.values():
|
||||
if float(angle) >= sec[0] and float(angle) <= sec[1]:
|
||||
sector = fs_sectors.find_key(sec)
|
||||
for diap in fs_freq.values():
|
||||
if ecm.params.has('freq'):
|
||||
if ecm.params['freq'] >= diap[0] and ecm.params['freq'] <= diap[1]:
|
||||
band = fs_freq.find_key(diap)
|
||||
var fs_index = band * 4 + sector
|
||||
return fs_index
|
||||
var sector: int
|
||||
var band: int
|
||||
var angle: float = ecm.kni + 45.0
|
||||
if angle > 360.0:
|
||||
angle -= 360.0
|
||||
for sec in fs_sectors.values():
|
||||
if float(angle) >= sec[0] and float(angle) <= sec[1]:
|
||||
sector = fs_sectors.find_key(sec)
|
||||
for diap in fs_freq.values():
|
||||
if ecm.params.has('freq'):
|
||||
if ecm.params['freq'] >= diap[0] and ecm.params['freq'] <= diap[1]:
|
||||
band = fs_freq.find_key(diap)
|
||||
var fs_index = band * 4 + sector
|
||||
return fs_index
|
||||
|
||||
|
||||
func set_btns_disabled(value: bool, btn):
|
||||
var external_cu = ProjectSettings.get_setting('application/config/external_cu', false)
|
||||
if external_cu:
|
||||
btn.set_pressed(false)
|
||||
btn.set_disabled(true)
|
||||
else:
|
||||
btn.set_disabled(value)
|
||||
var external_cu = ProjectSettings.get_setting('application/config/external_cu', false)
|
||||
if external_cu:
|
||||
btn.set_pressed(false)
|
||||
btn.set_disabled(true)
|
||||
else:
|
||||
btn.set_disabled(value)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=14 format=3 uid="uid://b276iygic5itk"]
|
||||
[gd_scene load_steps=15 format=3 uid="uid://b276iygic5itk"]
|
||||
|
||||
[ext_resource type="Script" path="res://scenes/работа/работа.gd" id="1_niok4"]
|
||||
[ext_resource type="PackedScene" uid="uid://nl1vklubr5kr" path="res://scenes/bip/bip.tscn" id="2_br3s6"]
|
||||
@@ -18,6 +18,8 @@ resource_local_to_scene = true
|
||||
shader = ExtResource("11_ekapd")
|
||||
shader_parameter/radius = 0.39
|
||||
|
||||
[sub_resource type="ImageTexture" id="ImageTexture_cnmvt"]
|
||||
|
||||
[node name="Работа" type="Panel"]
|
||||
script = ExtResource("1_niok4")
|
||||
Bip = ExtResource("2_br3s6")
|
||||
@@ -120,6 +122,33 @@ size_flags_vertical = 3
|
||||
text = "Подавление"
|
||||
toggle_mode = true
|
||||
|
||||
[node name="bt_navig_u" type="TextureButton" parent="."]
|
||||
layout_mode = 0
|
||||
offset_left = 530.0
|
||||
offset_top = 428.0
|
||||
offset_right = 570.0
|
||||
offset_bottom = 468.0
|
||||
|
||||
[node name="bt_navig_l" type="TextureButton" parent="."]
|
||||
layout_mode = 0
|
||||
offset_left = 410.0
|
||||
offset_top = 532.0
|
||||
offset_right = 460.0
|
||||
offset_bottom = 581.0
|
||||
texture_normal = SubResource("ImageTexture_cnmvt")
|
||||
|
||||
[node name="bt_navig_r" type="TextureButton" parent="."]
|
||||
layout_mode = 0
|
||||
offset_left = 651.0
|
||||
offset_top = 540.0
|
||||
offset_right = 691.0
|
||||
offset_bottom = 580.0
|
||||
|
||||
[node name="bt_navig_d" type="TextureButton" parent="."]
|
||||
layout_mode = 0
|
||||
offset_right = 40.0
|
||||
offset_bottom = 40.0
|
||||
|
||||
[node name="btn_zoom" parent="." instance=ExtResource("9_oey3x")]
|
||||
layout_mode = 0
|
||||
offset_left = 12.0
|
||||
|
||||
@@ -4,28 +4,28 @@ extends PanelContainer
|
||||
|
||||
|
||||
@export var texture_state0: Texture2D = preload('res://data/кнопка-эмс-1.png'):
|
||||
set(val): $state.set_texture(val)
|
||||
set(val): $state.set_texture(val)
|
||||
|
||||
|
||||
@export var texture_state1: Texture2D = preload('res://data/кнопка-эмс-0.png'):
|
||||
set(val): $state.set_texture(val)
|
||||
set(val): $state.set_texture(val)
|
||||
|
||||
|
||||
@export var text: String = '':
|
||||
set(val): $button.set_text(val)
|
||||
get: return $button.get_text()
|
||||
set(val): $button.set_text(val)
|
||||
get: return $button.get_text()
|
||||
|
||||
|
||||
@export var pressed: bool = false:
|
||||
set(val): $button.set_pressed(val)
|
||||
get: return $button.is_pressed()
|
||||
set(val): $button.set_pressed(val)
|
||||
get: return $button.is_pressed()
|
||||
|
||||
|
||||
@export var toggle_mode: bool = false:
|
||||
set(val):
|
||||
if is_inside_tree():
|
||||
$button.set_toggle_mode(val)
|
||||
get: return $button.is_toggle_mode()
|
||||
set(val):
|
||||
if is_inside_tree():
|
||||
$button.set_toggle_mode(val)
|
||||
get: return $button.is_toggle_mode()
|
||||
|
||||
|
||||
func set_text (val: String): $button.set_text(val)
|
||||
@@ -33,8 +33,8 @@ func set_pressed (val: bool): $button.set_pressed(val)
|
||||
|
||||
|
||||
func set_toggle_mode (val: bool):
|
||||
if is_inside_tree():
|
||||
$button.set_toggle_mode(val)
|
||||
if is_inside_tree():
|
||||
$button.set_toggle_mode(val)
|
||||
|
||||
|
||||
func get_text(): return $button.get_text()
|
||||
@@ -43,13 +43,13 @@ func is_toggle_mode(): return $button.is_toggle_mode()
|
||||
|
||||
|
||||
func _on_button_toggled(val: bool):
|
||||
if val: $state.set_texture(texture_state1)
|
||||
else: $state.set_texture(texture_state0)
|
||||
if val: $state.set_texture(texture_state1)
|
||||
else: $state.set_texture(texture_state0)
|
||||
|
||||
|
||||
func button_connect(button_signal: String, proc: Callable):
|
||||
$button.connect(button_signal, proc)
|
||||
$button.connect(button_signal, proc)
|
||||
|
||||
|
||||
func _on_button_mouse_entered():
|
||||
emit_signal("mouse_entered")
|
||||
emit_signal("mouse_entered")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
extends Panel
|
||||
class_name ems extends Panel
|
||||
|
||||
# Предзагрузка ячеек таблиц
|
||||
## Предзагрузка ячеек таблиц.
|
||||
const TableHeader = preload('res://table/header.tscn')
|
||||
const CellYemsButton = preload('res://scenes/эмс/кнопка-эмс.tscn')
|
||||
const CellLineEdit = preload('res://table/ячейка-2.tscn')
|
||||
@@ -10,7 +10,7 @@ const CellLEEmpty = preload('res://scenes/эмс/line-edit-empty.tscn')
|
||||
const CellFront = preload('res://scenes/cell/cell-front.tscn')
|
||||
const CellFrontRear = preload('res://scenes/cell/cell-front-rear.tscn')
|
||||
|
||||
# Режимы работы выходов
|
||||
## Режимы работы выходов.
|
||||
const OUT_MODE: Array = ['Работа', 'Контроль', '1', '0'] #
|
||||
const COLUMN_OPTS_BTN: Array = [5]
|
||||
const TABLE_ENTRY_COLUMNS: Array = [2,3]
|
||||
@@ -18,339 +18,347 @@ const OUT_SET_ROW: Array = [CellLineEdit, CellLEEmpty, CellLEEmpty, CellLEEmpty,
|
||||
const IN_SET_ROW: Array = [CellLineEdit, CellLEEmpty, CellLEEmpty, CellLEEmpty, CellLEEmpty]
|
||||
|
||||
|
||||
var g_boards: Dictionary # Словарь плат ЭМС
|
||||
var posx: int = 125 # Позиция элементов по x
|
||||
var posy: int = 70 # Позиция элементов по y
|
||||
var g_boards: Dictionary ## Словарь плат ЭМС.
|
||||
var posx: int = 125 ## Позиция элементов по x.
|
||||
var posy: int = 70 ## Позиция элементов по y.
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
call_deferred('init_boards')
|
||||
call_deferred('init_boards')
|
||||
|
||||
|
||||
## Инициализация основных элементов экрана ЭМС
|
||||
## Инициализация основных элементов экрана ЭМС.
|
||||
func init_boards():
|
||||
# Выставление позиций элементов ЭМС на экране
|
||||
$scrollin.set_position(Vector2(posx,posy))
|
||||
$scrollout.set_position(Vector2(posx+650,posy))
|
||||
$scrl_in_set.set_position(Vector2(posx,posy + 700))
|
||||
$scrl_out_set.set_position(Vector2(posx+650,posy + 700))
|
||||
$lbl_online.set_position(Vector2(posx,posy-60))
|
||||
$btn_flash_read.set_position(Vector2(posx,posy + 900))
|
||||
$btn_flash_write.set_position(Vector2(posx,posy+ 935))
|
||||
$btn_connect.set_position(Vector2(posx+590,posy-25))
|
||||
$btn_disconnect.set_position(Vector2(posx+587,posy + 675))
|
||||
# Выставление позиций элементов ЭМС на экране
|
||||
$scrollin.set_position(Vector2(posx,posy))
|
||||
$scrollout.set_position(Vector2(posx+650,posy))
|
||||
$scrl_in_set.set_position(Vector2(posx,posy + 700))
|
||||
$scrl_out_set.set_position(Vector2(posx+650,posy + 700))
|
||||
$lbl_online.set_position(Vector2(posx,posy-60))
|
||||
$btn_flash_read.set_position(Vector2(posx,posy + 900))
|
||||
$btn_flash_write.set_position(Vector2(posx,posy+ 935))
|
||||
$btn_connect.set_position(Vector2(posx+590,posy-25))
|
||||
$btn_disconnect.set_position(Vector2(posx+587,posy + 675))
|
||||
|
||||
g_boards['КЭМС'] = yemsboards.EmsBoard.new('КЭМС', 0x130, yemsconsts.INPUT_ROWS, yemsconsts.OUTPUT_ROWS)
|
||||
g_boards['П5-28'] = yemsboards.EmsBoard.new('П5-28', 0x140, yemsconsts.INPUT_ROWS1, yemsconsts.OUTPUT_ROWS1)
|
||||
init_tbl_in()
|
||||
$scrollin/tbl_in.pin_header($scrollin, self)
|
||||
init_tbl_out()
|
||||
$scrollout/tbl_out.pin_header($scrollout, self)
|
||||
$scrl_in_set/tbl_in_set.pin_header($scrl_in_set, self)
|
||||
$scrl_out_set/tbl_out_set.pin_header($scrl_out_set, self)
|
||||
init_tbl_files()
|
||||
$scrl_files/tbl_files.pin_header($scrl_files, self)
|
||||
$btn_connect.connect('pressed', Callable(self, 'on_btn_connect'))
|
||||
$btn_disconnect.connect('pressed', Callable(self, 'on_btn_disconnect'))
|
||||
$btn_flash_read.button_connect('pressed', Callable(self, 'on_btn_flash_read').bind($btn_flash_read))
|
||||
$btn_flash_write.button_connect('pressed', Callable(self, 'on_btn_flash_write').bind($btn_flash_write))
|
||||
g_boards['КЭМС'] = yemsboards.EmsBoard.new('КЭМС', 0x130, yemsconsts.INPUT_ROWS, yemsconsts.OUTPUT_ROWS)
|
||||
g_boards['П5-28'] = yemsboards.EmsBoard.new('П5-28', 0x140, yemsconsts.INPUT_ROWS1, yemsconsts.OUTPUT_ROWS1)
|
||||
init_tbl_in()
|
||||
$scrollin/tbl_in.pin_header($scrollin, self)
|
||||
init_tbl_out()
|
||||
$scrollout/tbl_out.pin_header($scrollout, self)
|
||||
$scrl_in_set/tbl_in_set.pin_header($scrl_in_set, self)
|
||||
$scrl_out_set/tbl_out_set.pin_header($scrl_out_set, self)
|
||||
init_tbl_files()
|
||||
$scrl_files/tbl_files.pin_header($scrl_files, self)
|
||||
$btn_connect.connect('pressed', Callable(self, 'on_btn_connect'))
|
||||
$btn_disconnect.connect('pressed', Callable(self, 'on_btn_disconnect'))
|
||||
$btn_flash_read.button_connect('pressed', Callable(self, 'on_btn_flash_read').bind($btn_flash_read))
|
||||
$btn_flash_write.button_connect('pressed', Callable(self, 'on_btn_flash_write').bind($btn_flash_write))
|
||||
|
||||
|
||||
## Обработчик нажатия кнопки disconnect.
|
||||
func on_btn_disconnect():
|
||||
var selected_rows_in: Array = []
|
||||
var selected_rows_out: Array = []
|
||||
$scrl_in_set/tbl_in_set.get_selected_rows(selected_rows_in)
|
||||
$scrl_out_set/tbl_out_set.get_selected_rows(selected_rows_out)
|
||||
if len(selected_rows_in):
|
||||
on_disconnect($scrl_in_set/tbl_in_set, selected_rows_in, 'вход')
|
||||
elif len(selected_rows_out):
|
||||
on_disconnect($scrl_out_set/tbl_out_set, selected_rows_out, 'выход')
|
||||
var selected_rows_in: Array = []
|
||||
var selected_rows_out: Array = []
|
||||
$scrl_in_set/tbl_in_set.get_selected_rows(selected_rows_in)
|
||||
$scrl_out_set/tbl_out_set.get_selected_rows(selected_rows_out)
|
||||
if len(selected_rows_in):
|
||||
on_disconnect($scrl_in_set/tbl_in_set, selected_rows_in, 'вход')
|
||||
elif len(selected_rows_out):
|
||||
on_disconnect($scrl_out_set/tbl_out_set, selected_rows_out, 'выход')
|
||||
|
||||
|
||||
## Разрывает связь входа и выхода, [param tbl] - таблица, [param selected_rows] - выбранные строки
|
||||
## [param type_dev] - тип, 'вход' или 'выход'
|
||||
## Разрывает связь входа и выхода, [param tbl] - таблица, [param selected_rows] - выбранные строки.
|
||||
## [param type_dev] - тип, 'вход' или 'выход'.
|
||||
func on_disconnect(tbl, selected_rows, type_dev: String):
|
||||
var dev = tbl.get_node_user_data(0, 0)
|
||||
var user_data: Array = tbl.get_node_user_data(0, selected_rows[0])
|
||||
var con_dev = user_data[0]
|
||||
var connector: String = con_dev.connector
|
||||
dev.connect_devs.erase(con_dev.connector)
|
||||
con_dev.connect_devs.erase(dev.connector)
|
||||
if type_dev == 'вход':
|
||||
set_in_dev(dev)
|
||||
set_out_dev(con_dev)
|
||||
elif type_dev == 'выход':
|
||||
set_in_dev(con_dev)
|
||||
set_out_dev(dev)
|
||||
var dev = tbl.get_node_user_data(0, 0)
|
||||
var user_data: Array = tbl.get_node_user_data(0, selected_rows[0])
|
||||
var con_dev = user_data[0]
|
||||
var connector: String = con_dev.connector
|
||||
dev.connect_devs.erase(con_dev.connector)
|
||||
con_dev.connect_devs.erase(dev.connector)
|
||||
if type_dev == 'вход':
|
||||
set_in_dev(dev)
|
||||
set_out_dev(con_dev)
|
||||
elif type_dev == 'выход':
|
||||
set_in_dev(con_dev)
|
||||
set_out_dev(dev)
|
||||
|
||||
|
||||
## Обработчик нажатия кнопки "Прочитать"
|
||||
## Обработчик нажатия кнопки "Прочитать".
|
||||
func on_btn_flash_read(btn):
|
||||
await get_tree().create_timer(0.1).timeout
|
||||
btn.pressed = false
|
||||
await get_tree().create_timer(0.1).timeout
|
||||
btn.pressed = false
|
||||
|
||||
|
||||
## Обработчик нажатия кнопки "Записать"
|
||||
## Обработчик нажатия кнопки "Записать".
|
||||
func on_btn_flash_write(btn):
|
||||
await get_tree().create_timer(0.1).timeout
|
||||
btn.pressed = false
|
||||
await get_tree().create_timer(0.1).timeout
|
||||
btn.pressed = false
|
||||
|
||||
|
||||
## Инициализация таблицы с файлами настроек ЭМС
|
||||
## Инициализация таблицы с файлами настроек ЭМС.
|
||||
func init_tbl_files():
|
||||
$scrl_files/tbl_files.set_header([TableHeader, TableHeader, TableHeader])
|
||||
$scrl_files/tbl_files.set_header_text(['Имя файла', 'Дата изменения', 'Размер'])
|
||||
$scrl_files/tbl_files.set_columns_min_size([200, 120, 70])
|
||||
$scrl_files/tbl_files.set_header([TableHeader, TableHeader, TableHeader])
|
||||
$scrl_files/tbl_files.set_header_text(['Имя файла', 'Дата изменения', 'Размер'])
|
||||
$scrl_files/tbl_files.set_columns_min_size([200, 120, 70])
|
||||
|
||||
|
||||
## Инициализация таблиц входов
|
||||
## Инициализация таблиц входов.
|
||||
func init_tbl_in():
|
||||
# Инициализация основной таблицы входов, в ней отображается информация о параметрах и состоянии
|
||||
var header_type: Array = [TableHeader, TableHeader, CellFront, CellFrontRear, TableHeader]
|
||||
var header_text: Array = ['Входы', 'Соединитель', 'мкс', 'мкс', 'Состояние']
|
||||
var row_type: Array = [CellLineEdit, CellLineEdit, CellLineEdit, CellLineEdit, CellState]
|
||||
var yams_alligment_in: Array = [ HORIZONTAL_ALIGNMENT_LEFT, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER]
|
||||
var column_size: Array = [250, 100, 70, 70, 50]
|
||||
$scrollin/tbl_in.set_header(header_type)
|
||||
$scrollin/tbl_in.set_header_text(header_text)
|
||||
for board in g_boards:
|
||||
for item in g_boards[board].in_tbl:
|
||||
$scrollin/tbl_in.add_row(row_type)
|
||||
var row_index : int = $scrollin/tbl_in.get_rows_count() - 1
|
||||
var params : Array = item[1]
|
||||
var in_dev: yemsdevs.InDev = yemsdevs.InDev.new(item[0], params, row_index)
|
||||
in_dev.board = board
|
||||
for i in range(len(row_type)):
|
||||
if i < len(params):
|
||||
var node = $scrollin/tbl_in.get_node2(i, row_index)
|
||||
node.text = params[i]
|
||||
node.editable = false
|
||||
$scrollin/tbl_in.set_node_user_data(i, row_index, [in_dev, board])
|
||||
$scrollin/tbl_in.set_columns_alignments(yams_alligment_in)
|
||||
$scrollin/tbl_in.set_columns_min_size(column_size)
|
||||
$scrollin/tbl_in.connect('row_pressed', Callable(self, 'on_row_pressed_in'))
|
||||
$scrollin/tbl_in.connect('selected_changed', Callable(self, 'on_selected_changed_in'))
|
||||
# Инициализация основной таблицы входов, в ней отображается информация о параметрах и состоянии
|
||||
var header_type: Array = [TableHeader, TableHeader, CellFront, CellFrontRear, TableHeader]
|
||||
var header_text: Array = ['Входы', 'Соединитель', 'мкс', 'мкс', 'Состояние']
|
||||
var row_type: Array = [CellLineEdit, CellLineEdit, CellLineEdit, CellLineEdit, CellState]
|
||||
var yams_alligment_in: Array = [ HORIZONTAL_ALIGNMENT_LEFT, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER]
|
||||
var column_size: Array = [250, 100, 70, 70, 50]
|
||||
$scrollin/tbl_in.set_header(header_type)
|
||||
$scrollin/tbl_in.set_header_text(header_text)
|
||||
for board in g_boards:
|
||||
for item in g_boards[board].in_tbl:
|
||||
$scrollin/tbl_in.add_row(row_type)
|
||||
var row_index : int = $scrollin/tbl_in.get_rows_count() - 1
|
||||
var params : Array = item[1]
|
||||
var in_dev: yemsdevs.InDev = yemsdevs.InDev.new(item[0], params, row_index)
|
||||
in_dev.board = board
|
||||
for i in range(len(row_type)):
|
||||
if i < len(params):
|
||||
var node = $scrollin/tbl_in.get_node2(i, row_index)
|
||||
node.text = params[i]
|
||||
node.editable = false
|
||||
$scrollin/tbl_in.set_node_user_data(i, row_index, [in_dev, board])
|
||||
$scrollin/tbl_in.set_columns_alignments(yams_alligment_in)
|
||||
$scrollin/tbl_in.set_columns_min_size(column_size)
|
||||
$scrollin/tbl_in.connect('row_pressed', Callable(self, 'on_row_pressed_in'))
|
||||
$scrollin/tbl_in.connect('selected_changed', Callable(self, 'on_selected_changed_in'))
|
||||
|
||||
# Инициализация таблицы изменения параметров входа и списка выходов связанных с ним
|
||||
header_text[0] = 'Вход'
|
||||
$scrl_in_set/tbl_in_set.set_header(header_type)
|
||||
$scrl_in_set/tbl_in_set.set_header_text(header_text)
|
||||
$scrl_in_set/tbl_in_set.set_columns_alignments(yams_alligment_in)
|
||||
$scrl_in_set/tbl_in_set.set_columns_min_size(column_size)
|
||||
$scrl_in_set/tbl_in_set.connect('row_pressed', Callable(self, 'on_row_pressed_si'))
|
||||
$scrl_in_set/tbl_in_set.connect('selected_changed', Callable(self, 'on_selected_changed_si'))
|
||||
# Инициализация таблицы изменения параметров входа и списка выходов связанных с ним
|
||||
header_text[0] = 'Вход'
|
||||
$scrl_in_set/tbl_in_set.set_header(header_type)
|
||||
$scrl_in_set/tbl_in_set.set_header_text(header_text)
|
||||
$scrl_in_set/tbl_in_set.set_columns_alignments(yams_alligment_in)
|
||||
$scrl_in_set/tbl_in_set.set_columns_min_size(column_size)
|
||||
$scrl_in_set/tbl_in_set.connect('row_pressed', Callable(self, 'on_row_pressed_si'))
|
||||
$scrl_in_set/tbl_in_set.connect('selected_changed', Callable(self, 'on_selected_changed_si'))
|
||||
|
||||
|
||||
## Обработчик редактирования Entry в таблице параметров входов/выходов
|
||||
## Обработчик редактирования Entry в таблице параметров входов/выходов.
|
||||
func on_edit_entry(text : String, entry):
|
||||
print_debug(text, entry)
|
||||
print_debug(text, entry)
|
||||
|
||||
|
||||
## Обработчик выбора строки в таблице входов
|
||||
## Обработчик выбора строки в таблице входов.
|
||||
func on_selected_changed_in(i_row: int):
|
||||
var selecter_rows: Array = []
|
||||
$scrollin/tbl_in.get_selected_rows(selecter_rows)
|
||||
var user_data = $scrollin/tbl_in.get_node_user_data(0, i_row)
|
||||
var dev = user_data[0]
|
||||
set_in_dev(dev)
|
||||
var selecter_rows: Array = []
|
||||
$scrollin/tbl_in.get_selected_rows(selecter_rows)
|
||||
var user_data = $scrollin/tbl_in.get_node_user_data(0, i_row)
|
||||
var dev = user_data[0]
|
||||
set_in_dev(dev)
|
||||
|
||||
|
||||
## Обработчик нажатия на таблицу входов
|
||||
## Обработчик нажатия на таблицу входов.
|
||||
func on_row_pressed_in(i_row: int):
|
||||
on_row_pressed(i_row, $scrollin/tbl_in)
|
||||
on_selected_changed_in(i_row)
|
||||
on_row_pressed(i_row, $scrollin/tbl_in)
|
||||
on_selected_changed_in(i_row)
|
||||
|
||||
|
||||
## Выбор входного устройства, для отображения в таблице соединений входа и изменения параметров
|
||||
## Выбор входного устройства, для отображения в таблице соединений входа и изменения параметров.
|
||||
func set_in_dev(dev):
|
||||
var row_type: Array = [CellLineEdit, CellLineEdit, CellLineEdit, CellLineEdit, CellState]
|
||||
set_dev($scrl_in_set/tbl_in_set, dev, row_type, IN_SET_ROW, 'Список соединённых выходов :', [250, 100, 70, 70, 70])
|
||||
var row_type: Array = [CellLineEdit, CellLineEdit, CellLineEdit, CellLineEdit, CellState]
|
||||
set_dev($scrl_in_set/tbl_in_set, dev, row_type, IN_SET_ROW, 'Список соединённых выходов :', [250, 100, 70, 70, 70])
|
||||
|
||||
|
||||
## Обработчик выбора строки в таблице соединений входа и изменения параметров
|
||||
## Обработчик выбора строки в таблице соединений входа и изменения параметров.
|
||||
func on_selected_changed_si(i_row: int):
|
||||
if i_row < 2:
|
||||
return
|
||||
var out_user_data = $scrl_in_set/tbl_in_set.get_node_user_data(0, i_row)
|
||||
var dev = out_user_data[0]
|
||||
var connector = dev.connector
|
||||
for i in range($scrollout/tbl_out.get_rows_count()):
|
||||
var node = $scrollout/tbl_out.get_node2(1, i)
|
||||
if connector == node.text:
|
||||
on_row_pressed_out(i)
|
||||
if i_row < 2:
|
||||
return
|
||||
var out_user_data = $scrl_in_set/tbl_in_set.get_node_user_data(0, i_row)
|
||||
var dev = out_user_data[0]
|
||||
var connector = dev.connector
|
||||
for i in range($scrollout/tbl_out.get_rows_count()):
|
||||
var node = $scrollout/tbl_out.get_node2(1, i)
|
||||
if connector == node.text:
|
||||
on_row_pressed_out(i)
|
||||
|
||||
|
||||
## Обработчик нажатия на таблицу соединений входа и изменения параметров
|
||||
## Обработчик нажатия на таблицу соединений входа и изменения параметров.
|
||||
func on_row_pressed_si(i_row: int):
|
||||
if i_row < 2:
|
||||
return
|
||||
on_row_pressed(i_row, $scrl_in_set/tbl_in_set)
|
||||
on_selected_changed_si(i_row)
|
||||
if i_row < 2:
|
||||
return
|
||||
on_row_pressed(i_row, $scrl_in_set/tbl_in_set)
|
||||
on_selected_changed_si(i_row)
|
||||
|
||||
|
||||
## Инициализация таблиц выходов
|
||||
## Инициализация таблиц выходов.
|
||||
func init_tbl_out():
|
||||
# Инициализация основной таблицы выходов, в ней отображается информация о параметрах и состоянии
|
||||
var header_text = ['Выходы', 'Соединитель', 'мкс', 'мкс', 'Состояние', 'Режим']
|
||||
var yams_alligment_out: Array = [ HORIZONTAL_ALIGNMENT_LEFT, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER]
|
||||
$scrollout/tbl_out.set_header([TableHeader, TableHeader, CellFront, CellFrontRear, TableHeader, TableHeader])
|
||||
$scrollout/tbl_out.set_header_text(header_text)
|
||||
for board in g_boards:
|
||||
for item in g_boards[board].out_tbl:
|
||||
$scrollout/tbl_out.add_row([CellLineEdit, CellLineEdit, CellLineEdit, CellLineEdit, CellState, CellLineEdit])
|
||||
var row_index : int = $scrollout/tbl_out.get_rows_count() - 1
|
||||
var params : Array = item[1]
|
||||
var out_dev = yemsdevs.OutDev.new(item[0], params, row_index)
|
||||
out_dev.board = board
|
||||
for i in range(len(header_text)):
|
||||
var cell = $scrollout/tbl_out.get_node2(i, row_index)
|
||||
if i < len(params):
|
||||
cell.text = params[i]
|
||||
cell.editable = false
|
||||
$scrollout/tbl_out.set_node_user_data(i, row_index, [out_dev, board])
|
||||
if i in COLUMN_OPTS_BTN:
|
||||
cell.text = out_dev.mode
|
||||
$scrollout/tbl_out.set_columns_min_size([250, 100, 70, 70, 70, 100])
|
||||
$scrollout/tbl_out.set_columns_alignments(yams_alligment_out)
|
||||
$scrollout/tbl_out.connect('row_pressed', Callable(self, 'on_row_pressed_out'))
|
||||
$scrollout/tbl_out.connect('selected_changed', Callable(self, 'on_selected_changed_out'))
|
||||
# Инициализация основной таблицы выходов, в ней отображается информация о параметрах и состоянии
|
||||
var header_text = ['Выходы', 'Соединитель', 'мкс', 'мкс', 'Состояние', 'Режим']
|
||||
var yams_alligment_out: Array = [ HORIZONTAL_ALIGNMENT_LEFT, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER]
|
||||
$scrollout/tbl_out.set_header([TableHeader, TableHeader, CellFront, CellFrontRear, TableHeader, TableHeader])
|
||||
$scrollout/tbl_out.set_header_text(header_text)
|
||||
for board in g_boards:
|
||||
for item in g_boards[board].out_tbl:
|
||||
$scrollout/tbl_out.add_row([CellLineEdit, CellLineEdit, CellLineEdit, CellLineEdit, CellState, CellLineEdit])
|
||||
var row_index : int = $scrollout/tbl_out.get_rows_count() - 1
|
||||
var params : Array = item[1]
|
||||
var out_dev = yemsdevs.OutDev.new(item[0], params, row_index)
|
||||
out_dev.board = board
|
||||
for i in range(len(header_text)):
|
||||
var cell = $scrollout/tbl_out.get_node2(i, row_index)
|
||||
if i < len(params):
|
||||
cell.text = params[i]
|
||||
cell.editable = false
|
||||
$scrollout/tbl_out.set_node_user_data(i, row_index, [out_dev, board])
|
||||
if i in COLUMN_OPTS_BTN:
|
||||
cell.text = out_dev.mode
|
||||
$scrollout/tbl_out.set_columns_min_size([250, 100, 70, 70, 70, 100])
|
||||
$scrollout/tbl_out.set_columns_alignments(yams_alligment_out)
|
||||
$scrollout/tbl_out.connect('row_pressed', Callable(self, 'on_row_pressed_out'))
|
||||
$scrollout/tbl_out.connect('selected_changed', Callable(self, 'on_selected_changed_out'))
|
||||
|
||||
# Инициализация таблицы изменения параметров выхода и списка входов связанных с ним
|
||||
header_text[0] = 'Выход'
|
||||
$scrl_out_set/tbl_out_set.set_header([TableHeader, TableHeader, CellFront, CellFrontRear, TableHeader, TableHeader])
|
||||
$scrl_out_set/tbl_out_set.set_header_text(header_text)
|
||||
$scrl_out_set/tbl_out_set.set_columns_min_size([250, 100, 70, 70, 70, 100])
|
||||
$scrl_out_set/tbl_out_set.connect('row_pressed', Callable(self, 'on_row_pressed_so'))
|
||||
$scrl_out_set/tbl_out_set.connect('selected_changed', Callable(self, 'on_selected_changed_so'))
|
||||
# Инициализация таблицы изменения параметров выхода и списка входов связанных с ним
|
||||
header_text[0] = 'Выход'
|
||||
$scrl_out_set/tbl_out_set.set_header([TableHeader, TableHeader, CellFront, CellFrontRear, TableHeader, TableHeader])
|
||||
$scrl_out_set/tbl_out_set.set_header_text(header_text)
|
||||
$scrl_out_set/tbl_out_set.set_columns_min_size([250, 100, 70, 70, 70, 100])
|
||||
$scrl_out_set/tbl_out_set.connect('row_pressed', Callable(self, 'on_row_pressed_so'))
|
||||
$scrl_out_set/tbl_out_set.connect('selected_changed', Callable(self, 'on_selected_changed_so'))
|
||||
|
||||
|
||||
## Обработчик выбора строки в таблице соединений выхода и изменения параметров
|
||||
## Обработчик выбора строки в таблице соединений выхода и изменения параметров.
|
||||
func on_selected_changed_so(i_row: int):
|
||||
if i_row < 2:
|
||||
return
|
||||
var in_user_data = $scrl_out_set/tbl_out_set.get_node_user_data(0, i_row)
|
||||
var dev = in_user_data[0]
|
||||
var connector = dev.connector
|
||||
for i in range($scrollin/tbl_in.get_rows_count()):
|
||||
var node = $scrollin/tbl_in.get_node2(1, i)
|
||||
if connector == node.text:
|
||||
on_row_pressed_in(i)
|
||||
if i_row < 2:
|
||||
return
|
||||
var in_user_data = $scrl_out_set/tbl_out_set.get_node_user_data(0, i_row)
|
||||
var dev = in_user_data[0]
|
||||
var connector = dev.connector
|
||||
for i in range($scrollin/tbl_in.get_rows_count()):
|
||||
var node = $scrollin/tbl_in.get_node2(1, i)
|
||||
if connector == node.text:
|
||||
on_row_pressed_in(i)
|
||||
|
||||
|
||||
## Обработчик нажатия на таблицу соединений выхода и изменения параметров
|
||||
## Обработчик нажатия на таблицу соединений выхода и изменения параметров.
|
||||
func on_row_pressed_so(i_row: int):
|
||||
if i_row < 2:
|
||||
return
|
||||
on_row_pressed(i_row, $scrl_out_set/tbl_out_set)
|
||||
on_selected_changed_so(i_row)
|
||||
if i_row < 2:
|
||||
return
|
||||
on_row_pressed(i_row, $scrl_out_set/tbl_out_set)
|
||||
on_selected_changed_so(i_row)
|
||||
|
||||
|
||||
## Обработчик выбора строки в таблице выходов
|
||||
## Обработчик выбора строки в таблице выходов.
|
||||
func on_selected_changed_out(i_row: int):
|
||||
var selecter_rows: Array = []
|
||||
$scrollout/tbl_out.get_selected_rows(selecter_rows)
|
||||
var user_data = $scrollout/tbl_out.get_node_user_data(0, i_row)
|
||||
var dev = user_data[0]
|
||||
set_out_dev(dev)
|
||||
var selecter_rows: Array = []
|
||||
$scrollout/tbl_out.get_selected_rows(selecter_rows)
|
||||
var user_data = $scrollout/tbl_out.get_node_user_data(0, i_row)
|
||||
var dev = user_data[0]
|
||||
set_out_dev(dev)
|
||||
|
||||
|
||||
## Обработчик выбора строки в таблице выходов
|
||||
## Обработчик выбора строки в таблице выходов.
|
||||
func on_row_pressed_out(i_row: int):
|
||||
on_row_pressed(i_row, $scrollout/tbl_out)
|
||||
on_selected_changed_out(i_row)
|
||||
on_row_pressed(i_row, $scrollout/tbl_out)
|
||||
on_selected_changed_out(i_row)
|
||||
|
||||
|
||||
## Выбор выходного устройства, для отображения в таблице соединений выхода и изменения параметров
|
||||
## Выбор выходного устройства, для отображения в таблице соединений выхода и изменения параметров.
|
||||
func set_out_dev(dev):
|
||||
var row_type: Array = [CellLineEdit, CellLineEdit, CellLineEdit, CellLineEdit, CellState, CellOptBtn]
|
||||
set_dev($scrl_out_set/tbl_out_set, dev, row_type, OUT_SET_ROW, 'Список соединённых входов :', [250, 100, 70, 70, 70, 100])
|
||||
var mode = $scrl_out_set/tbl_out_set.get_node2(5, 0)
|
||||
for opt in OUT_MODE:
|
||||
mode.add_item(opt)
|
||||
var mode_index: int = OUT_MODE.find(dev.mode)
|
||||
if mode_index != -1:
|
||||
mode.select(mode_index)
|
||||
var row_type: Array = [CellLineEdit, CellLineEdit, CellLineEdit, CellLineEdit, CellState, CellOptBtn]
|
||||
set_dev($scrl_out_set/tbl_out_set, dev, row_type, OUT_SET_ROW, 'Список соединённых входов :', [250, 100, 70, 70, 70, 100])
|
||||
var mode = $scrl_out_set/tbl_out_set.get_node2(5, 0)
|
||||
for opt in OUT_MODE:
|
||||
mode.add_item(opt)
|
||||
var mode_index: int = OUT_MODE.find(dev.mode)
|
||||
if mode_index != -1:
|
||||
mode.select(mode_index)
|
||||
|
||||
|
||||
## Выбор входного или выходного устройства [param tbl] - таблица, [param dev] - устройство,
|
||||
## [param row_type] - массив с типами колонок, [param row_type_conn] - массив с пустыми LineEdit
|
||||
## [param lbl_text] - текст отображаемый во 2 строке: пример: ('Список соединённых входов :')
|
||||
## Выбор входного или выходного устройства.[br]
|
||||
## [param tbl] - таблица,[br]
|
||||
## [param dev] - устройство,[br]
|
||||
## [param row_type] - массив с типами колонок,[br]
|
||||
## [param row_type_conn] - массив с пустыми LineEdit,[br]
|
||||
## [param lbl_text] - текст отображаемый во 2 строке: пример: ('Список соединённых входов :').[br]
|
||||
func set_dev(tbl, dev, row_type, row_type_conn, lbl_text, row_size):
|
||||
tbl.clear_rows()
|
||||
tbl.add_row(row_type)
|
||||
tbl.set_columns_min_size(row_size)
|
||||
var le_name: LineEdit = tbl.get_node2(0, 0)
|
||||
le_name.editable = false
|
||||
le_name.text = dev.dev_name
|
||||
var connector: LineEdit = tbl.get_node2(1, 0)
|
||||
connector.editable = false
|
||||
connector.text = dev.connector
|
||||
var delay: LineEdit = tbl.get_node2(2, 0)
|
||||
delay.text = '%4.2f'%dev.delay
|
||||
var offset: LineEdit = tbl.get_node2(3, 0)
|
||||
offset.text = '%4.2f'%dev.offset
|
||||
var state = tbl.get_node2(4, 0)
|
||||
state.set_frame(dev.state)
|
||||
tbl.add_row(row_type_conn)
|
||||
var lbl: LineEdit = tbl.get_node2(0, 1)
|
||||
lbl.text = lbl_text
|
||||
for i in len(row_type_conn):
|
||||
var le: LineEdit = tbl.get_node2(i, 1)
|
||||
tbl.set_node_user_data(i, 0, dev)
|
||||
le.editable = false
|
||||
tbl.clear_rows()
|
||||
tbl.add_row(row_type)
|
||||
tbl.set_columns_min_size(row_size)
|
||||
var le_name: LineEdit = tbl.get_node2(0, 0)
|
||||
le_name.editable = false
|
||||
le_name.text = dev.dev_name
|
||||
var connector: LineEdit = tbl.get_node2(1, 0)
|
||||
connector.editable = false
|
||||
connector.text = dev.connector
|
||||
var delay: LineEdit = tbl.get_node2(2, 0)
|
||||
delay.text = '%4.2f'%dev.delay
|
||||
var offset: LineEdit = tbl.get_node2(3, 0)
|
||||
offset.text = '%4.2f'%dev.offset
|
||||
var state = tbl.get_node2(4, 0)
|
||||
state.set_frame(dev.state)
|
||||
tbl.add_row(row_type_conn)
|
||||
var lbl: LineEdit = tbl.get_node2(0, 1)
|
||||
lbl.text = lbl_text
|
||||
for i in len(row_type_conn):
|
||||
var le: LineEdit = tbl.get_node2(i, 1)
|
||||
tbl.set_node_user_data(i, 0, dev)
|
||||
le.editable = false
|
||||
|
||||
for i in dev.connect_devs:
|
||||
var dev_con = dev.connect_devs[i][0]
|
||||
tbl.add_row(row_type_conn)
|
||||
var node_index: Array = [0, tbl.get_rows_count() -1]
|
||||
var le_name_out: LineEdit = tbl.get_node2(node_index[0], node_index[1])
|
||||
disable_edit(tbl, len(row_type_conn), node_index[1])
|
||||
le_name_out.text = dev_con.dev_name
|
||||
tbl.set_node_user_data(node_index[0], node_index[1], dev.connect_devs[i])
|
||||
tbl.connect_columns(self, 'text_submitted', 'on_edit_entry', TABLE_ENTRY_COLUMNS, [])
|
||||
for i in dev.connect_devs:
|
||||
var dev_con = dev.connect_devs[i][0]
|
||||
tbl.add_row(row_type_conn)
|
||||
var node_index: Array = [0, tbl.get_rows_count() -1]
|
||||
var le_name_out: LineEdit = tbl.get_node2(node_index[0], node_index[1])
|
||||
disable_edit(tbl, len(row_type_conn), node_index[1])
|
||||
le_name_out.text = dev_con.dev_name
|
||||
tbl.set_node_user_data(node_index[0], node_index[1], dev.connect_devs[i])
|
||||
tbl.connect_columns(self, 'text_submitted', 'on_edit_entry', TABLE_ENTRY_COLUMNS, [])
|
||||
|
||||
|
||||
## Обработчик нажатия кнопки connect
|
||||
## Обработчик нажатия кнопки connect.
|
||||
func on_btn_connect():
|
||||
var in_row_index: Array = []
|
||||
var out_row_index: Array = []
|
||||
$scrollin/tbl_in.get_selected_rows(in_row_index)
|
||||
$scrollout/tbl_out.get_selected_rows(out_row_index)
|
||||
if len(in_row_index) and len(out_row_index):
|
||||
var in_user_data = $scrollin/tbl_in.get_node_user_data(0, in_row_index[0])
|
||||
var out_user_data = $scrollout/tbl_out.get_node_user_data(0, out_row_index[0])
|
||||
var in_dev = in_user_data[0]
|
||||
var out_dev = out_user_data[0]
|
||||
add_connection_dev($scrl_out_set/tbl_out_set, in_dev, out_dev, OUT_SET_ROW, in_user_data)
|
||||
add_connection_dev($scrl_in_set/tbl_in_set, out_dev, in_dev, IN_SET_ROW, out_user_data)
|
||||
var in_row_index: Array = []
|
||||
var out_row_index: Array = []
|
||||
$scrollin/tbl_in.get_selected_rows(in_row_index)
|
||||
$scrollout/tbl_out.get_selected_rows(out_row_index)
|
||||
if len(in_row_index) and len(out_row_index):
|
||||
var in_user_data = $scrollin/tbl_in.get_node_user_data(0, in_row_index[0])
|
||||
var out_user_data = $scrollout/tbl_out.get_node_user_data(0, out_row_index[0])
|
||||
var in_dev = in_user_data[0]
|
||||
var out_dev = out_user_data[0]
|
||||
add_connection_dev($scrl_out_set/tbl_out_set, in_dev, out_dev, OUT_SET_ROW, in_user_data)
|
||||
add_connection_dev($scrl_in_set/tbl_in_set, out_dev, in_dev, IN_SET_ROW, out_user_data)
|
||||
|
||||
|
||||
## образовывает связь между выбранным входом и выходом [param tbl] - таблица, [param dev1] - устройство1,
|
||||
## [param dev2] - устройство 2, [param set_row] - массив с пустыми LineEdit
|
||||
## [param user_data] - пользовательские данные устройства1
|
||||
## Образовывает связь между выбранным входом и выходом.[br]
|
||||
## [param tbl] - таблица,[br]
|
||||
## [param dev1] - устройство1,[br]
|
||||
## [param dev2] - устройство 2,[br]
|
||||
## [param set_row] - массив с пустыми LineEdit,[br]
|
||||
## [param user_data] - пользовательские данные устройства1.[br]
|
||||
func add_connection_dev(tbl, dev1, dev2, set_row, user_data):
|
||||
if not dev1.connector in dev2.connect_devs:
|
||||
tbl.add_row(set_row)
|
||||
var node_index: Array = [0, tbl.get_rows_count() -1]
|
||||
var le_name: LineEdit = tbl.get_node2(node_index[0], node_index[1])
|
||||
le_name.text = dev1.connector
|
||||
disable_edit(tbl, len(set_row), node_index[1])
|
||||
tbl.set_node_user_data(node_index[0], node_index[1], user_data)
|
||||
dev2.connect_devs[dev1.connector] = user_data
|
||||
if not dev1.connector in dev2.connect_devs:
|
||||
tbl.add_row(set_row)
|
||||
var node_index: Array = [0, tbl.get_rows_count() -1]
|
||||
var le_name: LineEdit = tbl.get_node2(node_index[0], node_index[1])
|
||||
le_name.text = dev1.connector
|
||||
disable_edit(tbl, len(set_row), node_index[1])
|
||||
tbl.set_node_user_data(node_index[0], node_index[1], user_data)
|
||||
dev2.connect_devs[dev1.connector] = user_data
|
||||
|
||||
|
||||
## Отключает возможность редактирования LineEdit в таблице [param tbl] - таблица,
|
||||
## [param num_col] - номер колонки, [param i_row] - номер столбца
|
||||
## Отключает возможность редактирования LineEdit в таблице.[br]
|
||||
## [param tbl] - таблица,[br]
|
||||
## [param num_col] - номер колонки,[br]
|
||||
## [param i_row] - номер столбца.[br]
|
||||
func disable_edit(tbl, num_col: int, i_row: int):
|
||||
for col in range(num_col):
|
||||
var node: LineEdit = tbl.get_node2(col, i_row)
|
||||
node.editable = false
|
||||
for col in range(num_col):
|
||||
var node: LineEdit = tbl.get_node2(col, i_row)
|
||||
node.editable = false
|
||||
|
||||
|
||||
## Обработчик выбора строки с таблице
|
||||
## Обработчик выбора строки с таблице.
|
||||
func on_row_pressed(i_row: int, tbl):
|
||||
tbl.clear_rows_selected()
|
||||
var is_row_selected = tbl.is_row_selected(i_row)
|
||||
tbl.set_row_selected(i_row, not is_row_selected)
|
||||
tbl.clear_rows_selected()
|
||||
var is_row_selected = tbl.is_row_selected(i_row)
|
||||
tbl.set_row_selected(i_row, not is_row_selected)
|
||||
|
||||
|
||||
@@ -1,50 +1,50 @@
|
||||
extends Node
|
||||
class_name STC extends Node
|
||||
|
||||
## Реализация "Протокол информационного сопряжения
|
||||
## СПО АСУ изделия «МП‑550» с СПО «Управления КАПС РПБ»"
|
||||
## Реализация "Протокол информационного сопряжения.
|
||||
## СПО АСУ изделия «МП‑550» с СПО «Управления КАПС РПБ».
|
||||
|
||||
|
||||
const ONLINE_TIMEOUT = 3000 ## Время ожидания пакета от КАПС РПБ, мс
|
||||
const BUFFER_SIZE = 2048 ## Размер приёмного буфера для датаграмм
|
||||
const ONLINE_TIMEOUT = 3000 ## Время ожидания пакета от КАПС РПБ, мс.
|
||||
const BUFFER_SIZE = 2048 ## Размер приёмного буфера для датаграмм.
|
||||
|
||||
|
||||
class CapsRpb:
|
||||
signal line_changed(unit: CapsRpb) ## Сигнал состояние связи изменилось
|
||||
signal data_received(unit: CapsRpb) ## Сигнал данные приняты
|
||||
signal command_fail(unit: CapsRpb) ## Сигнал при не выполнении команды
|
||||
signal parse_error(unit: CapsRpb, msg: String) ## Сигнал ошибки разбора сообщения
|
||||
signal line_changed(unit: CapsRpb) ## Сигнал состояние связи изменилось.
|
||||
signal data_received(unit: CapsRpb) ## Сигнал данные приняты.
|
||||
signal command_fail(unit: CapsRpb) ## Сигнал при не выполнении команды.
|
||||
signal parse_error(unit: CapsRpb, msg: String) ## Сигнал ошибки разбора сообщения.
|
||||
|
||||
static var json_conv: = JSON.new()
|
||||
var online: = false ## Состояние связи с источником сообщений
|
||||
var name: String ## Имя экземпляра
|
||||
var json_dic: Dictionary ## Аппарат для разбора сообщений
|
||||
var tick: = 0 ## Тик время последнего обновления, мс
|
||||
var tx_data: = PackedByteArray() ## Пакет для отправки
|
||||
var tx_stack: Array ## Массив пакетов для отправки
|
||||
static var json_conv: = JSON.new()
|
||||
var online: = false ## Состояние связи с источником сообщений.
|
||||
var name: String ## Имя экземпляра.
|
||||
var json_dic: Dictionary ## Аппарат для разбора сообщений.
|
||||
var tick: = 0 ## Тик время последнего обновления, мс.
|
||||
var tx_data: = PackedByteArray() ## Пакет для отправки.
|
||||
var tx_stack: Array ## Массив пакетов для отправки.
|
||||
|
||||
func _to_string() -> String: return String('капсрпб: "%s" %s ' % [self.name, ['отключен', 'на связи'][int(online)]])
|
||||
func _init(nm): self.name = nm
|
||||
func _to_string() -> String: return String('капсрпб: "%s" %s ' % [self.name, ['отключен', 'на связи'][int(online)]])
|
||||
func _init(nm): self.name = nm
|
||||
|
||||
func parse(data: PackedByteArray, now_tick: int):
|
||||
tick = now_tick
|
||||
if not online:
|
||||
online = true
|
||||
emit_signal('line_changed', self)
|
||||
var utf8_data = data.get_string_from_utf8()
|
||||
if Error.OK == json_conv.parse(utf8_data):
|
||||
json_dic.merge(json_conv.get_data(), true)
|
||||
emit_signal('data_received', self)
|
||||
else:
|
||||
var msg = json_conv.get_error_message()
|
||||
emit_signal('parse_error', self, msg)
|
||||
func parse(data: PackedByteArray, now_tick: int):
|
||||
tick = now_tick
|
||||
if not online:
|
||||
online = true
|
||||
emit_signal('line_changed', self)
|
||||
var utf8_data = data.get_string_from_utf8()
|
||||
if Error.OK == json_conv.parse(utf8_data):
|
||||
json_dic.merge(json_conv.get_data(), true)
|
||||
emit_signal('data_received', self)
|
||||
else:
|
||||
var msg = json_conv.get_error_message()
|
||||
emit_signal('parse_error', self, msg)
|
||||
|
||||
func process(now_tick: int):
|
||||
if online and ((now_tick - 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 process(now_tick: int):
|
||||
if online and ((now_tick - 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
|
||||
|
||||
@@ -9,30 +9,30 @@ var FILES_ROWS_ALIGNMENT = [ HORIZONTAL_ALIGNMENT_LEFT, HORIZONTAL_ALIGNM
|
||||
|
||||
|
||||
func fill_files_table(tbl: table, folder: String, rows_types: Array):
|
||||
var dir: = DirAccess.open(folder)
|
||||
if dir == null:
|
||||
return
|
||||
var files: = []
|
||||
var exclude_names: = ['.', '..']
|
||||
dir.list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547
|
||||
while true:
|
||||
var file: = dir.get_next()
|
||||
if file == '':
|
||||
break
|
||||
if file in exclude_names:
|
||||
continue
|
||||
var file_name = folder + '/' + file
|
||||
var fd = FileAccess.open(file_name, FileAccess.READ)
|
||||
if not fd:
|
||||
continue
|
||||
var glob_path = ProjectSettings.globalize_path(file_name)
|
||||
var sz = fd.get_length()
|
||||
var ut = fd.get_modified_time(file_name)
|
||||
fd.close()
|
||||
var mt = Time.get_datetime_dict_from_unix_time(ut)
|
||||
var file_row = [file, '%d' % sz, '%d-%02d-%02d %02d:%02d' % [mt.year, mt.month, mt.day, mt.hour, mt.minute]]
|
||||
tbl.add_row(rows_types)
|
||||
var i_row = tbl.get_rows_count() - 1
|
||||
tbl.set_row_text(i_row, file_row)
|
||||
tbl.set_node_meta(0, i_row, 'file_path', glob_path)
|
||||
dir.list_dir_end()
|
||||
var dir: = DirAccess.open(folder)
|
||||
if dir == null:
|
||||
return
|
||||
var files: = []
|
||||
var exclude_names: = ['.', '..']
|
||||
dir.list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547
|
||||
while true:
|
||||
var file: = dir.get_next()
|
||||
if file == '':
|
||||
break
|
||||
if file in exclude_names:
|
||||
continue
|
||||
var file_name = folder + '/' + file
|
||||
var fd = FileAccess.open(file_name, FileAccess.READ)
|
||||
if not fd:
|
||||
continue
|
||||
var glob_path = ProjectSettings.globalize_path(file_name)
|
||||
var sz = fd.get_length()
|
||||
var ut = fd.get_modified_time(file_name)
|
||||
fd.close()
|
||||
var mt = Time.get_datetime_dict_from_unix_time(ut)
|
||||
var file_row = [file, '%d' % sz, '%d-%02d-%02d %02d:%02d' % [mt.year, mt.month, mt.day, mt.hour, mt.minute]]
|
||||
tbl.add_row(rows_types)
|
||||
var i_row = tbl.get_rows_count() - 1
|
||||
tbl.set_row_text(i_row, file_row)
|
||||
tbl.set_node_meta(0, i_row, 'file_path', glob_path)
|
||||
dir.list_dir_end()
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
extends Node
|
||||
class_name HotKeys extends Node
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
signaller.connect('full_screen', Callable(self, 'toggle_full_screen').bind(0))
|
||||
signaller.connect('full_screen', Callable(self, 'toggle_full_screen').bind(0))
|
||||
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if event is InputEventKey:
|
||||
if event.pressed and event.physical_keycode == KEY_F11:
|
||||
signaller.emit_signal('full_screen')
|
||||
if event is InputEventKey:
|
||||
if event.pressed and event.physical_keycode == KEY_F11:
|
||||
signaller.emit_signal('full_screen')
|
||||
|
||||
|
||||
## Переключает режим окна программы полный - обычный экран
|
||||
## Переключает режим окна программы полный - обычный экран.
|
||||
func toggle_full_screen(id: int) -> void:
|
||||
var mode = DisplayServer.window_get_mode(id)
|
||||
mode = DisplayServer.WINDOW_MODE_WINDOWED \
|
||||
if mode == DisplayServer.WINDOW_MODE_FULLSCREEN \
|
||||
else DisplayServer.WINDOW_MODE_FULLSCREEN
|
||||
DisplayServer.window_set_mode(mode, id)
|
||||
var mode = DisplayServer.window_get_mode(id)
|
||||
mode = DisplayServer.WINDOW_MODE_WINDOWED \
|
||||
if mode == DisplayServer.WINDOW_MODE_FULLSCREEN \
|
||||
else DisplayServer.WINDOW_MODE_FULLSCREEN
|
||||
DisplayServer.window_set_mode(mode, id)
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
extends Node
|
||||
class_name Iterfer extends Node
|
||||
|
||||
## Представление помехи
|
||||
## Представление помехи.
|
||||
|
||||
## Режимы помехи
|
||||
## Режимы помехи.
|
||||
const ITERFER_MODE = {
|
||||
'off': ['Откл', ['freq', 'width'], 0],
|
||||
'auto': ['АВТО', ['freq', 'width'], 1000],
|
||||
'srni1': ['СРН-И1', ['freq', 'width'], 1],
|
||||
'srnm2': ['СРН-М2', ['freq', 'width'], 2],
|
||||
'srngps': ['СРН-GPS', ['freq', 'width'], 3],
|
||||
'lchm1': ['ЛЧМ-1', ['freq', 'width'], 10],
|
||||
'lchm2': ['ЛЧМ-2', ['freq', 'width'], 4],
|
||||
'mchm1': ['МЧМ-1', ['freq', 'width'], 11],
|
||||
'pdm2': ['ПД-М2', ['freq', 'width'], 12],
|
||||
'pdm4': ['ПД-М4', ['freq', 'width'], 13],
|
||||
'pdm4s': ['ПД-М4С', ['freq', 'width'], 14],
|
||||
'pdchm': ['ПД-ЧМ', ['freq', 'width'], 15],
|
||||
'svi1': ['СВ-И1', ['freq', 'width'], 20],
|
||||
'svm2': ['СВ-М2', ['freq', 'width'], 21],
|
||||
'k1': ['K1', ['freq', 'width', 'dur', 'period'], 50],
|
||||
'ozp1': ['ОЗП-1', ['freq', 'width'], 51] }
|
||||
'off': ['Откл', ['freq', 'width'], 0],
|
||||
'auto': ['АВТО', ['freq', 'width'], 1000],
|
||||
'srni1': ['СРН-И1', ['freq', 'width'], 1],
|
||||
'srnm2': ['СРН-М2', ['freq', 'width'], 2],
|
||||
'srngps': ['СРН-GPS', ['freq', 'width'], 3],
|
||||
'lchm1': ['ЛЧМ-1', ['freq', 'width'], 10],
|
||||
'lchm2': ['ЛЧМ-2', ['freq', 'width'], 4],
|
||||
'mchm1': ['МЧМ-1', ['freq', 'width'], 11],
|
||||
'pdm2': ['ПД-М2', ['freq', 'width'], 12],
|
||||
'pdm4': ['ПД-М4', ['freq', 'width'], 13],
|
||||
'pdm4s': ['ПД-М4С', ['freq', 'width'], 14],
|
||||
'pdchm': ['ПД-ЧМ', ['freq', 'width'], 15],
|
||||
'svi1': ['СВ-И1', ['freq', 'width'], 20],
|
||||
'svm2': ['СВ-М2', ['freq', 'width'], 21],
|
||||
'k1': ['K1', ['freq', 'width', 'dur', 'period'], 50],
|
||||
'ozp1': ['ОЗП-1', ['freq', 'width'], 51] }
|
||||
|
||||
const FREQ_MAX = 6000
|
||||
const FREQ_MIN = 400
|
||||
@@ -27,63 +27,63 @@ const WIDTH_MAX = 120
|
||||
const WIDTH_MIN = 0
|
||||
|
||||
const SOURCE_INTERFER = ['th','fs','cu']
|
||||
const ID_INTERFERS_LEN = 63 ## Размер пула номеров целей
|
||||
const ID_INTERFERS_LEN = 63 ## Размер пула номеров целей.
|
||||
const INTERFER_OFF = 'off'
|
||||
const STATE_TSMT = 5 ## Значение svk для цели, когда ответ ещё не получен
|
||||
var msg_ss: int = 0 ## счётчик сообщений
|
||||
var id_array: Array ## Массив id воздействий
|
||||
var thrs: Dictionary ## Словарь воздействия для целей, ключ - id воздействия
|
||||
var fs: Dictionary ## Словарь воздействий для секторов, ключ - id воздействия
|
||||
var cu: Dictionary ## Словарь воздействий для 5П-28, ключ - id воздействия
|
||||
const STATE_TSMT = 5 ## Значение svk для цели, когда ответ ещё не получен.
|
||||
var msg_ss: int = 0 ## Счётчик сообщений.
|
||||
var id_array: Array ## Массив id воздействий.
|
||||
var thrs: Dictionary ## Словарь воздействия для целей, ключ - id воздействия.
|
||||
var fs: Dictionary ## Словарь воздействий для секторов, ключ - id воздействия.
|
||||
var cu: Dictionary ## Словарь воздействий для 5П-28, ключ - id воздействия.
|
||||
|
||||
## Сеанс помехи
|
||||
## Сеанс помехи.
|
||||
class Interfer:
|
||||
var ss: int = 0 ## Счётчик сообщений.
|
||||
var ispp: int = 0 ## Индекс сеанса.
|
||||
var svk: = 0 ## Состояние сеанса. Ответ КАПСРПБ. Возможные значения в [param ITERFER_STATE].
|
||||
var krp: String = '' ## Тип помехи. Возможные значения в [param INTERFER_MODE].
|
||||
var powp: float = 0.0 ## Мощность излучения выраженная в процентах.
|
||||
var kni: = 0.0 ## Курсовой угол направления излучения.
|
||||
var params: = {} ## Параметры помехи.
|
||||
var get_params: Array[String] ## Запрос массива параметров (список запрошенных параметров).
|
||||
var retss: int ## Значение счётчика сообщения в котором был произведён запрос массива параметров.
|
||||
var tick_tx: int ## Тик время обновления цели, мс.
|
||||
var source_interfer: String = '' ## Тип объекта по которой поставлена помеха
|
||||
var ss: int = 0 ## Счётчик сообщений.
|
||||
var ispp: int = 0 ## Индекс сеанса.
|
||||
var svk: = 0 ## Состояние сеанса. Ответ КАПСРПБ. Возможные значения в [param ITERFER_STATE].
|
||||
var krp: String = '' ## Тип помехи. Возможные значения в [param INTERFER_MODE].
|
||||
var powp: float = 0.0 ## Мощность излучения выраженная в процентах.
|
||||
var kni: = 0.0 ## Курсовой угол направления излучения.
|
||||
var params: = {} ## Параметры помехи.
|
||||
var get_params: Array[String] ## Запрос массива параметров (список запрошенных параметров).
|
||||
var retss: int ## Значение счётчика сообщения в котором был произведён запрос массива параметров.
|
||||
var tick_tx: int ## Тик время обновления цели, мс.
|
||||
var source_interfer: String = '' ## Тип объекта по которой поставлена помеха.
|
||||
|
||||
func _to_string() -> String:
|
||||
return 'номер: %d название: %s частота: %0.1f МГц пеленг: %0.1f гр.' % [ispp, ITERFER_MODE[krp][0], params['freq'], kni]
|
||||
func _to_string() -> String:
|
||||
return 'номер: %d название: %s частота: %0.1f МГц пеленг: %0.1f гр.' % [ispp, ITERFER_MODE[krp][0], params['freq'], kni]
|
||||
|
||||
func get_msg6_data():
|
||||
var data_to_json : Dictionary = {}
|
||||
data_to_json['ts'] = 6
|
||||
data_to_json['ss'] = ss
|
||||
data_to_json['ispp'] = ispp
|
||||
data_to_json['krp'] = krp
|
||||
if krp != INTERFER_OFF:
|
||||
data_to_json['kni'] = kni
|
||||
data_to_json['powp'] = powp # Необходимо добавить управление мощностью
|
||||
data_to_json['get'] = []
|
||||
data_to_json['params'] = params
|
||||
var json = JSON.stringify(data_to_json)
|
||||
var pac = json.to_utf8_buffer()
|
||||
return pac
|
||||
func get_msg6_data():
|
||||
var data_to_json : Dictionary = {}
|
||||
data_to_json['ts'] = 6
|
||||
data_to_json['ss'] = ss
|
||||
data_to_json['ispp'] = ispp
|
||||
data_to_json['krp'] = krp
|
||||
if krp != INTERFER_OFF:
|
||||
data_to_json['kni'] = kni
|
||||
data_to_json['powp'] = powp # Необходимо добавить управление мощностью
|
||||
data_to_json['get'] = []
|
||||
data_to_json['params'] = params
|
||||
var json = JSON.stringify(data_to_json)
|
||||
var pac = json.to_utf8_buffer()
|
||||
return pac
|
||||
|
||||
func set_from_dic(dic: Dictionary):
|
||||
var names: = tools.get_members_names(self)
|
||||
names.any(func(vn): if dic.has(vn): set(vn, dic[vn]); return false)
|
||||
func set_from_dic(dic: Dictionary):
|
||||
var names: = tools.get_members_names(self)
|
||||
names.any(func(vn): if dic.has(vn): set(vn, dic[vn]); return false)
|
||||
|
||||
func get_value(value_key):
|
||||
var param = self.get(value_key)
|
||||
if param == null:
|
||||
if params.has(value_key): param = params[value_key]
|
||||
return param
|
||||
func get_value(value_key):
|
||||
var param = self.get(value_key)
|
||||
if param == null:
|
||||
if params.has(value_key): param = params[value_key]
|
||||
return param
|
||||
|
||||
func set_value(value, value_key):
|
||||
var param = self.get(value_key)
|
||||
if param == null:
|
||||
params[value_key] = value
|
||||
else:
|
||||
self.set(value_key, value)
|
||||
func set_value(value, value_key):
|
||||
var param = self.get(value_key)
|
||||
if param == null:
|
||||
params[value_key] = value
|
||||
else:
|
||||
self.set(value_key, value)
|
||||
|
||||
|
||||
signal interfer_preparing(ecm: Interfer) ## Вызывается в момент запуска помехи.
|
||||
@@ -94,173 +94,173 @@ signal interfer_resized(ecms: Dictionary) ## Вызывается пр
|
||||
|
||||
|
||||
func _ready():
|
||||
var ecms: Dictionary = {} ## Словарь помех
|
||||
for i in range(ID_INTERFERS_LEN): # Заполняет массив ID целей
|
||||
id_array.append(i + 1)
|
||||
var unit_key = repsettings.get_unit_key('уарэп-капсрпб-отп')
|
||||
var unit = repnetwork.units[unit_key]
|
||||
var unit_5p28_key = repsettings.get_unit_key('уарэп-5п28')
|
||||
var unit_5p28 = repnetwork.units_tcp[unit_5p28_key]
|
||||
var timer_check_state: = Timer.new()
|
||||
add_child(timer_check_state)
|
||||
var resend_timeout = ProjectSettings.get_setting('application/interfer/resend_timeout', 1000.0)
|
||||
timer_check_state.connect('timeout', Callable(self, 'on_timer_check_state').bind(unit, ecms, resend_timeout))
|
||||
timer_check_state.start(resend_timeout / 1000.0)
|
||||
unit.connect('data_received', Callable(self, 'on_data_capsrpb_received').bind(ecms))
|
||||
unit_5p28.connect('get_interfers', Callable(self, 'on_get_interfers').bind(unit_5p28, ecms))
|
||||
signaller.connect('interfer_create', Callable(self, 'on_interfer_create').bind(unit, ecms))
|
||||
signaller.connect('interfer_rcv', Callable(self, 'on_interfer_rcv').bind(unit_5p28, ecms))
|
||||
signaller.connect('interfer_new', Callable(self, 'send_ecm').bind(unit))
|
||||
signaller.connect('interfer_off_all', Callable(self, 'on_interfer_off_all').bind(unit, ecms))
|
||||
var ecms: Dictionary = {} ## Словарь помех.
|
||||
for i in range(ID_INTERFERS_LEN): # Заполняет массив ID целей
|
||||
id_array.append(i + 1)
|
||||
var unit_key = repsettings.get_unit_key('уарэп-капсрпб-отп')
|
||||
var unit = repnetwork.units[unit_key]
|
||||
var unit_5p28_key = repsettings.get_unit_key('уарэп-5п28')
|
||||
var unit_5p28 = repnetwork.units_tcp[unit_5p28_key]
|
||||
var timer_check_state: = Timer.new()
|
||||
add_child(timer_check_state)
|
||||
var resend_timeout = ProjectSettings.get_setting('application/interfer/resend_timeout', 1000.0)
|
||||
timer_check_state.connect('timeout', Callable(self, 'on_timer_check_state').bind(unit, ecms, resend_timeout))
|
||||
timer_check_state.start(resend_timeout / 1000.0)
|
||||
unit.connect('data_received', Callable(self, 'on_data_capsrpb_received').bind(ecms))
|
||||
unit_5p28.connect('get_interfers', Callable(self, 'on_get_interfers').bind(unit_5p28, ecms))
|
||||
signaller.connect('interfer_create', Callable(self, 'on_interfer_create').bind(unit, ecms))
|
||||
signaller.connect('interfer_rcv', Callable(self, 'on_interfer_rcv').bind(unit_5p28, ecms))
|
||||
signaller.connect('interfer_new', Callable(self, 'send_ecm').bind(unit))
|
||||
signaller.connect('interfer_off_all', Callable(self, 'on_interfer_off_all').bind(unit, ecms))
|
||||
|
||||
|
||||
# Проверяет состояние отправки пакета и если не доставлен, повторяет отправку
|
||||
## Проверяет состояние отправки пакета и если не доставлен, повторяет отправку.
|
||||
func on_timer_check_state(unit, ecms, resend_timeout):
|
||||
var tick = Time.get_ticks_msec()
|
||||
for ecm in ecms.values():
|
||||
if ecm.svk == STATE_TSMT:
|
||||
if (tick - ecm.tick_tx) >= resend_timeout:
|
||||
send_ecm(ecm, unit)
|
||||
ecm.tick_tx = tick
|
||||
var tick = Time.get_ticks_msec()
|
||||
for ecm in ecms.values():
|
||||
if ecm.svk == STATE_TSMT:
|
||||
if (tick - ecm.tick_tx) >= resend_timeout:
|
||||
send_ecm(ecm, unit)
|
||||
ecm.tick_tx = tick
|
||||
|
||||
|
||||
## Производит приём состояния помех. [param unit] -> [param ecms]
|
||||
## Производит приём состояния помех. [param unit] -> [param ecms].
|
||||
func on_data_capsrpb_received(unit: capsrpb.CapsRpb, ecms: Dictionary):
|
||||
if not unit.json_dic.has('ts'): return
|
||||
if not (unit.json_dic['ts'] is float): return
|
||||
if unit.json_dic['ts'] != 5: return
|
||||
if not unit.json_dic.has('msvk'): return
|
||||
if not (unit.json_dic['msvk'] is Array): return
|
||||
var msvk = unit.json_dic['msvk']
|
||||
var sz: = ecms.size()
|
||||
for dic_msvk in msvk:
|
||||
if not (dic_msvk is Dictionary): continue
|
||||
if dic_msvk.has('ispp'):
|
||||
var ispp = int(dic_msvk['ispp'])
|
||||
if ecms.has(ispp):
|
||||
var ecm = ecms[ispp]
|
||||
ecm.set_from_dic(dic_msvk)
|
||||
call_deferred('emit_signal', 'interfer_update', ecm)
|
||||
else:
|
||||
var ecm = Interfer.new()
|
||||
ecm.set_from_dic(dic_msvk)
|
||||
ecm.krp = INTERFER_OFF
|
||||
send_ecm(ecm, unit)
|
||||
if sz != ecms.size():
|
||||
call_deferred('emit_signal', 'interfer_resized', ecms)
|
||||
if not unit.json_dic.has('ts'): return
|
||||
if not (unit.json_dic['ts'] is float): return
|
||||
if unit.json_dic['ts'] != 5: return
|
||||
if not unit.json_dic.has('msvk'): return
|
||||
if not (unit.json_dic['msvk'] is Array): return
|
||||
var msvk = unit.json_dic['msvk']
|
||||
var sz: = ecms.size()
|
||||
for dic_msvk in msvk:
|
||||
if not (dic_msvk is Dictionary): continue
|
||||
if dic_msvk.has('ispp'):
|
||||
var ispp = int(dic_msvk['ispp'])
|
||||
if ecms.has(ispp):
|
||||
var ecm = ecms[ispp]
|
||||
ecm.set_from_dic(dic_msvk)
|
||||
call_deferred('emit_signal', 'interfer_update', ecm)
|
||||
else:
|
||||
var ecm = Interfer.new()
|
||||
ecm.set_from_dic(dic_msvk)
|
||||
ecm.krp = INTERFER_OFF
|
||||
send_ecm(ecm, unit)
|
||||
if sz != ecms.size():
|
||||
call_deferred('emit_signal', 'interfer_resized', ecms)
|
||||
|
||||
|
||||
## Вызыватся, когда пользователь выбрал помеху и выбраны цели
|
||||
## Вызыватся, когда пользователь выбрал помеху и выбраны цели.
|
||||
func on_interfer_create(btn, sel_threats, fs_arr, _unit, ecms):
|
||||
for item in sel_threats:
|
||||
var param: Dictionary = {}
|
||||
var kni: float = item.aoa
|
||||
var id = item.id
|
||||
var interfer_name: String = btn.get_meta('rfi_name')
|
||||
param['freq'] = item.freq
|
||||
param['width'] = item.width
|
||||
interfer_create(interfer_name, ecms, param, kni, id, thrs, SOURCE_INTERFER[0])
|
||||
for item in sel_threats:
|
||||
var param: Dictionary = {}
|
||||
var kni: float = item.aoa
|
||||
var id = item.id
|
||||
var interfer_name: String = btn.get_meta('rfi_name')
|
||||
param['freq'] = item.freq
|
||||
param['width'] = item.width
|
||||
interfer_create(interfer_name, ecms, param, kni, id, thrs, SOURCE_INTERFER[0])
|
||||
|
||||
for item in fs_arr:
|
||||
var param: Dictionary = {}
|
||||
var kni: float = item[0]
|
||||
var id = item[3]
|
||||
var interfer_name: String = btn.get_meta('rfi_name')
|
||||
param['freq'] = item[1]
|
||||
param['width'] = item[2]
|
||||
interfer_create(interfer_name, ecms, param, kni, id, fs, SOURCE_INTERFER[1])
|
||||
for item in fs_arr:
|
||||
var param: Dictionary = {}
|
||||
var kni: float = item[0]
|
||||
var id = item[3]
|
||||
var interfer_name: String = btn.get_meta('rfi_name')
|
||||
param['freq'] = item[1]
|
||||
param['width'] = item[2]
|
||||
interfer_create(interfer_name, ecms, param, kni, id, fs, SOURCE_INTERFER[1])
|
||||
|
||||
|
||||
func on_interfer_rcv(interfer_params: Array, unit, ecms):
|
||||
var err: bool = false
|
||||
var mode = interfer_params[0]
|
||||
var id = interfer_params[1]
|
||||
var aoa = interfer_params[2]
|
||||
if (aoa < 0) and (aoa > 360):
|
||||
err = true
|
||||
var param: Dictionary = {}
|
||||
param['freq'] = interfer_params[4]
|
||||
if (param['freq'] < FREQ_MIN) and (param['freq'] > FREQ_MAX):
|
||||
err = true
|
||||
param['width'] = interfer_params[5]
|
||||
if (param['width'] < WIDTH_MIN) and (param['width'] > WIDTH_MAX):
|
||||
err = true
|
||||
var interfer_name: String
|
||||
for key in ITERFER_MODE:
|
||||
if ITERFER_MODE[key][2] == mode:
|
||||
interfer_name = key
|
||||
break
|
||||
if interfer_name == '':
|
||||
err = true
|
||||
if not err:
|
||||
interfer_create(interfer_name, ecms, param, aoa, id, cu, SOURCE_INTERFER[2])
|
||||
unit.on_interfer_accept(err)
|
||||
var err: bool = false
|
||||
var mode = interfer_params[0]
|
||||
var id = interfer_params[1]
|
||||
var aoa = interfer_params[2]
|
||||
if (aoa < 0) and (aoa > 360):
|
||||
err = true
|
||||
var param: Dictionary = {}
|
||||
param['freq'] = interfer_params[4]
|
||||
if (param['freq'] < FREQ_MIN) and (param['freq'] > FREQ_MAX):
|
||||
err = true
|
||||
param['width'] = interfer_params[5]
|
||||
if (param['width'] < WIDTH_MIN) and (param['width'] > WIDTH_MAX):
|
||||
err = true
|
||||
var interfer_name: String
|
||||
for key in ITERFER_MODE:
|
||||
if ITERFER_MODE[key][2] == mode:
|
||||
interfer_name = key
|
||||
break
|
||||
if interfer_name == '':
|
||||
err = true
|
||||
if not err:
|
||||
interfer_create(interfer_name, ecms, param, aoa, id, cu, SOURCE_INTERFER[2])
|
||||
unit.on_interfer_accept(err)
|
||||
|
||||
|
||||
func interfer_create(interfer_name, ecms, param, kni, id, dict, source_interfer):
|
||||
var ispp: int = 0
|
||||
if interfer_name == 'k1':
|
||||
param['dur'] = 1.0 # Необходимо добавить параметры управления
|
||||
param['period'] = 1.0 # Необходимо добавить параметры управления
|
||||
var key = dict.find_key(id)
|
||||
if source_interfer != SOURCE_INTERFER[2]:
|
||||
if key != null:
|
||||
ispp = key
|
||||
else:
|
||||
if interfer_name == 'off':
|
||||
return
|
||||
ispp = pop_id()
|
||||
if ispp == 0: return
|
||||
else: ispp = id
|
||||
dict[ispp] = id
|
||||
msg_ss += 1
|
||||
var ecm: Interfer
|
||||
if ecms.has(ispp):
|
||||
ecm = ecms[ispp]
|
||||
else:
|
||||
ecm = Interfer.new()
|
||||
ecm.ispp = ispp
|
||||
ecms[ispp] = ecm
|
||||
ecm.svk = STATE_TSMT # Подготовка к передаче сообщения
|
||||
ecm.ss = msg_ss
|
||||
ecm.kni = kni
|
||||
ecm.krp = interfer_name
|
||||
ecm.params = param
|
||||
ecm.powp = 100.0 # Необходимо добавить управление мощностью
|
||||
ecm.source_interfer = source_interfer
|
||||
signaller.emit_signal('interfer_new', ecm)
|
||||
if interfer_name == 'off':
|
||||
signaller.emit_signal('interfer_off', ecm, ecms, thrs)
|
||||
push_id(ecm.ispp)
|
||||
thrs.erase(ispp)
|
||||
ecm.tick_tx = Time.get_ticks_msec()
|
||||
var ispp: int = 0
|
||||
if interfer_name == 'k1':
|
||||
param['dur'] = 1.0 # Необходимо добавить параметры управления
|
||||
param['period'] = 1.0 # Необходимо добавить параметры управления
|
||||
var key = dict.find_key(id)
|
||||
if source_interfer != SOURCE_INTERFER[2]:
|
||||
if key != null:
|
||||
ispp = key
|
||||
else:
|
||||
if interfer_name == 'off':
|
||||
return
|
||||
ispp = pop_id()
|
||||
if ispp == 0: return
|
||||
else: ispp = id
|
||||
dict[ispp] = id
|
||||
msg_ss += 1
|
||||
var ecm: Interfer
|
||||
if ecms.has(ispp):
|
||||
ecm = ecms[ispp]
|
||||
else:
|
||||
ecm = Interfer.new()
|
||||
ecm.ispp = ispp
|
||||
ecms[ispp] = ecm
|
||||
ecm.svk = STATE_TSMT # Подготовка к передаче сообщения
|
||||
ecm.ss = msg_ss
|
||||
ecm.kni = kni
|
||||
ecm.krp = interfer_name
|
||||
ecm.params = param
|
||||
ecm.powp = 100.0 # Необходимо добавить управление мощностью
|
||||
ecm.source_interfer = source_interfer
|
||||
signaller.emit_signal('interfer_new', ecm)
|
||||
if interfer_name == 'off':
|
||||
signaller.emit_signal('interfer_off', ecm, ecms, thrs)
|
||||
push_id(ecm.ispp)
|
||||
thrs.erase(ispp)
|
||||
ecm.tick_tx = Time.get_ticks_msec()
|
||||
|
||||
|
||||
func send_ecm(ecm, unit):
|
||||
var json_data = ecm.get_msg6_data()
|
||||
unit.tx_stack.append(json_data)
|
||||
var json_data = ecm.get_msg6_data()
|
||||
unit.tx_stack.append(json_data)
|
||||
|
||||
|
||||
func on_interfer_off_all(unit, ecms):
|
||||
for ecm in ecms.values():
|
||||
ecm.krp = INTERFER_OFF
|
||||
push_id(ecm.ispp)
|
||||
send_ecm(ecm, unit)
|
||||
signaller.emit_signal('interfer_off',ecm, ecms, thrs)
|
||||
for ecm in ecms.values():
|
||||
ecm.krp = INTERFER_OFF
|
||||
push_id(ecm.ispp)
|
||||
send_ecm(ecm, unit)
|
||||
signaller.emit_signal('interfer_off',ecm, ecms, thrs)
|
||||
|
||||
|
||||
func pop_id():
|
||||
var id = 0
|
||||
if len(id_array):
|
||||
id = id_array[0]
|
||||
id_array.remove_at(0)
|
||||
return id
|
||||
var id = 0
|
||||
if len(id_array):
|
||||
id = id_array[0]
|
||||
id_array.remove_at(0)
|
||||
return id
|
||||
|
||||
|
||||
func push_id(id : int):
|
||||
id_array.append(id)
|
||||
id_array.sort()
|
||||
id_array.append(id)
|
||||
id_array.sort()
|
||||
|
||||
|
||||
## отправляет словаhь помех в юнит, для запаковки и отправки в 5П28
|
||||
## Отправляет словарь помех в юнит, для запаковки и отправки в 5П28.
|
||||
func on_get_interfers(unit, ecms): unit.pack_interfers(cu, ecms)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,131 +1,131 @@
|
||||
extends Node
|
||||
class_name mod_bus extends Node
|
||||
|
||||
const ONLINE_TIMEOUT = 5.0 ## Время ожидания пакета от ячейки, секунды
|
||||
const ONLINE_TIMEOUT = 5.0 ## Время ожидания пакета от ячейки, секунды.
|
||||
|
||||
class ModbusClient:
|
||||
|
||||
## Состояние автомата выполнения команды
|
||||
enum CmdState {
|
||||
DONE, ## Команда выполнена
|
||||
FAIL, ## Команда не выполнена
|
||||
SEND, ## Буфер готов для отправки
|
||||
WAIT ## Ожидание выполнения
|
||||
}
|
||||
## Состояние автомата выполнения команды.
|
||||
enum CmdState {
|
||||
DONE, ## Команда выполнена.
|
||||
FAIL, ## Команда не выполнена.
|
||||
SEND, ## Буфер готов для отправки.
|
||||
WAIT ## Ожидание выполнения.
|
||||
}
|
||||
|
||||
var name: String
|
||||
var unit: = 1 ## Адрес устройства Modbus
|
||||
var cmd_state: = CmdState.DONE ## Код текущей команды
|
||||
var tx_data: PackedByteArray ## Данные для отправки
|
||||
var online: = false ## Флаг. Если установлен, устройство на связи. Активный уровень - [b]true[/b].
|
||||
var tick_rx: = 0 ## Время приёма крайнего сообщения
|
||||
var tick_tx: = 0 ## Время отправки крайнего сообщения
|
||||
var name: String
|
||||
var unit: = 1 ## Адрес устройства Modbus.
|
||||
var cmd_state: = CmdState.DONE ## Код текущей команды.
|
||||
var tx_data: PackedByteArray ## Данные для отправки.
|
||||
var online: = false ## Флаг. Если установлен, устройство на связи. Активный уровень - [b]true[/b].
|
||||
var tick_rx: = 0 ## Время приёма крайнего сообщения.
|
||||
var tick_tx: = 0 ## Время отправки крайнего сообщения.
|
||||
|
||||
static var json_conv: = JSON.new()
|
||||
static var json_conv: = JSON.new()
|
||||
|
||||
signal command_done() ## Вызывается при успешном выполнении команды
|
||||
signal command_fail() ## Вызывается при возникновении ошибки во время выполнения команды
|
||||
signal line_changed() ## Вызывается при смене состояния связи с ячейкой
|
||||
signal data_received() ## Вызывается при приёме сообщения, до его разбора
|
||||
signal parse_failed(msg: String) ## Вызывается при возникновении ошибки во время разбора пакета. Передаёт сообщение об ошибке
|
||||
signal command_done() ## Вызывается при успешном выполнении команды.
|
||||
signal command_fail() ## Вызывается при возникновении ошибки во время выполнения команды.
|
||||
signal line_changed() ## Вызывается при смене состояния связи с ячейкой.
|
||||
signal data_received() ## Вызывается при приёме сообщения, до его разбора.
|
||||
signal parse_failed(msg: String) ## Вызывается при возникновении ошибки во время разбора пакета. Передаёт сообщение об ошибке.
|
||||
|
||||
signal holding_received(addr: int, data: Array) ## Вызывается при получении сообщения c данными из регистров хранения
|
||||
signal input_received(addr: int, data: Array) ## Вызывается при получении сообщения c данными из регистров входов
|
||||
signal info_received(msg: String) ## Вызывается при получении информационного сообщения
|
||||
signal except_received(msg: String) ## Вызывается при получении сообщения об исключительной ситуации
|
||||
signal holding_received(addr: int, data: Array) ## Вызывается при получении сообщения c данными из регистров хранения.
|
||||
signal input_received(addr: int, data: Array) ## Вызывается при получении сообщения c данными из регистров входов.
|
||||
signal info_received(msg: String) ## Вызывается при получении информационного сообщения.
|
||||
signal except_received(msg: String) ## Вызывается при получении сообщения об исключительной ситуации.
|
||||
|
||||
func _init(nm: String, u: int = 1):
|
||||
unit = u
|
||||
name = nm
|
||||
func _init(nm: String, u: int = 1):
|
||||
unit = u
|
||||
name = nm
|
||||
|
||||
## Изменяет состояние. Вызывать периодически[br]
|
||||
## [param tick] - Текущщее время в мс[br]
|
||||
func process(tick: int):
|
||||
if online and ((tick - tick_rx) > ONLINE_TIMEOUT):
|
||||
online = false
|
||||
emit_signal('line_changed')
|
||||
if (cmd_state == CmdState.WAIT) or (cmd_state == CmdState.SEND):
|
||||
cmd_state = CmdState.FAIL
|
||||
emit_signal('command_fail')
|
||||
var rc = Error.ERR_BUSY
|
||||
if cmd_state == CmdState.SEND:
|
||||
rc = Error.OK
|
||||
tick_tx = tick
|
||||
cmd_state = CmdState.WAIT
|
||||
return rc
|
||||
## Изменяет состояние. Вызывать периодически.[br]
|
||||
## [param tick] - Текущщее время в мс.[br]
|
||||
func process(tick: int):
|
||||
if online and ((tick - tick_rx) > ONLINE_TIMEOUT):
|
||||
online = false
|
||||
emit_signal('line_changed')
|
||||
if (cmd_state == CmdState.WAIT) or (cmd_state == CmdState.SEND):
|
||||
cmd_state = CmdState.FAIL
|
||||
emit_signal('command_fail')
|
||||
var rc = Error.ERR_BUSY
|
||||
if cmd_state == CmdState.SEND:
|
||||
rc = Error.OK
|
||||
tick_tx = tick
|
||||
cmd_state = CmdState.WAIT
|
||||
return rc
|
||||
|
||||
## Производит разбор принятых данных. Вызывать при приёме данных на сокете[br]
|
||||
## [param data] - Данные принятые на сокете[br]
|
||||
## [param tick] - Текущщее время в мс[br]
|
||||
func parse(data: PackedByteArray, tick: int) -> bool:
|
||||
tick_rx = tick
|
||||
if not online:
|
||||
online = true
|
||||
emit_signal('line_changed')
|
||||
var utf8_data = data.get_string_from_utf8()
|
||||
if Error.OK == json_conv.parse(utf8_data):
|
||||
emit_signal('data_received')
|
||||
var message: Dictionary = json_conv.get_data()
|
||||
if message.has('code') and message.has('data'):
|
||||
var rc: = true
|
||||
var message_code = message['code']
|
||||
var message_data = message['data']
|
||||
match message_code:
|
||||
'read_input':
|
||||
var addr = message_data[0]
|
||||
var regs = message_data.slice(1)
|
||||
emit_signal('input_received', addr, regs)
|
||||
'read_holding':
|
||||
var addr = message_data[0]
|
||||
var regs = message_data.slice(1)
|
||||
emit_signal('holding_received', addr, regs)
|
||||
'info':
|
||||
var msg = message['data']
|
||||
emit_signal('info_received', msg)
|
||||
'exception':
|
||||
var msg = message['data']
|
||||
emit_signal('except_received', msg)
|
||||
rc = false
|
||||
_:
|
||||
var msg: String = 'код команды \"%s\" - не распознан' % message_code
|
||||
emit_signal('parse_failed', msg)
|
||||
rc = false
|
||||
if (cmd_state == CmdState.WAIT) and rc:
|
||||
cmd_state = CmdState.DONE
|
||||
emit_signal('command_done')
|
||||
elif (cmd_state == CmdState.WAIT) and (not rc):
|
||||
cmd_state = CmdState.FAIL
|
||||
emit_signal('command_fail')
|
||||
else:
|
||||
var message = json_conv.get_error_message()
|
||||
emit_signal('parse_failed', message)
|
||||
return true
|
||||
## Производит разбор принятых данных. Вызывать при приёме данных на сокете.[br]
|
||||
## [param data] - Данные принятые на сокете.[br]
|
||||
## [param tick] - Текущщее время в мс.[br]
|
||||
func parse(data: PackedByteArray, tick: int) -> bool:
|
||||
tick_rx = tick
|
||||
if not online:
|
||||
online = true
|
||||
emit_signal('line_changed')
|
||||
var utf8_data = data.get_string_from_utf8()
|
||||
if Error.OK == json_conv.parse(utf8_data):
|
||||
emit_signal('data_received')
|
||||
var message: Dictionary = json_conv.get_data()
|
||||
if message.has('code') and message.has('data'):
|
||||
var rc: = true
|
||||
var message_code = message['code']
|
||||
var message_data = message['data']
|
||||
match message_code:
|
||||
'read_input':
|
||||
var addr = message_data[0]
|
||||
var regs = message_data.slice(1)
|
||||
emit_signal('input_received', addr, regs)
|
||||
'read_holding':
|
||||
var addr = message_data[0]
|
||||
var regs = message_data.slice(1)
|
||||
emit_signal('holding_received', addr, regs)
|
||||
'info':
|
||||
var msg = message['data']
|
||||
emit_signal('info_received', msg)
|
||||
'exception':
|
||||
var msg = message['data']
|
||||
emit_signal('except_received', msg)
|
||||
rc = false
|
||||
_:
|
||||
var msg: String = 'код команды \"%s\" - не распознан' % message_code
|
||||
emit_signal('parse_failed', msg)
|
||||
rc = false
|
||||
if (cmd_state == CmdState.WAIT) and rc:
|
||||
cmd_state = CmdState.DONE
|
||||
emit_signal('command_done')
|
||||
elif (cmd_state == CmdState.WAIT) and (not rc):
|
||||
cmd_state = CmdState.FAIL
|
||||
emit_signal('command_fail')
|
||||
else:
|
||||
var message = json_conv.get_error_message()
|
||||
emit_signal('parse_failed', message)
|
||||
return true
|
||||
|
||||
## Отправляет команду "записать в регистры".[br]
|
||||
## [param addr] - Начальный адрес регистров.[br]
|
||||
## [param count] - Данные для записи в регистры от начального адреса.[br]
|
||||
func write(addr: int, data: Array) -> bool:
|
||||
if cmd_state != CmdState.DONE: return false
|
||||
var json_dict = {'code': 'write', 'data': [addr] + data}
|
||||
tx_data = JSON.stringify(json_dict).to_utf8_buffer()
|
||||
cmd_state = CmdState.SEND
|
||||
return true
|
||||
## Отправляет команду "записать в регистры".[br]
|
||||
## [param addr] - Начальный адрес регистров.[br]
|
||||
## [param count] - Данные для записи в регистры от начального адреса.[br]
|
||||
func write(addr: int, data: Array) -> bool:
|
||||
if cmd_state != CmdState.DONE: return false
|
||||
var json_dict = {'code': 'write', 'data': [addr] + data}
|
||||
tx_data = JSON.stringify(json_dict).to_utf8_buffer()
|
||||
cmd_state = CmdState.SEND
|
||||
return true
|
||||
|
||||
## Отправляет команду "читать регистры хранения".[br]
|
||||
## [param addr] - Начальный адрес регистров.[br]
|
||||
## [param count] - Количество регистров от начального адреса.[br]
|
||||
func read_holdind(addr: int, count: int = 1) -> bool:
|
||||
if cmd_state != CmdState.DONE: return false
|
||||
var json_dict = {'code': 'read_holding', 'data': [addr, count]}
|
||||
tx_data = JSON.stringify(json_dict).to_utf8_buffer()
|
||||
cmd_state = CmdState.SEND
|
||||
return true
|
||||
## Отправляет команду "читать регистры хранения".[br]
|
||||
## [param addr] - Начальный адрес регистров.[br]
|
||||
## [param count] - Количество регистров от начального адреса.[br]
|
||||
func read_holdind(addr: int, count: int = 1) -> bool:
|
||||
if cmd_state != CmdState.DONE: return false
|
||||
var json_dict = {'code': 'read_holding', 'data': [addr, count]}
|
||||
tx_data = JSON.stringify(json_dict).to_utf8_buffer()
|
||||
cmd_state = CmdState.SEND
|
||||
return true
|
||||
|
||||
## Отправляет команду "читать регистры входов".[br]
|
||||
## [param addr] - Начальный адрес регистров.[br]
|
||||
## [param count] - Количество регистров от начального адреса.[br]
|
||||
func read_input(addr: int, count: int = 1) -> bool:
|
||||
if cmd_state != CmdState.DONE: return false
|
||||
var json_dict = {'code': 'read_input', 'data': [addr, count]}
|
||||
tx_data = JSON.stringify(json_dict).to_utf8_buffer()
|
||||
cmd_state = CmdState.SEND
|
||||
return true
|
||||
## Отправляет команду "читать регистры входов".[br]
|
||||
## [param addr] - Начальный адрес регистров.[br]
|
||||
## [param count] - Количество регистров от начального адреса.[br]
|
||||
func read_input(addr: int, count: int = 1) -> bool:
|
||||
if cmd_state != CmdState.DONE: return false
|
||||
var json_dict = {'code': 'read_input', 'data': [addr, count]}
|
||||
tx_data = JSON.stringify(json_dict).to_utf8_buffer()
|
||||
cmd_state = CmdState.SEND
|
||||
return true
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
extends Node
|
||||
class_name rep_network extends Node
|
||||
|
||||
|
||||
const PROTOCOL_TYPES: = {'yau07tx': yau07.YaU07, 'jsontx': capsrpb.CapsRpb, 'udp-json-mbcs': modbus.ModbusClient}
|
||||
const TCP_PROTO: = {'5p28': tcp5p28.TCP5P28}
|
||||
|
||||
class Socket extends PacketPeerUDP:
|
||||
func send_to(addr, data):
|
||||
self.set_dest_address(addr[0], addr[1])
|
||||
self.put_packet(data)
|
||||
func send_to(addr, data):
|
||||
self.set_dest_address(addr[0], addr[1])
|
||||
self.put_packet(data)
|
||||
|
||||
|
||||
class SocketTCP extends TCPServer:
|
||||
const RX_TIMEOUT: int = 1000 # Время сброса счётчика принятия части пакета
|
||||
var peerstream: = PacketPeerStream.new()
|
||||
var unit_key: Array # Клюс юнита
|
||||
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 # Размер ожидаемых данных
|
||||
const RX_TIMEOUT: int = 1000 ## Время сброса счётчика принятия части пакета.
|
||||
var peerstream: = PacketPeerStream.new()
|
||||
var unit_key: Array ## Клюс юнита.
|
||||
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):
|
||||
var peer = peerstream.get_stream_peer()
|
||||
peer.put_data(data)
|
||||
func send_to(data):
|
||||
var peer = peerstream.get_stream_peer()
|
||||
peer.put_data(data)
|
||||
|
||||
|
||||
var poll_sockets: Array[Socket]
|
||||
@@ -38,129 +38,129 @@ var logger_page: Node
|
||||
|
||||
|
||||
func create_socket(nm) -> Socket:
|
||||
var addr = repsettings.UnitProfiles[nm][1]
|
||||
var port = repsettings.UnitProfiles[nm][2]
|
||||
var broad = repsettings.UnitProfiles[nm][3]
|
||||
var bind = repsettings.UnitProfiles[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
|
||||
var addr = repsettings.UnitProfiles[nm][1]
|
||||
var port = repsettings.UnitProfiles[nm][2]
|
||||
var broad = repsettings.UnitProfiles[nm][3]
|
||||
var bind = repsettings.UnitProfiles[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 create_tcpsocket(nm) -> SocketTCP:
|
||||
var addr = repsettings.UnitProfiles[nm][1]
|
||||
var port = repsettings.UnitProfiles[nm][2]
|
||||
var sock = SocketTCP.new()
|
||||
sock.unit_key = repsettings.get_unit_key(nm)
|
||||
sock.listen(port, addr)
|
||||
log.message(log.INFO, '%s: сокет:%s:%d привязанный:' % [nm, addr, port])
|
||||
return sock
|
||||
var addr = repsettings.UnitProfiles[nm][1]
|
||||
var port = repsettings.UnitProfiles[nm][2]
|
||||
var sock = SocketTCP.new()
|
||||
sock.unit_key = repsettings.get_unit_key(nm)
|
||||
sock.listen(port, addr)
|
||||
log.message(log.INFO, '%s: сокет:%s:%d привязанный:' % [nm, addr, port])
|
||||
return sock
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
log.info('Модуль работы с сетью готов')
|
||||
poll_sockets.append(create_socket('уарэп-яу07-частный'))
|
||||
poll_sockets.append(create_socket('уарэп-яу07-общий'))
|
||||
poll_sockets.append(create_socket('уарэп-капсрпб-пол'))
|
||||
sock_unicast = poll_sockets[0]
|
||||
sock_capsrpb = poll_sockets[2]
|
||||
log.info('Модуль работы с сетью готов')
|
||||
poll_sockets.append(create_socket('уарэп-яу07-частный'))
|
||||
poll_sockets.append(create_socket('уарэп-яу07-общий'))
|
||||
poll_sockets.append(create_socket('уарэп-капсрпб-пол'))
|
||||
sock_unicast = poll_sockets[0]
|
||||
sock_capsrpb = poll_sockets[2]
|
||||
|
||||
for unit_name in repsettings.UnitProfiles:
|
||||
var setting = repsettings.UnitProfiles[unit_name]
|
||||
var proto = setting[0]
|
||||
if proto in PROTOCOL_TYPES:
|
||||
var unit = PROTOCOL_TYPES[proto].new(unit_name)
|
||||
var unit_key = repsettings.get_unit_key(unit_name)
|
||||
units[unit_key] = unit
|
||||
if logger_page:
|
||||
unit.connect('line_changed', Callable(logger_page, 'on_line_changed').bind(unit_key))
|
||||
unit.connect('command_fail', Callable(logger_page, 'on_command_fail').bind(unit_key))
|
||||
for unit_name in repsettings.UnitProfiles:
|
||||
var setting = repsettings.UnitProfiles[unit_name]
|
||||
var proto = setting[0]
|
||||
if proto in PROTOCOL_TYPES:
|
||||
var unit = PROTOCOL_TYPES[proto].new(unit_name)
|
||||
var unit_key = repsettings.get_unit_key(unit_name)
|
||||
units[unit_key] = unit
|
||||
if logger_page:
|
||||
unit.connect('line_changed', Callable(logger_page, 'on_line_changed').bind(unit_key))
|
||||
unit.connect('command_fail', Callable(logger_page, 'on_command_fail').bind(unit_key))
|
||||
|
||||
if proto in TCP_PROTO:
|
||||
var unit = TCP_PROTO[proto].new(unit_name)
|
||||
var unit_key = repsettings.get_unit_key(unit_name)
|
||||
units_tcp[unit_key] = unit
|
||||
if logger_page:
|
||||
unit.connect('line_changed', Callable(logger_page, 'on_line_changed').bind(unit_key))
|
||||
unit.connect('command_fail', Callable(logger_page, 'on_command_fail').bind(unit_key))
|
||||
if proto in TCP_PROTO:
|
||||
var unit = TCP_PROTO[proto].new(unit_name)
|
||||
var unit_key = repsettings.get_unit_key(unit_name)
|
||||
units_tcp[unit_key] = unit
|
||||
if logger_page:
|
||||
unit.connect('line_changed', Callable(logger_page, 'on_line_changed').bind(unit_key))
|
||||
unit.connect('command_fail', Callable(logger_page, 'on_command_fail').bind(unit_key))
|
||||
|
||||
tcp_sockets.append([create_tcpsocket('уарэп-5п28'), units_tcp[repsettings.get_unit_key('уарэп-5п28')]])
|
||||
tcp_sockets.append([create_tcpsocket('уарэп-5п28'), units_tcp[repsettings.get_unit_key('уарэп-5п28')]])
|
||||
|
||||
for key in units: log.info('%s %s:%d' % [units[key].name, key[0], key[1]])
|
||||
for key in units_tcp: log.info('%s %s:%d' % [units_tcp[key].name, key[0], key[1]])
|
||||
for key in units: log.info('%s %s:%d' % [units[key].name, key[0], key[1]])
|
||||
for key in units_tcp: log.info('%s %s:%d' % [units_tcp[key].name, key[0], key[1]])
|
||||
|
||||
|
||||
func poll_receive(sock: Socket, tick: int) -> bool:
|
||||
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, tick)
|
||||
return false
|
||||
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, tick)
|
||||
return false
|
||||
|
||||
|
||||
func poll_receive_tcp(sock: SocketTCP, tick: int) -> bool:
|
||||
if sock.is_connection_available(): # check if someone's trying to connect
|
||||
var client = sock.take_connection() # accept connection
|
||||
sock.peerstream.set_stream_peer(client) # bind peerstream to new client
|
||||
print_debug('client_is_connected')
|
||||
var peer = sock.peerstream.get_stream_peer()
|
||||
if peer:
|
||||
var peer_len_data = peer.get_available_bytes()
|
||||
if peer_len_data > 0:
|
||||
get_client_data(sock, peer_len_data, peer, tick)
|
||||
if sock.unit_key in units_tcp and sock.rx_all: units_tcp[sock.unit_key].parse(sock.rx_data, tick)
|
||||
return false
|
||||
if sock.is_connection_available(): # check if someone's trying to connect
|
||||
var client = sock.take_connection() # accept connection
|
||||
sock.peerstream.set_stream_peer(client) # bind peerstream to new client
|
||||
print_debug('client_is_connected')
|
||||
var peer = sock.peerstream.get_stream_peer()
|
||||
if peer:
|
||||
var peer_len_data = peer.get_available_bytes()
|
||||
if peer_len_data > 0:
|
||||
get_client_data(sock, peer_len_data, peer, tick)
|
||||
if sock.unit_key in units_tcp and sock.rx_all: units_tcp[sock.unit_key].parse(sock.rx_data, tick)
|
||||
return false
|
||||
|
||||
|
||||
func get_client_data(sock: SocketTCP, peer_len_data, peer, tick):
|
||||
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)
|
||||
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, len_rx):
|
||||
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
|
||||
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:
|
||||
var tick = Time.get_ticks_msec()
|
||||
for addr in units:
|
||||
var unit = units[addr]
|
||||
match unit.process(tick):
|
||||
Error.OK: sock_unicast.send_to(addr, unit.tx_data)
|
||||
Error.FAILED: emit_signal('socket_error', 'ошибка: %s %s:%d' % [unit, addr[0], addr[1]])
|
||||
for sock_unit in tcp_sockets:
|
||||
var sock = sock_unit[0]
|
||||
var unit = sock_unit[1]
|
||||
match unit.process(tick):
|
||||
Error.OK: sock.send_to(unit.tx_data)
|
||||
Error.FAILED: emit_signal('socket_error', 'ошибка: %s' %unit)
|
||||
poll_receive_tcp(sock, tick)
|
||||
poll_sockets.any(func(sock): poll_receive(sock, tick))
|
||||
var tick = Time.get_ticks_msec()
|
||||
for addr in units:
|
||||
var unit = units[addr]
|
||||
match unit.process(tick):
|
||||
Error.OK: sock_unicast.send_to(addr, unit.tx_data)
|
||||
Error.FAILED: emit_signal('socket_error', 'ошибка: %s %s:%d' % [unit, addr[0], addr[1]])
|
||||
for sock_unit in tcp_sockets:
|
||||
var sock = sock_unit[0]
|
||||
var unit = sock_unit[1]
|
||||
match unit.process(tick):
|
||||
Error.OK: sock.send_to(unit.tx_data)
|
||||
Error.FAILED: emit_signal('socket_error', 'ошибка: %s' %unit)
|
||||
poll_receive_tcp(sock, tick)
|
||||
poll_sockets.any(func(sock): poll_receive(sock, tick))
|
||||
|
||||
@@ -1,50 +1,49 @@
|
||||
extends Node
|
||||
|
||||
## Параметры
|
||||
class_name rep_settings extends Node
|
||||
|
||||
## Параметры.
|
||||
|
||||
@export var UnitProfiles: = { \
|
||||
# Название | Протокол | Адрес | Порт | Широковещательное | Привязывать к адресу | Комментарий
|
||||
'уарэп-яу07-частный': ['yau07rx', '10.1.1.2', 50002, false, true, 'IP-адрес на котором принимают частные сообщения от ЯУ-07'],
|
||||
'уарэп-яу07-общий': ['yau07rx', '10.1.1.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 прибора ПРД-Н'],
|
||||
# Название | Протокол | Адрес | Порт | Широковещательное | Привязывать к адресу | Комментарий
|
||||
'уарэп-яу07-частный': ['yau07rx', '10.1.1.2', 50002, false, true, 'IP-адрес на котором принимают частные сообщения от ЯУ-07'],
|
||||
'уарэп-яу07-общий': ['yau07rx', '10.1.1.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 прибора ПРД-Н'],
|
||||
|
||||
# Название | Протокол | Адрес | Порт получения | Комментарий
|
||||
'уарэп-5п28': ['5p28', '127.0.0.1', 50000, 'IP-адрес комплекса 5П-28'],
|
||||
# Название | Протокол | Адрес | Порт получения | Комментарий
|
||||
'уарэп-5п28': ['5p28', '127.0.0.1', 50000, 'IP-адрес комплекса 5П-28'],
|
||||
|
||||
# Название | Протокол | Адрес | Порт получения | Порт отправки | Комментарий
|
||||
'уарэп-щ3': ['udp-json-mbcs', 'localhost', 48000, 44100, 'IP-адрес и порты через которые производят обмен сообщения с драйвером клиента Modbus Serial'],
|
||||
# Название | Протокол | Адрес | Порт получения | Порт отправки | Комментарий
|
||||
'уарэп-щ3': ['udp-json-mbcs', 'localhost', 48000, 44100, 'IP-адрес и порты через которые производят обмен сообщения с драйвером клиента Modbus Serial'],
|
||||
|
||||
# Название | Протокол | Имя порта | Скорость, бод | Чётность | Комментарий
|
||||
'уарэп-спт25-1': ['uart', '/dev/tty2', 115200, false, 'Адрес прибора СПТ-25 (G1)'],
|
||||
'уарэп-спт25-2': ['uart', '/dev/tty3', 115200, false, 'Адрес прибора СПТ-25 (G2)'],
|
||||
# Название | Протокол | Имя порта | Скорость, бод | Чётность | Комментарий
|
||||
'уарэп-спт25-1': ['uart', '/dev/tty2', 115200, false, 'Адрес прибора СПТ-25 (G1)'],
|
||||
'уарэп-спт25-2': ['uart', '/dev/tty3', 115200, false, 'Адрес прибора СПТ-25 (G2)'],
|
||||
}
|
||||
|
||||
## Параметры цели
|
||||
## Параметры цели.
|
||||
@export var ThreatParams = {
|
||||
'time_lost': 5000 ## Время после последнего обновления в мс, через которое цель считается потерянной.
|
||||
}
|
||||
'time_lost': 5000 ## Время после последнего обновления в мс, через которое цель считается потерянной.
|
||||
}
|
||||
|
||||
|
||||
func _ready() -> void: log.info('Модуль настроек готов')
|
||||
|
||||
|
||||
## Возвращает ключ устройства
|
||||
## Возвращает ключ устройства.
|
||||
func get_unit_key(unit_name: String) -> Array:
|
||||
assert(UnitProfiles.has(unit_name), 'ошибка: нет такого устройства \"%s\"' % unit_name)
|
||||
var item = UnitProfiles[unit_name]
|
||||
return [item[1], item[2]]
|
||||
assert(UnitProfiles.has(unit_name), 'ошибка: нет такого устройства \"%s\"' % unit_name)
|
||||
var item = UnitProfiles[unit_name]
|
||||
return [item[1], item[2]]
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
class_name Signaller extends Node
|
||||
|
||||
## Обмен сигналами между узлами. Здесь объявлены сигналы, которые используют
|
||||
## Обмен сигналами между узлами. Здесь объявлены сигналы, которые используют.
|
||||
## два и более узла, из разных файлов. Должен быть помещён в автозагрузку.
|
||||
|
||||
func conn(sgnl: Signal, clbl: Callable): connect(sgnl.get_name(), clbl)
|
||||
|
||||
## Вызывается при переходе в режим [b]Работа[/b]
|
||||
## Вызывается при переходе в режим [b]Работа[/b].
|
||||
signal режим_работа()
|
||||
|
||||
|
||||
## Вызывается при переходе в режим [b]Контроль[/b]
|
||||
## Вызывается при переходе в режим [b]Контроль[/b].
|
||||
signal режим_контроль()
|
||||
|
||||
|
||||
## Вызывается при переходе в режим [b]Журнал[/b]
|
||||
## Вызывается при переходе в режим [b]Журнал[/b].
|
||||
signal режим_журнал()
|
||||
|
||||
|
||||
## Вызывается при переходе в режим [b]ЭМС[/b]
|
||||
## Вызывается при переходе в режим [b]ЭМС[/b].
|
||||
signal режим_эмс()
|
||||
|
||||
|
||||
## Вызывается при переходе в режим [b]Настройка[/b]
|
||||
## Вызывается при переходе в режим [b]Настройка[/b].
|
||||
signal режим_настройки()
|
||||
|
||||
|
||||
## Вызывается, когда оператор переводит программу в режим [b]Автомат выбора цели и помехи[/b]
|
||||
## Вызывается, когда оператор переводит программу в режим [b]Автомат выбора цели и помехи[/b].
|
||||
signal full_auto()
|
||||
|
||||
|
||||
## Вызывается, когда оператор переводит программу в режим [b]Автомат выбора цели[/b]
|
||||
## Вызывается, когда оператор переводит программу в режим [b]Автомат выбора цели[/b].
|
||||
signal threat_auto()
|
||||
|
||||
|
||||
## Вызывается, когда оператор переводит программу в режим [b]Автомат выбора помехи[/b]
|
||||
## Вызывается, когда оператор переводит программу в режим [b]Автомат выбора помехи[/b].
|
||||
signal interfer_auto()
|
||||
|
||||
|
||||
## Вызывается, когда оператор переводит программу в режим [b]Ручной[/b]
|
||||
## Вызывается, когда оператор переводит программу в режим [b]Ручной[/b].
|
||||
signal manual_control()
|
||||
|
||||
|
||||
@@ -59,21 +59,21 @@ signal full_screen(id: int)
|
||||
|
||||
|
||||
## Вызывается, когда пользователь выбирает цель.[br]
|
||||
## [param th_id] - Отметка цели на экране
|
||||
## [param th_id] - Отметка цели на экране.
|
||||
signal rto_threat_sel (th_id: int)
|
||||
|
||||
|
||||
## Вызывается, когда пользователь нажимает на значёк цели.[br]
|
||||
## [param th_id] - Отметка цели на экране
|
||||
## [param th_id] - Отметка цели на экране.
|
||||
signal bip_pressed (th_id: int)
|
||||
|
||||
|
||||
## Вызывается, когда пользователь снимает выделение с цели.[br]
|
||||
## [param th_id] - Отметка цели на экране
|
||||
## [param th_id] - Отметка цели на экране.
|
||||
signal rto_threat_unsel (th_id: int)
|
||||
|
||||
|
||||
## Вызывается, когда пользователь снимает выделение со всех целей
|
||||
## Вызывается, когда пользователь снимает выделение со всех целей.
|
||||
signal rto_threat_unsel_all ()
|
||||
|
||||
|
||||
@@ -100,32 +100,32 @@ signal interfer_new (ecm: interfer.Interfer)
|
||||
signal interfer_off (ecm: interfer.Interfer, ecms: Dictionary, thrs: Dictionary)
|
||||
|
||||
|
||||
## Вызывается при нажатии отключить все помехи
|
||||
## Вызывается при нажатии отключить все помехи.
|
||||
signal interfer_off_all ()
|
||||
|
||||
|
||||
## Вызывается при получении внешнего целеуказания
|
||||
## Вызывается при получении внешнего целеуказания.
|
||||
## [param interfer_params] - Параметры полученной помехи от 5П-28.[br]
|
||||
signal interfer_rcv(interfer_params: Array)
|
||||
|
||||
|
||||
## Вызывается, когда отключается действующая помеха.[br]
|
||||
## [param ecm] - Выбранная помеха
|
||||
## [param ecm] - Выбранная помеха.
|
||||
signal interfer_selected (ecm: interfer.Interfer)
|
||||
|
||||
|
||||
## Вызывается, когда отключается выбираем помеху по сектору в таблице.[br]
|
||||
## [param ecm] - Выбранная помеха
|
||||
## [param ecm] - Выбранная помеха.
|
||||
signal fs_selected(ecm: interfer.Interfer)
|
||||
|
||||
|
||||
## Вызывается при запросе изменения уровня детализации карты.[br]
|
||||
## [param zoom] - Вновь установленный уровень детализации
|
||||
## [param zoom] - Вновь установленный уровень детализации.
|
||||
signal zoom_changed(zoom: int)
|
||||
|
||||
|
||||
## Вызывается при завершении изменения уровня детализации карты.[br]
|
||||
## [param zoom] - Вновь установленный уровень детализации
|
||||
## [param zoom] - Вновь установленный уровень детализации.
|
||||
signal zoom_complete(zoom: int)
|
||||
|
||||
|
||||
@@ -135,5 +135,5 @@ signal map_coords_changed(lan: float, lat: float)
|
||||
|
||||
|
||||
## Вызывается при изменении размера изображения для отображения карты.[br]
|
||||
## [param mode] - Вновь установленный режим
|
||||
## [param mode] - Вновь установленный режим.
|
||||
signal map_mode_changed(mode: int)
|
||||
|
||||
@@ -1,193 +1,193 @@
|
||||
extends Node
|
||||
class_name tcp5_p28 extends Node
|
||||
|
||||
## Реализация "Протокол информационного сопряжения
|
||||
## СПО АСУ изделия «МП‑550» с СПО 5П-28"
|
||||
## Реализация "Протокол информационного сопряжения.
|
||||
## СПО АСУ изделия «МП‑550» с СПО 5П-28".
|
||||
|
||||
|
||||
const ONLINE_TIMEOUT = 5000 ## Время ожидания пакета от 5П-28, мс
|
||||
const BUFFER_SIZE = 2048 ## Размер приёмного буфера для датаграмм
|
||||
const ONLINE_TIMEOUT = 5000 ## Время ожидания пакета от 5П-28, мс.
|
||||
const BUFFER_SIZE = 2048 ## Размер приёмного буфера для датаграмм.
|
||||
|
||||
## Тип модуляции для запаковки в пакет для 5П-28
|
||||
## Тип модуляции для запаковки в пакет для 5П-28.
|
||||
const MOD_TYPES: Array = ['',
|
||||
'am',
|
||||
'ook',
|
||||
'ask',
|
||||
'fm',
|
||||
'qpsk',
|
||||
'oqpsk',
|
||||
'pi4qpsk',
|
||||
'qam16',
|
||||
'qam32',
|
||||
'qam64',
|
||||
'qam128',
|
||||
'qam256',
|
||||
'qam512',
|
||||
'cpfsk',
|
||||
'psk',
|
||||
'ofdm',]
|
||||
'am',
|
||||
'ook',
|
||||
'ask',
|
||||
'fm',
|
||||
'qpsk',
|
||||
'oqpsk',
|
||||
'pi4qpsk',
|
||||
'qam16',
|
||||
'qam32',
|
||||
'qam64',
|
||||
'qam128',
|
||||
'qam256',
|
||||
'qam512',
|
||||
'cpfsk',
|
||||
'psk',
|
||||
'ofdm',]
|
||||
|
||||
const CU_STATE: Dictionary = {
|
||||
0:2, # Подготовка к выполнению
|
||||
1:1, # Выполняется
|
||||
2:9, # Ошибка в команде
|
||||
3:7, # Занят выполнением другого ЦУ
|
||||
4:9, # Неисправность
|
||||
}
|
||||
0:2, # Подготовка к выполнению
|
||||
1:1, # Выполняется
|
||||
2:9, # Ошибка в команде
|
||||
3:7, # Занят выполнением другого ЦУ
|
||||
4:9, # Неисправность
|
||||
}
|
||||
|
||||
class TCP5P28:
|
||||
const PACK_TYPE_CMD: int = 1
|
||||
const PACK_TYPE_RES: int = 2
|
||||
const CMD_TYPE_STATE: int = 1
|
||||
const CMD_TYPE_TH: int = 2
|
||||
const CMD_TYPE_IN: int = 3
|
||||
const PACK_TYPE_CMD: int = 1
|
||||
const PACK_TYPE_RES: int = 2
|
||||
const CMD_TYPE_STATE: int = 1
|
||||
const CMD_TYPE_TH: int = 2
|
||||
const CMD_TYPE_IN: int = 3
|
||||
|
||||
signal line_changed(unit: TCP5P28) ## Сигнал состояние связи изменилось
|
||||
signal data_received(unit: TCP5P28) ## Сигнал данные приняты
|
||||
signal command_fail(unit: TCP5P28) ## Сигнал при не выполнении команды
|
||||
signal parse_error(unit: TCP5P28, msg: String) ## Сигнал ошибки разбора сообщения
|
||||
signal get_threats(unit: TCP5P28) ## Сигнал запрос целей
|
||||
signal get_interfers(unit: TCP5P28) ## Запрос состояния выполнения целеуказания
|
||||
signal line_changed(unit: TCP5P28) ## Сигнал состояние связи изменилось.
|
||||
signal data_received(unit: TCP5P28) ## Сигнал данные приняты.
|
||||
signal command_fail(unit: TCP5P28) ## Сигнал при не выполнении команды.
|
||||
signal parse_error(unit: TCP5P28, msg: String) ## Сигнал ошибки разбора сообщения.
|
||||
signal get_threats(unit: TCP5P28) ## Сигнал запрос целей.
|
||||
signal get_interfers(unit: TCP5P28) ## Запрос состояния выполнения целеуказания.
|
||||
|
||||
var online: = false ## Состояние связи с источником сообщений
|
||||
var name: String ## Имя экземпляра
|
||||
var rx_tick: = 0 ## Тик время последнего приёма, мс
|
||||
var tx_data: = PackedByteArray() ## Пакет для отправки
|
||||
var tx_stack: Array ## Массив пакетов для отправки
|
||||
var online: = false ## Состояние связи с источником сообщений.
|
||||
var name: String ## Имя экземпляра.
|
||||
var rx_tick: = 0 ## Тик время последнего приёма, мс.
|
||||
var tx_data: = PackedByteArray() ## Пакет для отправки.
|
||||
var tx_stack: Array ## Массив пакетов для отправки.
|
||||
|
||||
func _to_string() -> String: return String('капсрпб: "%s" %s ' % [self.name, ['отключен', 'на связи'][int(online)]])
|
||||
func _init(nm): self.name = nm
|
||||
func _to_string() -> String: return String('капсрпб: "%s" %s ' % [self.name, ['отключен', 'на связи'][int(online)]])
|
||||
func _init(nm): self.name = nm
|
||||
|
||||
func parse(data: PackedByteArray, now_tick: int):
|
||||
rx_tick = now_tick
|
||||
if not online:
|
||||
online = true
|
||||
emit_signal('line_changed', self)
|
||||
var pack_type = data.decode_u8(2)
|
||||
if pack_type == PACK_TYPE_CMD:
|
||||
var cmd_type = data.decode_u8(8)
|
||||
if cmd_type == CMD_TYPE_TH:
|
||||
emit_signal('get_threats')
|
||||
if cmd_type == CMD_TYPE_STATE:
|
||||
emit_signal('get_interfers')
|
||||
var external_cu = ProjectSettings.get_setting('application/config/external_cu', false)
|
||||
if cmd_type == CMD_TYPE_IN and external_cu:
|
||||
set_interfer(data)
|
||||
func parse(data: PackedByteArray, now_tick: int):
|
||||
rx_tick = now_tick
|
||||
if not online:
|
||||
online = true
|
||||
emit_signal('line_changed', self)
|
||||
var pack_type = data.decode_u8(2)
|
||||
if pack_type == PACK_TYPE_CMD:
|
||||
var cmd_type = data.decode_u8(8)
|
||||
if cmd_type == CMD_TYPE_TH:
|
||||
emit_signal('get_threats')
|
||||
if cmd_type == CMD_TYPE_STATE:
|
||||
emit_signal('get_interfers')
|
||||
var external_cu = ProjectSettings.get_setting('application/config/external_cu', false)
|
||||
if cmd_type == CMD_TYPE_IN and external_cu:
|
||||
set_interfer(data)
|
||||
|
||||
func process(now_tick: int):
|
||||
if online and ((now_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 process(now_tick: int):
|
||||
if online and ((now_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 pack_threats(ths):
|
||||
var data = PackedByteArray()
|
||||
var data_len = 4 + len(ths) * 80 # длинна блока данных в байтах
|
||||
var tick = Time.get_ticks_msec()
|
||||
data.resize(4)
|
||||
data.encode_u16(0, 0) # Код ошибки
|
||||
data.encode_u16(2, len(ths)) # Количество целей
|
||||
for th in ths.values():
|
||||
data.append_array(get_threats_data(th, int(tick)))
|
||||
var data_to_send: PackedByteArray = create_header(data_len)
|
||||
data_to_send.append_array(data)
|
||||
tx_stack.append(data_to_send)
|
||||
func pack_threats(ths):
|
||||
var data = PackedByteArray()
|
||||
var data_len = 4 + len(ths) * 80 # длинна блока данных в байтах
|
||||
var tick = Time.get_ticks_msec()
|
||||
data.resize(4)
|
||||
data.encode_u16(0, 0) # Код ошибки
|
||||
data.encode_u16(2, len(ths)) # Количество целей
|
||||
for th in ths.values():
|
||||
data.append_array(get_threats_data(th, int(tick)))
|
||||
var data_to_send: PackedByteArray = create_header(data_len)
|
||||
data_to_send.append_array(data)
|
||||
tx_stack.append(data_to_send)
|
||||
|
||||
func pack_interfers(interfers, ecms):
|
||||
var data = PackedByteArray()
|
||||
var data_len = 12 # длинна блока данных в байтах
|
||||
data.resize(data_len)
|
||||
data.encode_u16(0, 0) # Код ошибки
|
||||
data.encode_u16(2, len(interfers)) # Количество целей
|
||||
data.encode_u32(4, 0) # Состояние УА-РЕП
|
||||
data.encode_u32(8, 0) # Состояние линий связи
|
||||
for id in interfers.values():
|
||||
var cu_data: PackedByteArray = []
|
||||
cu_data.resize(4)
|
||||
var cu = ecms[id]
|
||||
cu_data.encode_u16(0, cu.ispp)
|
||||
var state: int
|
||||
if CU_STATE.has(cu.svk):
|
||||
state = CU_STATE[cu.svk]
|
||||
else:
|
||||
state = 9
|
||||
cu_data.encode_u8(2, state) # Состояние выполнения команды
|
||||
cu_data.encode_u8(3, 0xFF) # Эффективность работы помехи
|
||||
data.append_array(cu_data)
|
||||
var data_to_send: PackedByteArray = create_header(data_len + 4 * len(interfers))
|
||||
data_to_send.append_array(data)
|
||||
tx_stack.append(data_to_send)
|
||||
func pack_interfers(interfers, ecms):
|
||||
var data = PackedByteArray()
|
||||
var data_len = 12 # длинна блока данных в байтах
|
||||
data.resize(data_len)
|
||||
data.encode_u16(0, 0) # Код ошибки
|
||||
data.encode_u16(2, len(interfers)) # Количество целей
|
||||
data.encode_u32(4, 0) # Состояние УА-РЕП
|
||||
data.encode_u32(8, 0) # Состояние линий связи
|
||||
for id in interfers.values():
|
||||
var cu_data: PackedByteArray = []
|
||||
cu_data.resize(4)
|
||||
var cu = ecms[id]
|
||||
cu_data.encode_u16(0, cu.ispp)
|
||||
var state: int
|
||||
if CU_STATE.has(cu.svk):
|
||||
state = CU_STATE[cu.svk]
|
||||
else:
|
||||
state = 9
|
||||
cu_data.encode_u8(2, state) # Состояние выполнения команды
|
||||
cu_data.encode_u8(3, 0xFF) # Эффективность работы помехи
|
||||
data.append_array(cu_data)
|
||||
var data_to_send: PackedByteArray = create_header(data_len + 4 * len(interfers))
|
||||
data_to_send.append_array(data)
|
||||
tx_stack.append(data_to_send)
|
||||
|
||||
func create_header(data_len):
|
||||
var head_data = PackedByteArray()
|
||||
head_data.resize(8) # Размер заголовка
|
||||
head_data.encode_u16(0, 0) # Код ошибки
|
||||
head_data.encode_u8(2, 2) # Тип пакета, ответ на запрос
|
||||
head_data.encode_u8(3, 5) # Версия протокола, всегда 5
|
||||
head_data.encode_u32(4, data_len) # Длинна пакета данных
|
||||
return head_data
|
||||
func create_header(data_len):
|
||||
var head_data = PackedByteArray()
|
||||
head_data.resize(8) # Размер заголовка
|
||||
head_data.encode_u16(0, 0) # Код ошибки
|
||||
head_data.encode_u8(2, 2) # Тип пакета, ответ на запрос
|
||||
head_data.encode_u8(3, 5) # Версия протокола, всегда 5
|
||||
head_data.encode_u32(4, data_len) # Длинна пакета данных
|
||||
return head_data
|
||||
|
||||
func get_threats_data(th, tick):
|
||||
var th_data = PackedByteArray()
|
||||
th_data.resize(80) # Количество байт в массиве
|
||||
th_data.encode_u64(0, tick)
|
||||
var flags: int = 0 # с 0 по 7 бит рекомендованная помеха
|
||||
flags |= 0 << 8 # Флаг рекомендуемой помехи
|
||||
flags |= int(th.fflags['aoa']) << 9 # Флаг доставерности пеленга
|
||||
flags |= int(th.fflags['alt']) << 10 # Флаг доставерности высоты
|
||||
flags |= int(th.fflags['power']) << 11 # Флаг доставерности мощности
|
||||
flags |= int(th.fflags['baud']) << 12 # Флаг доставерности ск. мод.
|
||||
flags |= int(th.fflags['slon']) << 13 # Флаг доставерности долготы ст. позиции
|
||||
flags |= int(th.fflags['slat']) << 14 # Флаг доставерности широты ст. позиции
|
||||
flags |= int(th.fflags['lon']) << 15 # Флаг доставерности долготы
|
||||
flags |= int(th.fflags['lat']) << 16 # Флаг доставерности широты
|
||||
flags |= int(0) << 30 # Флаг признак назначения помехи на цель
|
||||
flags |= int(0) << 31 # Флаг признак назначения опасной цель
|
||||
th_data.encode_u32(8, flags) # Флаги
|
||||
th_data.encode_u16(12, th.id) # Идентификатор объекта
|
||||
th_data.encode_u16(14, int(round(th.aoa/0.1))) # Пеленг объекта
|
||||
th_data.encode_u16(16, int(th.alt)) # Высота объекта
|
||||
th_data.encode_u16(18, int(th.freq)) # Частота объекта
|
||||
th_data.encode_u16(20, int(th.width)) # Ширина частотной полосы объекта
|
||||
th_data.encode_u8(22, int(th.power)) # Мощность излучения объекта
|
||||
var mod = MOD_TYPES.find(th.tmod)
|
||||
if mod == -1: mod = 0
|
||||
th_data.encode_u8(23, int(mod)) # Тип модуляции
|
||||
th_data.encode_u32(24, int(th.baud)) # Скорость модуляции, бод
|
||||
to_cp866(th.proto, th_data)
|
||||
var c1 = pow(2, 30) / 180.0
|
||||
th_data.encode_s32(64, int(th.slon * c1))
|
||||
th_data.encode_s32(68, int(th.slat * c1))
|
||||
th_data.encode_s32(72, int(th.lon * c1))
|
||||
th_data.encode_s32(76, int(th.lat * c1))
|
||||
return th_data
|
||||
func get_threats_data(th, tick):
|
||||
var th_data = PackedByteArray()
|
||||
th_data.resize(80) # Количество байт в массиве
|
||||
th_data.encode_u64(0, tick)
|
||||
var flags: int = 0 # с 0 по 7 бит рекомендованная помеха
|
||||
flags |= 0 << 8 # Флаг рекомендуемой помехи
|
||||
flags |= int(th.fflags['aoa']) << 9 # Флаг доставерности пеленга
|
||||
flags |= int(th.fflags['alt']) << 10 # Флаг доставерности высоты
|
||||
flags |= int(th.fflags['power']) << 11 # Флаг доставерности мощности
|
||||
flags |= int(th.fflags['baud']) << 12 # Флаг доставерности ск. мод.
|
||||
flags |= int(th.fflags['slon']) << 13 # Флаг доставерности долготы ст. позиции
|
||||
flags |= int(th.fflags['slat']) << 14 # Флаг доставерности широты ст. позиции
|
||||
flags |= int(th.fflags['lon']) << 15 # Флаг доставерности долготы
|
||||
flags |= int(th.fflags['lat']) << 16 # Флаг доставерности широты
|
||||
flags |= int(0) << 30 # Флаг признак назначения помехи на цель
|
||||
flags |= int(0) << 31 # Флаг признак назначения опасной цель
|
||||
th_data.encode_u32(8, flags) # Флаги
|
||||
th_data.encode_u16(12, th.id) # Идентификатор объекта
|
||||
th_data.encode_u16(14, int(round(th.aoa/0.1))) # Пеленг объекта
|
||||
th_data.encode_u16(16, int(th.alt)) # Высота объекта
|
||||
th_data.encode_u16(18, int(th.freq)) # Частота объекта
|
||||
th_data.encode_u16(20, int(th.width)) # Ширина частотной полосы объекта
|
||||
th_data.encode_u8(22, int(th.power)) # Мощность излучения объекта
|
||||
var mod = MOD_TYPES.find(th.tmod)
|
||||
if mod == -1: mod = 0
|
||||
th_data.encode_u8(23, int(mod)) # Тип модуляции
|
||||
th_data.encode_u32(24, int(th.baud)) # Скорость модуляции, бод
|
||||
to_cp866(th.proto, th_data)
|
||||
var c1 = pow(2, 30) / 180.0
|
||||
th_data.encode_s32(64, int(th.slon * c1))
|
||||
th_data.encode_s32(68, int(th.slat * c1))
|
||||
th_data.encode_s32(72, int(th.lon * c1))
|
||||
th_data.encode_s32(76, int(th.lat * c1))
|
||||
return th_data
|
||||
|
||||
func to_cp866(proto: String, th_data):
|
||||
var cp866_proto: PackedByteArray = proto.to_ascii_buffer()
|
||||
cp866_proto.resize(36)
|
||||
for i in len(cp866_proto):
|
||||
th_data[28 + i] = cp866_proto[i]
|
||||
func to_cp866(proto: String, th_data):
|
||||
var cp866_proto: PackedByteArray = proto.to_ascii_buffer()
|
||||
cp866_proto.resize(36)
|
||||
for i in len(cp866_proto):
|
||||
th_data[28 + i] = cp866_proto[i]
|
||||
|
||||
func set_interfer(data):
|
||||
var mode = data.decode_u8(9)
|
||||
var id = data.decode_u16(10)
|
||||
var aoa = float(data.decode_u16(12)) / 10
|
||||
var ela = float(data.decode_u16(14)) / 10
|
||||
var freq = data.decode_u16(16)
|
||||
var width = data.decode_u16(18)
|
||||
var interfer_params: Array = [mode, id, aoa, ela, freq, width]
|
||||
signaller.emit_signal('interfer_rcv', interfer_params)
|
||||
func set_interfer(data):
|
||||
var mode = data.decode_u8(9)
|
||||
var id = data.decode_u16(10)
|
||||
var aoa = float(data.decode_u16(12)) / 10
|
||||
var ela = float(data.decode_u16(14)) / 10
|
||||
var freq = data.decode_u16(16)
|
||||
var width = data.decode_u16(18)
|
||||
var interfer_params: Array = [mode, id, aoa, ela, freq, width]
|
||||
signaller.emit_signal('interfer_rcv', interfer_params)
|
||||
|
||||
func on_interfer_accept(err: bool):
|
||||
var data_tx = PackedByteArray()
|
||||
var data_len = 2 # длинна блока данных в байтах
|
||||
data_tx.resize(data_len)
|
||||
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)
|
||||
func on_interfer_accept(err: bool):
|
||||
var data_tx = PackedByteArray()
|
||||
var data_len = 2 # длинна блока данных в байтах
|
||||
data_tx.resize(data_len)
|
||||
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)
|
||||
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
extends Node
|
||||
|
||||
## Работа с целями
|
||||
## Работа с целями.
|
||||
|
||||
|
||||
## Цель
|
||||
class Threat:
|
||||
var alt: float ## Текущая высота, метры.
|
||||
var aoa: float ## Курсовой угол на источник сигнала, градусы.
|
||||
var atick: float ## Тик обнаружения.
|
||||
var baud: float ## Модуляционная скорость.
|
||||
var fflags: Dictionary ## Флаги достоверности полей.
|
||||
var freq: float ## Частота несущей или центральная частота, МГц.
|
||||
var freqm: String ## Режим смены частоты.
|
||||
var id: int ## Идентификатор цели.
|
||||
var lat: float ## Текущие координаты, широта в градусах.
|
||||
var lon: float ## Текущие координаты, долгота в градусах.
|
||||
var power: float ## Уровень принимаемого сигнала, дБм.
|
||||
var proto: String ## Тип протокола источника сигнала.
|
||||
var rkrp: String ## Рекомендуемый режим помехи.
|
||||
var rparams: String ## Рекомендуемые параметры помехи.
|
||||
var salt: float ## Координаты старта, высота от уровня моря, м.
|
||||
var slat: float ## Координаты старта, широта в градусах.
|
||||
var slon: float ## Координаты старта, долгота в градусах.
|
||||
var tick: int ## Тик время приёма сигнала, мс.
|
||||
var tick_rx: int ## Тик время обновления цели, мс.
|
||||
var tmod: String ## Тип модуляции.
|
||||
var width: float ## Ширина занимаемого диапазона частот, МГц.
|
||||
var selected: bool ## Флаг, что цель выбрана
|
||||
var alt: float ## Текущая высота, метры.
|
||||
var aoa: float ## Курсовой угол на источник сигнала, градусы.
|
||||
var atick: float ## Тик обнаружения.
|
||||
var baud: float ## Модуляционная скорость.
|
||||
var fflags: Dictionary ## Флаги достоверности полей.
|
||||
var freq: float ## Частота несущей или центральная частота, МГц.
|
||||
var freqm: String ## Режим смены частоты.
|
||||
var id: int ## Идентификатор цели.
|
||||
var lat: float ## Текущие координаты, широта в градусах.
|
||||
var lon: float ## Текущие координаты, долгота в градусах.
|
||||
var power: float ## Уровень принимаемого сигнала, дБм.
|
||||
var proto: String ## Тип протокола источника сигнала.
|
||||
var rkrp: String ## Рекомендуемый режим помехи.
|
||||
var rparams: String ## Рекомендуемые параметры помехи.
|
||||
var salt: float ## Координаты старта, высота от уровня моря, м.
|
||||
var slat: float ## Координаты старта, широта в градусах.
|
||||
var slon: float ## Координаты старта, долгота в градусах.
|
||||
var tick: int ## Тик время приёма сигнала, мс.
|
||||
var tick_rx: int ## Тик время обновления цели, мс.
|
||||
var tmod: String ## Тип модуляции.
|
||||
var width: float ## Ширина занимаемого диапазона частот, МГц.
|
||||
var selected: bool ## Флаг, что цель выбрана.
|
||||
|
||||
func _init(): clear_fflags()
|
||||
func _to_string() -> String: return 'номер: %d пеленг: %0.1f частота: %0.1f МГц' % [id, aoa, freq]
|
||||
func clear_fflags(): tools.get_members_names(self).any(func(vn): fflags[vn] = false)
|
||||
func _init(): clear_fflags()
|
||||
func _to_string() -> String: return 'номер: %d пеленг: %0.1f частота: %0.1f МГц' % [id, aoa, freq]
|
||||
func clear_fflags(): tools.get_members_names(self).any(func(vn): fflags[vn] = false)
|
||||
|
||||
func set_from_dic(dic: Dictionary):
|
||||
var items: = fflags.keys().filter(func(vn): return dic.has(vn))
|
||||
items.any(func(vn): set(vn, dic[vn]); fflags[vn] = true; return false)
|
||||
func set_from_dic(dic: Dictionary):
|
||||
var items: = fflags.keys().filter(func(vn): return dic.has(vn))
|
||||
items.any(func(vn): set(vn, dic[vn]); fflags[vn] = true; return false)
|
||||
|
||||
|
||||
signal threat_new(th: Threat)
|
||||
@@ -44,37 +44,37 @@ signal threats_resized(th: Dictionary)
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
log.info('Модуль обработки целей готов')
|
||||
var threats = {} ## Список целей. Индекс - <номер цели>
|
||||
var unit_key = repsettings.get_unit_key('уарэп-капсрпб-отп')
|
||||
var unit = repnetwork.units[unit_key]
|
||||
var unit_5p28_key = repsettings.get_unit_key('уарэп-5п28')
|
||||
var unit_5p28 = repnetwork.units_tcp[unit_5p28_key]
|
||||
var timer_check_lost: = Timer.new()
|
||||
add_child(timer_check_lost)
|
||||
unit.connect('data_received', Callable(self, 'on_data_capsrpb_received').bind(threats))
|
||||
unit_5p28.connect('get_threats', Callable(self, 'on_get_threats').bind(unit_5p28, threats))
|
||||
timer_check_lost.connect('timeout', Callable(self, 'on_timer_check_lost').bind(repsettings.ThreatParams.time_lost, threats))
|
||||
timer_check_lost.start(repsettings.ThreatParams.time_lost / 1000.0)
|
||||
signaller.connect('rto_threat_sel', Callable(self, 'on_rto_threat_sel').bind(threats))
|
||||
signaller.connect('rto_threat_unsel', Callable(self, 'on_rto_threat_unsel').bind(threats))
|
||||
signaller.connect('rto_threat_unsel_all', Callable(self, 'on_rto_threat_unsel_all').bind(threats))
|
||||
signaller.connect('threat_selected', Callable(self, 'on_threat_selected').bind(threats))
|
||||
signaller.connect('interfer_init', Callable(self, 'on_interfer_init').bind(threats))
|
||||
log.info('Модуль обработки целей готов')
|
||||
var threats = {} ## Список целей. Индекс - <номер цели>
|
||||
var unit_key = repsettings.get_unit_key('уарэп-капсрпб-отп')
|
||||
var unit = repnetwork.units[unit_key]
|
||||
var unit_5p28_key = repsettings.get_unit_key('уарэп-5п28')
|
||||
var unit_5p28 = repnetwork.units_tcp[unit_5p28_key]
|
||||
var timer_check_lost: = Timer.new()
|
||||
add_child(timer_check_lost)
|
||||
unit.connect('data_received', Callable(self, 'on_data_capsrpb_received').bind(threats))
|
||||
unit_5p28.connect('get_threats', Callable(self, 'on_get_threats').bind(unit_5p28, threats))
|
||||
timer_check_lost.connect('timeout', Callable(self, 'on_timer_check_lost').bind(repsettings.ThreatParams.time_lost, threats))
|
||||
timer_check_lost.start(repsettings.ThreatParams.time_lost / 1000.0)
|
||||
signaller.connect('rto_threat_sel', Callable(self, 'on_rto_threat_sel').bind(threats))
|
||||
signaller.connect('rto_threat_unsel', Callable(self, 'on_rto_threat_unsel').bind(threats))
|
||||
signaller.connect('rto_threat_unsel_all', Callable(self, 'on_rto_threat_unsel_all').bind(threats))
|
||||
signaller.connect('threat_selected', Callable(self, 'on_threat_selected').bind(threats))
|
||||
signaller.connect('interfer_init', Callable(self, 'on_interfer_init').bind(threats))
|
||||
|
||||
## Периодически удаляет устаревшие цели
|
||||
## Периодически удаляет устаревшие цели.
|
||||
func on_timer_check_lost(time_lost: int, threats: Dictionary):
|
||||
var tick = Time.get_ticks_msec()
|
||||
var sz: = threats.size()
|
||||
for th in threats.values():
|
||||
if (tick - th.tick_rx) >= time_lost:
|
||||
threats.erase(th.id)
|
||||
call_deferred('emit_signal', 'threat_lost', th)
|
||||
if sz != threats.size():
|
||||
call_deferred('emit_signal', 'threats_resized', threats)
|
||||
var tick = Time.get_ticks_msec()
|
||||
var sz: = threats.size()
|
||||
for th in threats.values():
|
||||
if (tick - th.tick_rx) >= time_lost:
|
||||
threats.erase(th.id)
|
||||
call_deferred('emit_signal', 'threat_lost', th)
|
||||
if sz != threats.size():
|
||||
call_deferred('emit_signal', 'threats_resized', threats)
|
||||
|
||||
|
||||
## отправляет словарь целей в юнит, для запаковки и отправки в 5П28
|
||||
## отправляет словарь целей в юнит, для запаковки и отправки в 5П28.
|
||||
func on_get_threats(unit, threats): unit.pack_threats(threats)
|
||||
|
||||
|
||||
@@ -82,56 +82,56 @@ func on_get_threats(unit, threats): unit.pack_threats(threats)
|
||||
func on_rto_threat_unsel(th_id, threats): threats[th_id].selected = false
|
||||
|
||||
|
||||
## Снимает выделение со всех целей
|
||||
## Снимает выделение со всех целей.
|
||||
func on_rto_threat_unsel_all(threats):
|
||||
for th in threats.values():
|
||||
signaller.emit_signal('rto_threat_unsel', th.id)
|
||||
for th in threats.values():
|
||||
signaller.emit_signal('rto_threat_unsel', th.id)
|
||||
|
||||
|
||||
## Выбирает цель, если нажать по отметке цели.
|
||||
func on_rto_threat_sel(th_id, threats): on_threat_selected(threats[th_id], threats)
|
||||
|
||||
|
||||
## Выбирает цель, если выбрать в таблице
|
||||
## Выбирает цель, если выбрать в таблице.
|
||||
func on_threat_selected(th, threats):
|
||||
for threat in threats.values():
|
||||
threat.selected = false
|
||||
th.selected = true
|
||||
for threat in threats.values():
|
||||
threat.selected = false
|
||||
th.selected = true
|
||||
|
||||
|
||||
## Формирует список выбранных целей для включения помехи
|
||||
## Формирует список выбранных целей для включения помехи.
|
||||
func on_interfer_init(btn, fs_arr, threats):
|
||||
var sel_threats: Array = []
|
||||
for threat in threats.values():
|
||||
if threat.selected:
|
||||
sel_threats.append(threat)
|
||||
if len(sel_threats) or (len(fs_arr)):
|
||||
signaller.emit_signal('interfer_create', btn, sel_threats, fs_arr)
|
||||
var sel_threats: Array = []
|
||||
for threat in threats.values():
|
||||
if threat.selected:
|
||||
sel_threats.append(threat)
|
||||
if len(sel_threats) or (len(fs_arr)):
|
||||
signaller.emit_signal('interfer_create', btn, sel_threats, fs_arr)
|
||||
|
||||
|
||||
## Производит приём целей
|
||||
## Производит приём целей.
|
||||
func on_data_capsrpb_received(unit: capsrpb.CapsRpb, threats: Dictionary):
|
||||
if not unit.json_dic.has('ts'): return
|
||||
if unit.json_dic['ts'] != 5: return
|
||||
if not unit.json_dic.has('mis'): return
|
||||
if not unit.json_dic.has('ts'): return
|
||||
if unit.json_dic['ts'] != 5: return
|
||||
if not unit.json_dic.has('mis'): return
|
||||
|
||||
var mis = unit.json_dic['mis']
|
||||
var sz: = threats.size()
|
||||
for dic_th in mis:
|
||||
if dic_th is Dictionary:
|
||||
if dic_th.has('id'):
|
||||
var id = int(dic_th['id'])
|
||||
if threats.has(id):
|
||||
var th = threats[id]
|
||||
th.clear_fflags()
|
||||
th.set_from_dic(dic_th)
|
||||
th.tick_rx = unit.tick
|
||||
call_deferred('emit_signal', 'threat_update', th)
|
||||
else:
|
||||
var th = Threat.new()
|
||||
th.set_from_dic(dic_th)
|
||||
threats[id] = th
|
||||
th.tick_rx = unit.tick
|
||||
call_deferred('emit_signal', 'threat_new', th)
|
||||
if sz != threats.size():
|
||||
call_deferred('emit_signal', 'threats_resized', threats)
|
||||
var mis = unit.json_dic['mis']
|
||||
var sz: = threats.size()
|
||||
for dic_th in mis:
|
||||
if dic_th is Dictionary:
|
||||
if dic_th.has('id'):
|
||||
var id = int(dic_th['id'])
|
||||
if threats.has(id):
|
||||
var th = threats[id]
|
||||
th.clear_fflags()
|
||||
th.set_from_dic(dic_th)
|
||||
th.tick_rx = unit.tick
|
||||
call_deferred('emit_signal', 'threat_update', th)
|
||||
else:
|
||||
var th = Threat.new()
|
||||
th.set_from_dic(dic_th)
|
||||
threats[id] = th
|
||||
th.tick_rx = unit.tick
|
||||
call_deferred('emit_signal', 'threat_new', th)
|
||||
if sz != threats.size():
|
||||
call_deferred('emit_signal', 'threats_resized', threats)
|
||||
|
||||
122
scripts/tools.gd
122
scripts/tools.gd
@@ -1,10 +1,10 @@
|
||||
@tool
|
||||
extends Node
|
||||
class_name Tools extends Node
|
||||
|
||||
## Простые часто используемые функции
|
||||
## Простые часто используемые функции.
|
||||
|
||||
|
||||
## Возвращает округлённое значение [param v] с точностью [param a]
|
||||
## Возвращает округлённое значение [param v] с точностью [param a].
|
||||
func round_to(v: float, a: float) -> float: return snappedf(v, -a if v < 0 else a)
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ func radians(val: float): return (val * PI) / 180.0
|
||||
func ibytes_to_word(buf: PackedByteArray, i: int) -> int: return buf[i] + (buf[i + 1] * 256)
|
||||
|
||||
|
||||
## Возвращает расстояние от центра координат до точки
|
||||
## Возвращает расстояние от центра координат до точки.
|
||||
func hypot(x: float, y: float) -> float: return sqrt(x * x + y * y)
|
||||
|
||||
|
||||
@@ -30,14 +30,14 @@ func is_overlap(x1, x2, y1, y2) -> bool: return max(x1, y1) <= min(x2, y2)
|
||||
|
||||
|
||||
func _check_index(obj, index) -> bool:
|
||||
if obj is Dictionary:
|
||||
if obj.has(index):
|
||||
return true
|
||||
elif obj is Array:
|
||||
if index is int:
|
||||
if (index >= 0) and (index < obj.size()):
|
||||
return true
|
||||
return false
|
||||
if obj is Dictionary:
|
||||
if obj.has(index):
|
||||
return true
|
||||
elif obj is Array:
|
||||
if index is int:
|
||||
if (index >= 0) and (index < obj.size()):
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
## Возвращает значение поля хранящегося по указанному пути внутри объекта.[br]
|
||||
@@ -48,15 +48,15 @@ func _check_index(obj, index) -> bool:
|
||||
## [param ret_val[1]] - устанвлено в [b]true[/b], если поле найдено, и установлено в [b]false[/b],
|
||||
## если искомое поле не найдено.
|
||||
func get_value_by_path(obj, paths: Array, ret_val: Array):
|
||||
var index = paths.pop_at(0)
|
||||
ret_val[1] = false
|
||||
if paths.size():
|
||||
if _check_index(obj, index):
|
||||
get_value_by_path(obj[index], paths, ret_val)
|
||||
else:
|
||||
if _check_index(obj, index):
|
||||
ret_val[0] = obj[index]
|
||||
ret_val[1] = true
|
||||
var index = paths.pop_at(0)
|
||||
ret_val[1] = false
|
||||
if paths.size():
|
||||
if _check_index(obj, index):
|
||||
get_value_by_path(obj[index], paths, ret_val)
|
||||
else:
|
||||
if _check_index(obj, index):
|
||||
ret_val[0] = obj[index]
|
||||
ret_val[1] = true
|
||||
|
||||
|
||||
## Возвращает часть от входной строки ограниченную индексами символов.[br]
|
||||
@@ -65,75 +65,75 @@ func get_value_by_path(obj, paths: Array, ret_val: Array):
|
||||
## [param i0] - Индекс начала части строки.[br]
|
||||
## [param i1] - Индекс конца части строки. Возвращает все символы до этого индекса.
|
||||
func get_string_slice(s_in: String, s_out: Array, i0: int, i1: int):
|
||||
for i in range(i0, i1):
|
||||
if s_in[i] != '\'':
|
||||
s_out[0] += s_in[i]
|
||||
for i in range(i0, i1):
|
||||
if s_in[i] != '\'':
|
||||
s_out[0] += s_in[i]
|
||||
|
||||
|
||||
## Производит преобразование из декартовой в полярную систему координат
|
||||
## Производит преобразование из декартовой в полярную систему координат.
|
||||
func pos_calc(freq: float, aoa: float, pos0: Vector2, r0: float, r1: float, f0: float, f1: float):
|
||||
var r = ((freq - f0) / (f1 - f0)) * r1 + r0
|
||||
var aoa_rad = radians(aoa) - PI / 2.0
|
||||
return Vector2(cos(aoa_rad), sin(aoa_rad)) * r + pos0
|
||||
var r = ((freq - f0) / (f1 - f0)) * r1 + r0
|
||||
var aoa_rad = radians(aoa) - PI / 2.0
|
||||
return Vector2(cos(aoa_rad), sin(aoa_rad)) * r + pos0
|
||||
|
||||
|
||||
## Отсекает значение до заданного диапазона
|
||||
## Отсекает значение до заданного диапазона.
|
||||
func clip_value(val, val_min, val_max):
|
||||
if val < val_min: val = val_min
|
||||
if val > val_max: val = val_max
|
||||
return val
|
||||
if val < val_min: val = val_min
|
||||
if val > val_max: val = val_max
|
||||
return val
|
||||
|
||||
|
||||
## Возвращает массив с именами членов [param obj]
|
||||
## Возвращает массив с именами членов [param obj].
|
||||
func get_members_names(obj: Object) -> Array:
|
||||
var pl = obj.get_property_list()
|
||||
var names: = Array()
|
||||
for item in pl: names.append(item.name)
|
||||
return names
|
||||
var pl = obj.get_property_list()
|
||||
var names: = Array()
|
||||
for item in pl: names.append(item.name)
|
||||
return names
|
||||
|
||||
|
||||
## Проверяет, что заданный массив [param val] похож на ip-адрес
|
||||
## Проверяет, что заданный массив [param val] похож на ip-адрес.
|
||||
func is_array_ipaddr(val: Array):
|
||||
return (val.size() == 2) \
|
||||
and (val[0] is String) \
|
||||
and (val[1] is int) \
|
||||
and (0 < val[1]) \
|
||||
and (val[1] < 65536)
|
||||
return (val.size() == 2) \
|
||||
and (val[0] is String) \
|
||||
and (val[1] is int) \
|
||||
and (0 < val[1]) \
|
||||
and (val[1] < 65536)
|
||||
|
||||
|
||||
## Преобразует декартовые координаты в полярные.[br]
|
||||
## [param pos0] - координаты центра.[br]
|
||||
## [param pos] - координаты точки.[br]
|
||||
func map_dec_to_rad(pos0: Vector2, pos: Vector2) -> Vector2:
|
||||
var x1: float = pos.x - pos0.x
|
||||
var y1: float = pos.y - pos0.y
|
||||
var ang: float = (atan2(y1, x1) * 180.0) / PI
|
||||
return Vector2(ang + 360.0 * float(ang < 0.0), hypot(x1, y1))
|
||||
var x1: float = pos.x - pos0.x
|
||||
var y1: float = pos.y - pos0.y
|
||||
var ang: float = (atan2(y1, x1) * 180.0) / PI
|
||||
return Vector2(ang + 360.0 * float(ang < 0.0), hypot(x1, y1))
|
||||
|
||||
|
||||
## Переводит значение val из диапазона a0...a1 в диапазон b0...b1
|
||||
## Переводит значение val из диапазона a0...a1 в диапазон b0...b1.
|
||||
func map_range(val: float, a0: float, a1: float, b0: float, b1: float) -> float:
|
||||
return (((val - a0) * (b1 - b0)) / (a1 - a0)) + b0
|
||||
return (((val - a0) * (b1 - b0)) / (a1 - a0)) + b0
|
||||
|
||||
|
||||
## Возвращает [b]true[/b], если точка внутри заданного полигона.[br]
|
||||
## [param pos] - Проверяемая точка.[br]
|
||||
## [param p] - Координаты вершин полигона.[br]
|
||||
func is_point_in_polygon(pos: Vector2, p: PackedVector2Array) -> bool:
|
||||
var sz: = p.size()
|
||||
assert(sz)
|
||||
var j: int = sz - 1
|
||||
var odd_nodes: int = 0
|
||||
for i in sz:
|
||||
if ((p[i].y < pos.y and p[j].y >= pos.y or p[j].y < pos.y and p[i].y >= pos.y) and (p[i].x <= pos.x or p[j].x <= pos.x)):
|
||||
odd_nodes ^= int((p[i].x + (pos.y - p[i].y) / (p[j].y - p[i].y) * (p[j].x - p[i].x) < pos.x))
|
||||
j = i
|
||||
return odd_nodes > 0
|
||||
var sz: = p.size()
|
||||
assert(sz)
|
||||
var j: int = sz - 1
|
||||
var odd_nodes: int = 0
|
||||
for i in sz:
|
||||
if ((p[i].y < pos.y and p[j].y >= pos.y or p[j].y < pos.y and p[i].y >= pos.y) and (p[i].x <= pos.x or p[j].x <= pos.x)):
|
||||
odd_nodes ^= int((p[i].x + (pos.y - p[i].y) / (p[j].y - p[i].y) * (p[j].x - p[i].x) < pos.x))
|
||||
j = i
|
||||
return odd_nodes > 0
|
||||
|
||||
|
||||
## Записывает слово [param val] в элемент байтовго массива [param buf]
|
||||
## Записывает слово [param val] в элемент байтовго массива [param buf].
|
||||
## расположенный по индексу [param index] (младшее слово).[br]
|
||||
## [i]Следует использовать встроенные в[/i] [b]PackedByteArray[/b] [i]методы вместо этой функции.[/i]
|
||||
func set_wordi(buf: PackedByteArray, index: int, val: int) -> void:
|
||||
buf[index] = val & 0xff
|
||||
buf[index + 1] = (val >> 8) & 0xff
|
||||
buf[index] = val & 0xff
|
||||
buf[index + 1] = (val >> 8) & 0xff
|
||||
|
||||
404
scripts/yau07.gd
404
scripts/yau07.gd
@@ -1,6 +1,6 @@
|
||||
extends Node
|
||||
class_name yau_07 extends Node
|
||||
|
||||
## Протокол ячейки ЯУ-07
|
||||
## Протокол ячейки ЯУ-07.
|
||||
|
||||
const ONLINE_TIMEOUT = 5.0 ## Время ожидания пакета от ячейки, секунды
|
||||
const RESEND_TIMEOUT = 0.3 ## Задержка для повторной отправки команды, секунды
|
||||
@@ -8,242 +8,242 @@ const RETRY_COUNT = 5 ## Количество повторных отпр
|
||||
const BUFFER_SIZE = 2048 ## Размер буфера для приёма датаграмм
|
||||
|
||||
|
||||
## Ячейка ЯУ-07
|
||||
## Ячейка ЯУ-07.
|
||||
class YaU07:
|
||||
|
||||
## Коды выполняемых команд
|
||||
enum CmdCode {
|
||||
READ_ISA = 0, ## Код команды "читать порт ISA" ячейки ЯУ-07
|
||||
WRITE_ISA = 1, ## Код команды "записать порт ISA" ячейки ЯУ-07
|
||||
WRITE_BLOCK = 60, ## Код команды "записать блок данных ISA" внешней шины ячейки ЯУ-07
|
||||
READ_BLOCK = 61, ## Код команды "читать блок данных ISA" внешней шины ячейки ЯУ-07
|
||||
}
|
||||
## Коды выполняемых команд.
|
||||
enum CmdCode {
|
||||
READ_ISA = 0, ## Код команды "читать порт ISA" ячейки ЯУ-07.
|
||||
WRITE_ISA = 1, ## Код команды "записать порт ISA" ячейки ЯУ-07.
|
||||
WRITE_BLOCK = 60, ## Код команды "записать блок данных ISA" внешней шины ячейки ЯУ-07.
|
||||
READ_BLOCK = 61, ## Код команды "читать блок данных ISA" внешней шины ячейки ЯУ-07.
|
||||
}
|
||||
|
||||
## Состояние автомата выполнения команды
|
||||
enum CmdState {
|
||||
UNCK, ## Номер команды не ининциирован
|
||||
SEND, ## Буфер готов для отправки
|
||||
WAIT, ## Ожидание выполнения
|
||||
DONE, ## Команда выполнена
|
||||
FAIL ## Команда не выполнена
|
||||
}
|
||||
## Состояние автомата выполнения команды.
|
||||
enum CmdState {
|
||||
UNCK, ## Номер команды не ининциирован.
|
||||
SEND, ## Буфер готов для отправки.
|
||||
WAIT, ## Ожидание выполнения.
|
||||
DONE, ## Команда выполнена.
|
||||
FAIL ## Команда не выполнена.
|
||||
}
|
||||
|
||||
signal line_changed(unit: YaU07) ## Вызывается когда меняется состояние связи с ячейкой
|
||||
signal command_done(unit: YaU07) ## Вызывается после выполнения команды
|
||||
signal command_fail(unit: YaU07) ## Вызывается если возникла ошибка при выполнении команды и команда не выполнена
|
||||
signal parse_failed(unit: YaU07)
|
||||
signal line_changed(unit: YaU07) ## Вызывается когда меняется состояние связи с ячейкой.
|
||||
signal command_done(unit: YaU07) ## Вызывается после выполнения команды.
|
||||
signal command_fail(unit: YaU07) ## Вызывается если возникла ошибка при выполнении команды и команда не выполнена.
|
||||
signal parse_failed(unit: YaU07)
|
||||
|
||||
var name: = String()
|
||||
var cmd_num_rx: = 0 ## Номер команды принятый
|
||||
var cmd_num_tx: = 0 ## Номер команды переданный
|
||||
var cmd_state = CmdState.UNCK ## Состояние выполнения команды
|
||||
var cmd_result: = 1 ## Результат выполнения команды. Устанавливается в ЯУ-07
|
||||
var cmd_data: = PackedByteArray() ## Данные команды. Устанавливается в ЯУ-07
|
||||
var cmd_retry = 0 ## Счётчик оставшихся попыток выполнить команду
|
||||
var tick = 0.0 ## Текущее тик-время в мс
|
||||
var cmd_tick_tx = 0.0 ## Время последней отправки команды
|
||||
var cmd_tick_rx = 0.0 ## Время последнего приёма команды
|
||||
var status: = PackedByteArray() ## Поле "состояние прибора"
|
||||
var tx_data: = PackedByteArray() ## Буфер отправленный
|
||||
var tx_len = 0 ## Длина последнего отправленного пакета
|
||||
var isa_ports = {} ## Результат выполнения команды "читать порт"
|
||||
var isa_block = {} ## Результат выполнения команды "читать массив из порта"
|
||||
var online = false ## Состояние связи с ячейкой
|
||||
var name: = String()
|
||||
var cmd_num_rx: = 0 ## Номер команды принятый.
|
||||
var cmd_num_tx: = 0 ## Номер команды переданный.
|
||||
var cmd_state = CmdState.UNCK ## Состояние выполнения команды.
|
||||
var cmd_result: = 1 ## Результат выполнения команды. Устанавливается в ЯУ-07.
|
||||
var cmd_data: = PackedByteArray() ## Данные команды. Устанавливается в ЯУ-07.
|
||||
var cmd_retry = 0 ## Счётчик оставшихся попыток выполнить команду.
|
||||
var tick = 0.0 ## Текущее тик-время в мс.
|
||||
var cmd_tick_tx = 0.0 ## Время последней отправки команды.
|
||||
var cmd_tick_rx = 0.0 ## Время последнего приёма команды.
|
||||
var status: = PackedByteArray() ## Поле "состояние прибора".
|
||||
var tx_data: = PackedByteArray() ## Буфер отправленный.
|
||||
var tx_len = 0 ## Длина последнего отправленного пакета.
|
||||
var isa_ports = {} ## Результат выполнения команды "читать порт".
|
||||
var isa_block = {} ## Результат выполнения команды "читать массив из порта".
|
||||
var online = false ## Состояние связи с ячейкой.
|
||||
|
||||
func _to_string() -> String: return String('яу07: %s %s' % [self.name, ['отключен', 'на связи'][int(online)]])
|
||||
func _to_string() -> String: return String('яу07: %s %s' % [self.name, ['отключен', 'на связи'][int(online)]])
|
||||
|
||||
|
||||
func _init(nm):
|
||||
self.name = nm
|
||||
tx_data.resize(BUFFER_SIZE)
|
||||
tx_data.fill(0)
|
||||
tick = 0.0
|
||||
func _init(nm):
|
||||
self.name = nm
|
||||
tx_data.resize(BUFFER_SIZE)
|
||||
tx_data.fill(0)
|
||||
tick = 0.0
|
||||
|
||||
|
||||
func process(delta: float):
|
||||
tick += delta
|
||||
if online and ((tick - cmd_tick_rx) > ONLINE_TIMEOUT):
|
||||
online = false
|
||||
emit_signal('line_changed', self)
|
||||
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:
|
||||
rc = Error.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:
|
||||
rc = Error.OK
|
||||
cmd_tick_tx = tick
|
||||
cmd_retry -= 1
|
||||
else:
|
||||
cmd_state = CmdState.FAIL
|
||||
emit_signal('command_fail', self)
|
||||
rc = Error.FAILED
|
||||
return rc
|
||||
var rc = Error.ERR_BUSY
|
||||
if cmd_state == CmdState.SEND:
|
||||
rc = Error.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:
|
||||
rc = Error.OK
|
||||
cmd_tick_tx = tick
|
||||
cmd_retry -= 1
|
||||
else:
|
||||
cmd_state = CmdState.FAIL
|
||||
emit_signal('command_fail', self)
|
||||
rc = Error.FAILED
|
||||
return rc
|
||||
|
||||
|
||||
func send_isa(cmd_code: int, ports_data: Array) -> bool:
|
||||
if (cmd_state == CmdState.WAIT) \
|
||||
or (cmd_state == CmdState.SEND) \
|
||||
or (cmd_state == CmdState.UNCK):
|
||||
return false
|
||||
if not ((cmd_code == CmdCode.READ_ISA) or (cmd_code == CmdCode.WRITE_ISA)):
|
||||
return false
|
||||
func send_isa(cmd_code: int, ports_data: Array) -> bool:
|
||||
if (cmd_state == CmdState.WAIT) \
|
||||
or (cmd_state == CmdState.SEND) \
|
||||
or (cmd_state == CmdState.UNCK):
|
||||
return false
|
||||
if not ((cmd_code == CmdCode.READ_ISA) or (cmd_code == CmdCode.WRITE_ISA)):
|
||||
return false
|
||||
|
||||
cmd_num_tx = (cmd_num_rx + 1) % 0xffff
|
||||
cmd_num_tx = (cmd_num_rx + 1) % 0xffff
|
||||
|
||||
var ports_count = ports_data.size()
|
||||
tx_len = ports_count * 2 + 8
|
||||
tx_data.encode_u16(0, cmd_retry) # Исправление для сетевого стека "nm-callback" процессоров STM
|
||||
tx_data.encode_u16(2, cmd_num_tx)
|
||||
var ports_count = ports_data.size()
|
||||
tx_len = ports_count * 2 + 8
|
||||
tx_data.encode_u16(0, cmd_retry) # Исправление для сетевого стека "nm-callback" процессоров STM
|
||||
tx_data.encode_u16(2, cmd_num_tx)
|
||||
|
||||
if cmd_code == CmdCode.WRITE_ISA:
|
||||
ports_count /= 2
|
||||
tx_data[6] = cmd_code
|
||||
tx_data[7] = ports_count
|
||||
if cmd_code == CmdCode.WRITE_ISA:
|
||||
ports_count /= 2
|
||||
tx_data[6] = cmd_code
|
||||
tx_data[7] = ports_count
|
||||
|
||||
var i: = 0
|
||||
for word in ports_data:
|
||||
tx_data.encode_u16(8 + i, word)
|
||||
i += 2
|
||||
cmd_state = CmdState.SEND
|
||||
return true
|
||||
var i: = 0
|
||||
for word in ports_data:
|
||||
tx_data.encode_u16(8 + i, word)
|
||||
i += 2
|
||||
cmd_state = CmdState.SEND
|
||||
return true
|
||||
|
||||
func send_block(cmd_code: int, block_len: int, port: Array) -> bool:
|
||||
if (cmd_state == CmdState.WAIT) \
|
||||
or (cmd_state == CmdState.SEND) \
|
||||
or (cmd_state == CmdState.UNCK):
|
||||
return false
|
||||
if not ((cmd_code == CmdCode.READ_BLOCK) or (cmd_code == CmdCode.WRITE_BLOCK)):
|
||||
return false
|
||||
func send_block(cmd_code: int, block_len: int, port: Array) -> bool:
|
||||
if (cmd_state == CmdState.WAIT) \
|
||||
or (cmd_state == CmdState.SEND) \
|
||||
or (cmd_state == CmdState.UNCK):
|
||||
return false
|
||||
if not ((cmd_code == CmdCode.READ_BLOCK) or (cmd_code == CmdCode.WRITE_BLOCK)):
|
||||
return false
|
||||
|
||||
cmd_num_tx = (cmd_num_rx + 1) % 0xffff
|
||||
cmd_num_tx = (cmd_num_rx + 1) % 0xffff
|
||||
|
||||
tx_len = 11
|
||||
tx_data.encode_u16(0, cmd_retry) # Исправление для сетевого стека "nm-callback" процессоров STM
|
||||
tx_data.encode_u16(2, cmd_num_tx)
|
||||
tx_len = 11
|
||||
tx_data.encode_u16(0, cmd_retry) # Исправление для сетевого стека "nm-callback" процессоров STM
|
||||
tx_data.encode_u16(2, cmd_num_tx)
|
||||
|
||||
if cmd_code == CmdCode.WRITE_BLOCK:
|
||||
block_len /= 2
|
||||
tx_data[6] = cmd_code
|
||||
tx_data.encode_u16(7, block_len)
|
||||
if cmd_code == CmdCode.WRITE_BLOCK:
|
||||
block_len /= 2
|
||||
tx_data[6] = cmd_code
|
||||
tx_data.encode_u16(7, block_len)
|
||||
|
||||
tx_data.encode_u16(9, int(port[0]))
|
||||
cmd_state = CmdState.SEND
|
||||
return true
|
||||
## Возвращает код команды ЯУ-07
|
||||
## rx_data - Принятые данные
|
||||
## Возвращает - Код команды не найден, 0...255 - код команды
|
||||
func get_cmd_code(rx_data: PackedByteArray):
|
||||
tx_data.encode_u16(9, int(port[0]))
|
||||
cmd_state = CmdState.SEND
|
||||
return true
|
||||
## Возвращает код команды ЯУ-07.
|
||||
## rx_data - Принятые данные.
|
||||
## Возвращает - Код команды не найден, 0...255 - код команды.
|
||||
func get_cmd_code(rx_data: PackedByteArray):
|
||||
|
||||
var rx_data_len = rx_data.size()
|
||||
if rx_data_len < 7:
|
||||
return null
|
||||
var status_len = rx_data.decode_u16(6) # Длина массива байтового "состояние прибора"
|
||||
if rx_data_len <= (status_len + 6): # Нет поля "ответ на команду", разбор пакета завершить
|
||||
return null
|
||||
var cmd_code_pos = status_len + 8 # Положение в приёмном буфере "кода команды"
|
||||
if rx_data_len <= cmd_code_pos:
|
||||
return null
|
||||
return rx_data[cmd_code_pos] # "код команды"
|
||||
var rx_data_len = rx_data.size()
|
||||
if rx_data_len < 7:
|
||||
return null
|
||||
var status_len = rx_data.decode_u16(6) # Длина массива байтового "состояние прибора"
|
||||
if rx_data_len <= (status_len + 6): # Нет поля "ответ на команду", разбор пакета завершить
|
||||
return null
|
||||
var cmd_code_pos = status_len + 8 # Положение в приёмном буфере "кода команды"
|
||||
if rx_data_len <= cmd_code_pos:
|
||||
return null
|
||||
return rx_data[cmd_code_pos] # "код команды"
|
||||
|
||||
|
||||
func parse_isa(rx_data: PackedByteArray, status_len) -> bool:
|
||||
var ports_count_pos = status_len + 10 # Положение в приёмном буфере количества портов
|
||||
if rx_data.size() < ports_count_pos:
|
||||
return false
|
||||
var ports_count = rx_data[ports_count_pos] # Количество портов
|
||||
var counted_len = status_len + (ports_count * 4) + 11 # Вычисленная длина пакета
|
||||
if rx_data.size() < counted_len:
|
||||
return false
|
||||
var addr_pos = status_len + 11 # Смещение положения адреса в приёмном буфере
|
||||
var data_pos = status_len + 13 # Смещение положения данных в приёмном буфере
|
||||
var i: = 0
|
||||
while i < ports_count:
|
||||
var shift: = i * 4
|
||||
var isa_addr = rx_data.decode_u16(addr_pos + shift) # Адрес порта ISA яу-07
|
||||
var isa_data = rx_data.decode_u16(data_pos + shift) # Данные порта ISA яу-07
|
||||
isa_ports[isa_addr] = isa_data
|
||||
i += 1
|
||||
cmd_data = rx_data.slice(addr_pos, (addr_pos + ports_count * 4) - 1)
|
||||
return i > 0
|
||||
func parse_isa(rx_data: PackedByteArray, status_len) -> bool:
|
||||
var ports_count_pos = status_len + 10 # Положение в приёмном буфере количества портов
|
||||
if rx_data.size() < ports_count_pos:
|
||||
return false
|
||||
var ports_count = rx_data[ports_count_pos] # Количество портов
|
||||
var counted_len = status_len + (ports_count * 4) + 11 # Вычисленная длина пакета
|
||||
if rx_data.size() < counted_len:
|
||||
return false
|
||||
var addr_pos = status_len + 11 # Смещение положения адреса в приёмном буфере
|
||||
var data_pos = status_len + 13 # Смещение положения данных в приёмном буфере
|
||||
var i: = 0
|
||||
while i < ports_count:
|
||||
var shift: = i * 4
|
||||
var isa_addr = rx_data.decode_u16(addr_pos + shift) # Адрес порта ISA яу-07
|
||||
var isa_data = rx_data.decode_u16(data_pos + shift) # Данные порта ISA яу-07
|
||||
isa_ports[isa_addr] = isa_data
|
||||
i += 1
|
||||
cmd_data = rx_data.slice(addr_pos, (addr_pos + ports_count * 4) - 1)
|
||||
return i > 0
|
||||
|
||||
func parse_block(rx_data: PackedByteArray, status_len) -> bool:
|
||||
var ports_count_pos = status_len + 7 # Положение в приёмном буфере количества портов
|
||||
if rx_data.size() < ports_count_pos:
|
||||
return false
|
||||
var block_len = rx_data.decode_u16(ports_count_pos + 3)
|
||||
var block_adr = rx_data.decode_u16(ports_count_pos + 5)
|
||||
var block_data = []
|
||||
for i in block_len:
|
||||
var shift: int = i * 2
|
||||
block_data.append(rx_data.decode_u16(ports_count_pos + 7 + shift))
|
||||
isa_block[block_adr] = block_data
|
||||
return true
|
||||
func parse_block(rx_data: PackedByteArray, status_len) -> bool:
|
||||
var ports_count_pos = status_len + 7 # Положение в приёмном буфере количества портов
|
||||
if rx_data.size() < ports_count_pos:
|
||||
return false
|
||||
var block_len = rx_data.decode_u16(ports_count_pos + 3)
|
||||
var block_adr = rx_data.decode_u16(ports_count_pos + 5)
|
||||
var block_data = []
|
||||
for i in block_len:
|
||||
var shift: int = i * 2
|
||||
block_data.append(rx_data.decode_u16(ports_count_pos + 7 + shift))
|
||||
isa_block[block_adr] = block_data
|
||||
return true
|
||||
|
||||
|
||||
## Заполняет состояние прибора данными прочитанными из портов ЯУ-07
|
||||
## для команд "читать порты" или "записать порты"[br]
|
||||
## [param rx_data] - Принятые данные[br]
|
||||
## Возвращает [b]true[/b] - Данные обработаны успешно[br]
|
||||
## Возвращает [b]false[/b] - Данные не обработаны из за ошибки[br]
|
||||
func parse(rx_data: PackedByteArray) -> bool:
|
||||
## Заполняет состояние прибора данными прочитанными из портов ЯУ-07.
|
||||
## для команд "читать порты" или "записать порты".[br]
|
||||
## [param rx_data] - Принятые данные.[br]
|
||||
## Возвращает [b]true[/b] - Данные обработаны успешно.[br]
|
||||
## Возвращает [b]false[/b] - Данные не обработаны из за ошибки.[br]
|
||||
func parse(rx_data: PackedByteArray) -> bool:
|
||||
|
||||
cmd_tick_rx = tick
|
||||
cmd_tick_rx = tick
|
||||
|
||||
if not online:
|
||||
online = true
|
||||
emit_signal('line_changed', self)
|
||||
if not online:
|
||||
online = true
|
||||
emit_signal('line_changed', self)
|
||||
|
||||
var rx_data_len = rx_data.size()
|
||||
if rx_data_len < 10:
|
||||
return false
|
||||
var rx_data_len = rx_data.size()
|
||||
if rx_data_len < 10:
|
||||
return false
|
||||
|
||||
cmd_num_rx = rx_data.decode_u16(2)
|
||||
if cmd_state == CmdState.UNCK:
|
||||
cmd_state = CmdState.DONE
|
||||
cmd_num_rx = rx_data.decode_u16(2)
|
||||
if cmd_state == CmdState.UNCK:
|
||||
cmd_state = CmdState.DONE
|
||||
|
||||
var status_len = rx_data.decode_u16(6) # Длина массива байтового "состояние прибора"
|
||||
if rx_data_len < (status_len + 6):
|
||||
return false
|
||||
var i: = 0
|
||||
var len_rx_data: = rx_data.size()
|
||||
status.resize(status_len)
|
||||
while i < status_len:
|
||||
var byte_i = i + 8
|
||||
if byte_i < len_rx_data:
|
||||
status[i] = rx_data[byte_i] # Массив байтовый "состояние прибора"
|
||||
i += 1
|
||||
var status_len = rx_data.decode_u16(6) # Длина массива байтового "состояние прибора"
|
||||
if rx_data_len < (status_len + 6):
|
||||
return false
|
||||
var i: = 0
|
||||
var len_rx_data: = rx_data.size()
|
||||
status.resize(status_len)
|
||||
while i < status_len:
|
||||
var byte_i = i + 8
|
||||
if byte_i < len_rx_data:
|
||||
status[i] = rx_data[byte_i] # Массив байтовый "состояние прибора"
|
||||
i += 1
|
||||
|
||||
if rx_data_len == (status_len + 6):
|
||||
return true # Нет поля "ответ на команду", разбор пакета завершить
|
||||
if rx_data_len == (status_len + 6):
|
||||
return true # Нет поля "ответ на команду", разбор пакета завершить
|
||||
|
||||
var cmd_code_pos = status_len + 8 # Положение в приёмном буфере "код команды"
|
||||
if rx_data_len <= cmd_code_pos:
|
||||
return false
|
||||
var cmd_code_pos = status_len + 8 # Положение в приёмном буфере "код команды"
|
||||
if rx_data_len <= cmd_code_pos:
|
||||
return false
|
||||
|
||||
var cmd_status_pos = status_len + 9 # Положение в приёмном буфере "состояния выполнения команды"
|
||||
if rx_data_len <= cmd_status_pos:
|
||||
return false
|
||||
cmd_result = rx_data[cmd_status_pos]
|
||||
if cmd_result != 1: # Команда не выполнена
|
||||
return false
|
||||
var cmd_status_pos = status_len + 9 # Положение в приёмном буфере "состояния выполнения команды"
|
||||
if rx_data_len <= cmd_status_pos:
|
||||
return false
|
||||
cmd_result = rx_data[cmd_status_pos]
|
||||
if cmd_result != 1: # Команда не выполнена
|
||||
return false
|
||||
|
||||
var cmd_code: CmdCode = rx_data[cmd_code_pos] as CmdCode # "код команды"
|
||||
var rc = true
|
||||
if (cmd_code == CmdCode.READ_ISA) or (cmd_code == CmdCode.WRITE_ISA):
|
||||
rc = parse_isa(rx_data, status_len)
|
||||
var cmd_code: CmdCode = rx_data[cmd_code_pos] as CmdCode # "код команды"
|
||||
var rc = true
|
||||
if (cmd_code == CmdCode.READ_ISA) or (cmd_code == CmdCode.WRITE_ISA):
|
||||
rc = parse_isa(rx_data, status_len)
|
||||
|
||||
elif (cmd_code == CmdCode.READ_BLOCK) or (cmd_code == CmdCode.WRITE_BLOCK):
|
||||
rc = parse_block(rx_data, status_len)
|
||||
elif (cmd_code == CmdCode.READ_BLOCK) or (cmd_code == CmdCode.WRITE_BLOCK):
|
||||
rc = parse_block(rx_data, status_len)
|
||||
|
||||
if rc:
|
||||
if (cmd_state == CmdState.WAIT) and (cmd_num_rx == cmd_num_tx):
|
||||
cmd_state = CmdState.DONE
|
||||
emit_signal('command_done', self)
|
||||
else:
|
||||
emit_signal('parse_failed', self)
|
||||
return true
|
||||
if rc:
|
||||
if (cmd_state == CmdState.WAIT) and (cmd_num_rx == cmd_num_tx):
|
||||
cmd_state = CmdState.DONE
|
||||
emit_signal('command_done', self)
|
||||
else:
|
||||
emit_signal('parse_failed', self)
|
||||
return true
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
extends Node
|
||||
class_name yems_boards extends Node
|
||||
|
||||
class EmsBoard:
|
||||
var id_board: String
|
||||
var in_devs: Dictionary ## Словарь с входными устройствами
|
||||
var out_devs: Dictionary ## Словарь с выходными устройствами
|
||||
var base_addr_isa: int ## Базовый адрес ячейки isa
|
||||
var in_tbl: Array
|
||||
var out_tbl: Array
|
||||
var id_board: String
|
||||
var in_devs: Dictionary ## Словарь с входными устройствами.
|
||||
var out_devs: Dictionary ## Словарь с выходными устройствами.
|
||||
var base_addr_isa: int ## Базовый адрес ячейки isa.
|
||||
var in_tbl: Array
|
||||
var out_tbl: Array
|
||||
|
||||
func _init(id, base_addr, in_table, out_table):
|
||||
id_board = id
|
||||
in_tbl = in_table
|
||||
out_tbl = out_table
|
||||
base_addr_isa = base_addr
|
||||
func _init(id, base_addr, in_table, out_table):
|
||||
id_board = id
|
||||
in_tbl = in_table
|
||||
out_tbl = out_table
|
||||
base_addr_isa = base_addr
|
||||
|
||||
@@ -1,144 +1,144 @@
|
||||
extends Node
|
||||
class_name yerms_consts extends Node
|
||||
|
||||
##
|
||||
## Таблица с данными для входов, первое значение - индекс устройства в ячейке КЭМС.
|
||||
const INPUT_ROWS1 = [
|
||||
[12,['283333 МР-231S, Строб ЭМС', 'X52', '0.00', '0.00']],
|
||||
[13,['29НРЛС МР-231-3, УИЗП', 'X54', '0.00', '0.00']],
|
||||
[14,['30НРЛС МР-231-3, Строб ЭМС', 'X55', '0.00', '0.00']],
|
||||
[15,['31ЦИСВС-1010, УИЗП', 'X23', '0.00', '0.00']],
|
||||
[21,['32НРЛС МР-231S, УИЗП', 'X21', '0.00', '0.00']],
|
||||
[22,['33НРЛС МР-231S, Строб ЭМС', 'X22', '0.00', '0.00']],
|
||||
[23,['34НРЛС МР-231-3, УИЗП', 'X24', '0.00', '0.00']],
|
||||
[32,['352222 МР-231S, Строб ЭМС', 'X32', '0.00', '0.00']],
|
||||
[33,['36НРЛС МР-231-3, УИЗП', 'X34', '0.00', '0.00']],
|
||||
[34,['37НРЛС МР-231-3, Строб ЭМС', 'X35', '0.00', '0.00']],
|
||||
[35,['38ЦИСВС-1010, УИЗП', 'X43', '0.00', '0.00']],
|
||||
[38,['394302-01, 4302-04, УИЗП', 'X46', '0.00', '0.00']],
|
||||
[31,['40НРЛС МР-231S, УИЗП', 'X51', '0.00', '0.00']]]
|
||||
[12,['283333 МР-231S, Строб ЭМС', 'X52', '0.00', '0.00']],
|
||||
[13,['29НРЛС МР-231-3, УИЗП', 'X54', '0.00', '0.00']],
|
||||
[14,['30НРЛС МР-231-3, Строб ЭМС', 'X55', '0.00', '0.00']],
|
||||
[15,['31ЦИСВС-1010, УИЗП', 'X23', '0.00', '0.00']],
|
||||
[21,['32НРЛС МР-231S, УИЗП', 'X21', '0.00', '0.00']],
|
||||
[22,['33НРЛС МР-231S, Строб ЭМС', 'X22', '0.00', '0.00']],
|
||||
[23,['34НРЛС МР-231-3, УИЗП', 'X24', '0.00', '0.00']],
|
||||
[32,['352222 МР-231S, Строб ЭМС', 'X32', '0.00', '0.00']],
|
||||
[33,['36НРЛС МР-231-3, УИЗП', 'X34', '0.00', '0.00']],
|
||||
[34,['37НРЛС МР-231-3, Строб ЭМС', 'X35', '0.00', '0.00']],
|
||||
[35,['38ЦИСВС-1010, УИЗП', 'X43', '0.00', '0.00']],
|
||||
[38,['394302-01, 4302-04, УИЗП', 'X46', '0.00', '0.00']],
|
||||
[31,['40НРЛС МР-231S, УИЗП', 'X51', '0.00', '0.00']]]
|
||||
|
||||
## Таблица с данными для выходов, первое значение - индекс устройства в ячейке КЭМС
|
||||
## Таблица с данными для выходов, первое значение - индекс устройства в ячейке КЭМС.
|
||||
const OUTPUT_ROWS1 = [
|
||||
[41,['41НРЛС МР-231S, БИ', 'X61', '0.00', '0.00']],
|
||||
[42,['42НРЛС МР-231S', 'X62', '0.00', '0.00']],
|
||||
[43,['43НРЛС МР-231-3, БИ', 'X64', '0.00', '0.00']],
|
||||
[44,['44НРЛС МР-231-3', 'X65', '0.00', '0.00']],
|
||||
[45,['45ЦИСВС-1010, БИ', 'X63', '0.00', '0.00']],
|
||||
[46,['464302-01, 4302-04, БИ', 'X66', '0.00', '0.00']],
|
||||
[48,['47НРЛС 11111111', 'X69', '0.00', '0.00']],
|
||||
[62,['48НРЛС МР-231S', 'X62', '0.00', '0.00']],
|
||||
[63,['49НРЛС МР-231-3, БИ', 'X64', '0.00', '0.00']],
|
||||
[64,['50НРЛС МР-231-3', 'X65', '0.00', '0.00']],
|
||||
[65,['51ЦИСВС-1010, БИ', 'X63', '0.00', '0.00']],
|
||||
[66,['524302-01, 4302-04, БИ', 'X66', '0.00', '0.00']],
|
||||
[68,['53НРЛС 11111111', 'X69', '0.00', '0.00']]]
|
||||
[41,['41НРЛС МР-231S, БИ', 'X61', '0.00', '0.00']],
|
||||
[42,['42НРЛС МР-231S', 'X62', '0.00', '0.00']],
|
||||
[43,['43НРЛС МР-231-3, БИ', 'X64', '0.00', '0.00']],
|
||||
[44,['44НРЛС МР-231-3', 'X65', '0.00', '0.00']],
|
||||
[45,['45ЦИСВС-1010, БИ', 'X63', '0.00', '0.00']],
|
||||
[46,['464302-01, 4302-04, БИ', 'X66', '0.00', '0.00']],
|
||||
[48,['47НРЛС 11111111', 'X69', '0.00', '0.00']],
|
||||
[62,['48НРЛС МР-231S', 'X62', '0.00', '0.00']],
|
||||
[63,['49НРЛС МР-231-3, БИ', 'X64', '0.00', '0.00']],
|
||||
[64,['50НРЛС МР-231-3', 'X65', '0.00', '0.00']],
|
||||
[65,['51ЦИСВС-1010, БИ', 'X63', '0.00', '0.00']],
|
||||
[66,['524302-01, 4302-04, БИ', 'X66', '0.00', '0.00']],
|
||||
[68,['53НРЛС 11111111', 'X69', '0.00', '0.00']]]
|
||||
|
||||
## Таблица с данными для входов, первое значение - индекс устройства в ячейке КЭМС
|
||||
## Таблица с данными для входов, первое значение - индекс устройства в ячейке КЭМС.
|
||||
const INPUT_ROWS = [
|
||||
[1,['УИЗП №1', 'Х7', '0.00', '0.00']],
|
||||
[2,['УИЗПФ №1', 'Х8', '0.00', '0.00']],
|
||||
[3,['УИЗП №2', 'Х10', '0.00', '0.00']],
|
||||
[4,['УИЗПФ №2', 'Х11', '0.00', '0.00']],
|
||||
[5,['УИЗП №3', 'Х13', '0.00', '0.00']],
|
||||
[6,['УИЗПФ №3', 'Х14', '0.00', '0.00']],
|
||||
[7,['УИЗП №4', 'Х16', '0.00', '0.00']],
|
||||
[8,['УИЗПФ №4', 'Х17', '0.00', '0.00']],
|
||||
[9,['УИЗП №5', 'Х19', '0.00', '0.00']],
|
||||
[10,['УИЗПФ №5', 'Х20', '0.00', '0.00']],
|
||||
[11,['УИЗП №6', 'Х22', '0.00', '0.00']],
|
||||
[12,['УИЗПФ №6','Х23', '0.00', '0.00']],
|
||||
[13,['УИЗП №7','Х25', '0.00', '0.00']],
|
||||
[14,['УИЗПФ №7','Х26', '0.00', '0.00']],
|
||||
[15,['СИ1 Л1','X31 : 2', '0.00', '0.00']],
|
||||
[16,['СИ1 Л6','X31 : 5', '0.00', '0.00']],
|
||||
[17,['СИ1 Л7','X31 : 8', '0.00', '0.00']],
|
||||
[18,['СИ2 Л1','X32 : 2', '0.00', '0.00']],
|
||||
[19,['СИ2 Л6','X32 : 5', '0.00', '0.00']],
|
||||
[20,['СИ2 Л7','X32 : 8', '0.00', '0.00']],
|
||||
[21,['СИ3 Л1','X33 : 2', '0.00', '0.00']],
|
||||
[22,['СИ3 Л6','X33 : 5', '0.00', '0.00']],
|
||||
[23,['СИ3 Л7','X33 : 8', '0.00', '0.00']],
|
||||
[24,['СИ4 Л1','X34 : 2', '0.00', '0.00']],
|
||||
[25,['СИ4 Л6','X34 : 5', '0.00', '0.00']],
|
||||
[26,['СИ4 Л7','X34 : 8', '0.00', '0.00']],
|
||||
[27,['СИ1 Л2','X38 : 2', '0.00', '0.00']],
|
||||
[28,['СИ1 Л3','X38 : 5', '0.00', '0.00']],
|
||||
[29,['СИ2 Л2','X39 : 2', '0.00', '0.00']],
|
||||
[30,['СИ2 Л3','X39 : 5', '0.00', '0.00']],
|
||||
[31,['СИ3 Л2','X40 : 2', '0.00', '0.00']],
|
||||
[32,['СИ3 Л3','X40 : 5', '0.00', '0.00']],
|
||||
[33,['СИ4 Л2','X41 : 2', '0.00', '0.00']],
|
||||
[34,['СИ4 Л3','X41 : 5', '0.00', '0.00']],
|
||||
[35,['СИ1 Л4','X42 : 2', '0.00', '0.00']],
|
||||
[36,['СИ1 Л5','X42 : 5', '0.00', '0.00']],
|
||||
[37,['СИ2 Л4','X43 : 2', '0.00', '0.00']],
|
||||
[38,['СИ2 Л5','X43 : 5', '0.00', '0.00']],
|
||||
[39,['СИ3 Л4','X44 : 2', '0.00', '0.00']],
|
||||
[40,['СИ3 Л5','X44 : 5', '0.00', '0.00']],
|
||||
[41,['СИ4 Л4','X45 : 2', '0.00', '0.00']],
|
||||
[42,['СИ4 Л5','X45 : 5', '0.00', '0.00']],
|
||||
[43,['БИ В Лб','Х49 : 37', '0.00', '0.00']],
|
||||
[44,['БИ В ПрБ','Х49 : 31', '0.00', '0.00']],
|
||||
[45,['БИ Г Лб','Х49 : 15', '0.00', '0.00']],
|
||||
[46,['БИ Г ПрБ','Х49 : 8', '0.00', '0.00']],
|
||||
[47,['БИ Д Лб','Х49 : 6', '0.00', '0.00']],
|
||||
[48,['БИ Д ПрБ','Х49 : 10', '0.00', '0.00']],
|
||||
[49,['БИ Е Лб','Х49 : 25', '0.00', '0.00']],
|
||||
[50,['БИ Е ПрБ','Х49 : 40', '0.00', '0.00']],
|
||||
[51,['СЗИ В Лб','Х49 : 42', '0.00', '0.00']],
|
||||
[52,['СЗИ В ПрБ','Х49 : 32', '0.00', '0.00']],
|
||||
[53,['СЗИ Г Лб','Х49 : 46', '0.00', '0.00']],
|
||||
[54,['СЗИ Г ПрБ','Х49 : 32', '0.00', '0.00']],
|
||||
[55,['СЗИ Д Лб','Х49 : 16', '0.00', '0.00']],
|
||||
[56,['СЗИ Д ПрБ','Х49 : 47', '0.00', '0.00']],
|
||||
[57,['СЗИ Е Лб','Х49 : 1', '0.00', '0.00']],
|
||||
[58,['СЗИ Е ПрБ','Х49 : 50', '0.00', '0.00']]]
|
||||
[1,['УИЗП №1', 'Х7', '0.00', '0.00']],
|
||||
[2,['УИЗПФ №1', 'Х8', '0.00', '0.00']],
|
||||
[3,['УИЗП №2', 'Х10', '0.00', '0.00']],
|
||||
[4,['УИЗПФ №2', 'Х11', '0.00', '0.00']],
|
||||
[5,['УИЗП №3', 'Х13', '0.00', '0.00']],
|
||||
[6,['УИЗПФ №3', 'Х14', '0.00', '0.00']],
|
||||
[7,['УИЗП №4', 'Х16', '0.00', '0.00']],
|
||||
[8,['УИЗПФ №4', 'Х17', '0.00', '0.00']],
|
||||
[9,['УИЗП №5', 'Х19', '0.00', '0.00']],
|
||||
[10,['УИЗПФ №5', 'Х20', '0.00', '0.00']],
|
||||
[11,['УИЗП №6', 'Х22', '0.00', '0.00']],
|
||||
[12,['УИЗПФ №6','Х23', '0.00', '0.00']],
|
||||
[13,['УИЗП №7','Х25', '0.00', '0.00']],
|
||||
[14,['УИЗПФ №7','Х26', '0.00', '0.00']],
|
||||
[15,['СИ1 Л1','X31 : 2', '0.00', '0.00']],
|
||||
[16,['СИ1 Л6','X31 : 5', '0.00', '0.00']],
|
||||
[17,['СИ1 Л7','X31 : 8', '0.00', '0.00']],
|
||||
[18,['СИ2 Л1','X32 : 2', '0.00', '0.00']],
|
||||
[19,['СИ2 Л6','X32 : 5', '0.00', '0.00']],
|
||||
[20,['СИ2 Л7','X32 : 8', '0.00', '0.00']],
|
||||
[21,['СИ3 Л1','X33 : 2', '0.00', '0.00']],
|
||||
[22,['СИ3 Л6','X33 : 5', '0.00', '0.00']],
|
||||
[23,['СИ3 Л7','X33 : 8', '0.00', '0.00']],
|
||||
[24,['СИ4 Л1','X34 : 2', '0.00', '0.00']],
|
||||
[25,['СИ4 Л6','X34 : 5', '0.00', '0.00']],
|
||||
[26,['СИ4 Л7','X34 : 8', '0.00', '0.00']],
|
||||
[27,['СИ1 Л2','X38 : 2', '0.00', '0.00']],
|
||||
[28,['СИ1 Л3','X38 : 5', '0.00', '0.00']],
|
||||
[29,['СИ2 Л2','X39 : 2', '0.00', '0.00']],
|
||||
[30,['СИ2 Л3','X39 : 5', '0.00', '0.00']],
|
||||
[31,['СИ3 Л2','X40 : 2', '0.00', '0.00']],
|
||||
[32,['СИ3 Л3','X40 : 5', '0.00', '0.00']],
|
||||
[33,['СИ4 Л2','X41 : 2', '0.00', '0.00']],
|
||||
[34,['СИ4 Л3','X41 : 5', '0.00', '0.00']],
|
||||
[35,['СИ1 Л4','X42 : 2', '0.00', '0.00']],
|
||||
[36,['СИ1 Л5','X42 : 5', '0.00', '0.00']],
|
||||
[37,['СИ2 Л4','X43 : 2', '0.00', '0.00']],
|
||||
[38,['СИ2 Л5','X43 : 5', '0.00', '0.00']],
|
||||
[39,['СИ3 Л4','X44 : 2', '0.00', '0.00']],
|
||||
[40,['СИ3 Л5','X44 : 5', '0.00', '0.00']],
|
||||
[41,['СИ4 Л4','X45 : 2', '0.00', '0.00']],
|
||||
[42,['СИ4 Л5','X45 : 5', '0.00', '0.00']],
|
||||
[43,['БИ В Лб','Х49 : 37', '0.00', '0.00']],
|
||||
[44,['БИ В ПрБ','Х49 : 31', '0.00', '0.00']],
|
||||
[45,['БИ Г Лб','Х49 : 15', '0.00', '0.00']],
|
||||
[46,['БИ Г ПрБ','Х49 : 8', '0.00', '0.00']],
|
||||
[47,['БИ Д Лб','Х49 : 6', '0.00', '0.00']],
|
||||
[48,['БИ Д ПрБ','Х49 : 10', '0.00', '0.00']],
|
||||
[49,['БИ Е Лб','Х49 : 25', '0.00', '0.00']],
|
||||
[50,['БИ Е ПрБ','Х49 : 40', '0.00', '0.00']],
|
||||
[51,['СЗИ В Лб','Х49 : 42', '0.00', '0.00']],
|
||||
[52,['СЗИ В ПрБ','Х49 : 32', '0.00', '0.00']],
|
||||
[53,['СЗИ Г Лб','Х49 : 46', '0.00', '0.00']],
|
||||
[54,['СЗИ Г ПрБ','Х49 : 32', '0.00', '0.00']],
|
||||
[55,['СЗИ Д Лб','Х49 : 16', '0.00', '0.00']],
|
||||
[56,['СЗИ Д ПрБ','Х49 : 47', '0.00', '0.00']],
|
||||
[57,['СЗИ Е Лб','Х49 : 1', '0.00', '0.00']],
|
||||
[58,['СЗИ Е ПрБ','Х49 : 50', '0.00', '0.00']]]
|
||||
|
||||
## Таблица с данными для выходов, первое значение - индекс устройства в ячейке КЭМС
|
||||
## Таблица с данными для выходов, первое значение - индекс устройства в ячейке КЭМС.
|
||||
const OUTPUT_ROWS = [
|
||||
[11,['Бланк №1','Х6', '0.00', '0.00']],
|
||||
[12,['Бланк №2','Х9', '0.00', '0.00']],
|
||||
[13,['Бланк №3','Х12', '0.00', '0.00']],
|
||||
[14,['Бланк №4','Х15', '0.00', '0.00']],
|
||||
[15,['Бланк №5','Х18', '0.00', '0.00']],
|
||||
[16,['Бланк №6','Х21', '0.00', '0.00']],
|
||||
[17,['Бланк №7','Х24', '0.00', '0.00']],
|
||||
[18,['СЗИ1 Л1','X31 : 11', '0.00', '0.00']],
|
||||
[19,['СЗИ1 Л6','X31 :14', '0.00', '0.00']],
|
||||
[20,['СЗИ1 Л7','X31 : 17', '0.00', '0.00']],
|
||||
[21,['СЗИ2 Л1','X32 : 11', '0.00', '0.00']],
|
||||
[22,['СЗИ2 Л6','X32 : 14', '0.00', '0.00']],
|
||||
[23,['СЗИ2 Л7','X32: 17', '0.00', '0.00']],
|
||||
[24,['СЗИ3 Л1','X33 : 11', '0.00', '0.00']],
|
||||
[25,['СЗИ3 Л6','X33 :14', '0.00', '0.00']],
|
||||
[26,['СЗИ3 Л7','X33: 17', '0.00', '0.00']],
|
||||
[27,['СЗИ4 Л1','X34 : 11', '0.00', '0.00']],
|
||||
[28,['СЗИ4 Л6','X34 :14', '0.00', '0.00']],
|
||||
[29,['СЗИ4 Л7','X34: 17', '0.00', '0.00']],
|
||||
[30,['СЗИ1 Л2','X38 : 11', '0.00', '0.00']],
|
||||
[31,['СЗИ1 Л3','X38 : 14', '0.00', '0.00']],
|
||||
[32,['СЗИ2 Л2','X39 : 11', '0.00', '0.00']],
|
||||
[33,['СЗИ2 Л3','X39 : 14', '0.00', '0.00']],
|
||||
[34,['СЗИ3 Л2','X40 : 11', '0.00', '0.00']],
|
||||
[35,['СЗИ3 Л3','X40 : 14', '0.00', '0.00']],
|
||||
[36,['СЗИ4 Л2','X41 : 11', '0.00', '0.00']],
|
||||
[37,['СЗИ4 Л3','X41 :14', '0.00', '0.00']],
|
||||
[38,['СЗИ1 Л4','X42 : 11', '0.00', '0.00']],
|
||||
[39,['СЗИ1 Л5','X42 :14', '0.00', '0.00']],
|
||||
[40,['СЗИ2 Л4','X43 : 11', '0.00', '0.00']],
|
||||
[41,['СЗИ2 Л5','X43 : 14', '0.00', '0.00']],
|
||||
[42,['СЗИ3 Л4','X44 : 11', '0.00', '0.00']],
|
||||
[43,['СЗИ3 Л5','X44 :14', '0.00', '0.00']],
|
||||
[44,['СЗИ4 Л4','X45 : 11', '0.00', '0.00']],
|
||||
[45,['СЗИ4 Л5','X45 : 14', '0.00', '0.00']],
|
||||
[46,['БИ РТР №1','X47 : 2', '0.00', '0.00']],
|
||||
[47,['БИ РТР №2','X47 : 5', '0.00', '0.00']],
|
||||
[48,['БИ РТР №3','X47 : 8', '0.00', '0.00']],
|
||||
[49,['БИ РТР №4','X47 : 11', '0.00', '0.00']],
|
||||
[50,['СИ В Лб','Х49 : 21', '0.00', '0.00']],
|
||||
[51,['СИ В ПрБ','Х49 : 19', '0.00', '0.00']],
|
||||
[52,['СИ Г Лб','Х49 : 28', '0.00', '0.00']],
|
||||
[53,['СИ Г ПрБ','Х49 : 30', '0.00', '0.00']],
|
||||
[54,['СИ Д Лб','Х49 : 13', '0.00', '0.00']],
|
||||
[55,['СИ Д ПрБ','Х49 : 11', '0.00', '0.00']],
|
||||
[56,['СИ Е Лб','Х49 : 26', '0.00', '0.00']],
|
||||
[57,['СИ Е ПрБ','Х49 : 35', '0.00', '0.00']]]
|
||||
[11,['Бланк №1','Х6', '0.00', '0.00']],
|
||||
[12,['Бланк №2','Х9', '0.00', '0.00']],
|
||||
[13,['Бланк №3','Х12', '0.00', '0.00']],
|
||||
[14,['Бланк №4','Х15', '0.00', '0.00']],
|
||||
[15,['Бланк №5','Х18', '0.00', '0.00']],
|
||||
[16,['Бланк №6','Х21', '0.00', '0.00']],
|
||||
[17,['Бланк №7','Х24', '0.00', '0.00']],
|
||||
[18,['СЗИ1 Л1','X31 : 11', '0.00', '0.00']],
|
||||
[19,['СЗИ1 Л6','X31 :14', '0.00', '0.00']],
|
||||
[20,['СЗИ1 Л7','X31 : 17', '0.00', '0.00']],
|
||||
[21,['СЗИ2 Л1','X32 : 11', '0.00', '0.00']],
|
||||
[22,['СЗИ2 Л6','X32 : 14', '0.00', '0.00']],
|
||||
[23,['СЗИ2 Л7','X32: 17', '0.00', '0.00']],
|
||||
[24,['СЗИ3 Л1','X33 : 11', '0.00', '0.00']],
|
||||
[25,['СЗИ3 Л6','X33 :14', '0.00', '0.00']],
|
||||
[26,['СЗИ3 Л7','X33: 17', '0.00', '0.00']],
|
||||
[27,['СЗИ4 Л1','X34 : 11', '0.00', '0.00']],
|
||||
[28,['СЗИ4 Л6','X34 :14', '0.00', '0.00']],
|
||||
[29,['СЗИ4 Л7','X34: 17', '0.00', '0.00']],
|
||||
[30,['СЗИ1 Л2','X38 : 11', '0.00', '0.00']],
|
||||
[31,['СЗИ1 Л3','X38 : 14', '0.00', '0.00']],
|
||||
[32,['СЗИ2 Л2','X39 : 11', '0.00', '0.00']],
|
||||
[33,['СЗИ2 Л3','X39 : 14', '0.00', '0.00']],
|
||||
[34,['СЗИ3 Л2','X40 : 11', '0.00', '0.00']],
|
||||
[35,['СЗИ3 Л3','X40 : 14', '0.00', '0.00']],
|
||||
[36,['СЗИ4 Л2','X41 : 11', '0.00', '0.00']],
|
||||
[37,['СЗИ4 Л3','X41 :14', '0.00', '0.00']],
|
||||
[38,['СЗИ1 Л4','X42 : 11', '0.00', '0.00']],
|
||||
[39,['СЗИ1 Л5','X42 :14', '0.00', '0.00']],
|
||||
[40,['СЗИ2 Л4','X43 : 11', '0.00', '0.00']],
|
||||
[41,['СЗИ2 Л5','X43 : 14', '0.00', '0.00']],
|
||||
[42,['СЗИ3 Л4','X44 : 11', '0.00', '0.00']],
|
||||
[43,['СЗИ3 Л5','X44 :14', '0.00', '0.00']],
|
||||
[44,['СЗИ4 Л4','X45 : 11', '0.00', '0.00']],
|
||||
[45,['СЗИ4 Л5','X45 : 14', '0.00', '0.00']],
|
||||
[46,['БИ РТР №1','X47 : 2', '0.00', '0.00']],
|
||||
[47,['БИ РТР №2','X47 : 5', '0.00', '0.00']],
|
||||
[48,['БИ РТР №3','X47 : 8', '0.00', '0.00']],
|
||||
[49,['БИ РТР №4','X47 : 11', '0.00', '0.00']],
|
||||
[50,['СИ В Лб','Х49 : 21', '0.00', '0.00']],
|
||||
[51,['СИ В ПрБ','Х49 : 19', '0.00', '0.00']],
|
||||
[52,['СИ Г Лб','Х49 : 28', '0.00', '0.00']],
|
||||
[53,['СИ Г ПрБ','Х49 : 30', '0.00', '0.00']],
|
||||
[54,['СИ Д Лб','Х49 : 13', '0.00', '0.00']],
|
||||
[55,['СИ Д ПрБ','Х49 : 11', '0.00', '0.00']],
|
||||
[56,['СИ Е Лб','Х49 : 26', '0.00', '0.00']],
|
||||
[57,['СИ Е ПрБ','Х49 : 35', '0.00', '0.00']]]
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
extends Node
|
||||
class_name yems_dev extends Node
|
||||
|
||||
|
||||
class InDev:
|
||||
var id: int ## Идентификатор индекс устройства
|
||||
var dev_name: String ## Имя подключаемого комплекса
|
||||
var connector: String ## Номер разъёма в приборе
|
||||
var delay: float ## Задержка фронта импульса
|
||||
var offset: float ## Смещение фронта импульса
|
||||
var state: int ## Состояние входа
|
||||
var freq: int ## Предполагаемая частота на которой работает комплекс
|
||||
var ports_data: Dictionary ## Словарь состояния портов устройства
|
||||
var tbl_row_id: int ## Индекс устройства в таблице выходов
|
||||
var out_dots: Array ## Список выходных устройств в порядке, как в таблице и точки матрицы
|
||||
var connect_devs: Dictionary ## Список присоединённых устройств
|
||||
var board: String ## Плата в которой находится устройство
|
||||
var id: int ## Идентификатор индекс устройства.
|
||||
var dev_name: String ## Имя подключаемого комплекса.
|
||||
var connector: String ## Номер разъёма в приборе.
|
||||
var delay: float ## Задержка фронта импульса.
|
||||
var offset: float ## Смещение фронта импульса.
|
||||
var state: int ## Состояние входа.
|
||||
var freq: int ## Предполагаемая частота на которой работает комплекс.
|
||||
var ports_data: Dictionary ## Словарь состояния портов устройства.
|
||||
var tbl_row_id: int ## Индекс устройства в таблице выходов.
|
||||
var out_dots: Array ## Список выходных устройств в порядке, как в таблице и точки матрицы.
|
||||
var connect_devs: Dictionary ## Список присоединённых устройств.
|
||||
var board: String ## Плата в которой находится устройство.
|
||||
|
||||
func _init(dev_id : int, params : Array, row_id : int):
|
||||
id = dev_id
|
||||
dev_name = String(params[0])
|
||||
connector = String(params[1])
|
||||
delay = float(params[2])
|
||||
offset = float(params[3])
|
||||
tbl_row_id = row_id
|
||||
func _init(dev_id : int, params : Array, row_id : int):
|
||||
id = dev_id
|
||||
dev_name = String(params[0])
|
||||
connector = String(params[1])
|
||||
delay = float(params[2])
|
||||
offset = float(params[3])
|
||||
tbl_row_id = row_id
|
||||
|
||||
|
||||
class OutDev extends InDev:
|
||||
var mode: String ## Режим работы выхода
|
||||
var mode: String ## Режим работы выхода.
|
||||
|
||||
func _init(dev_id : int, params : Array, row_id : int):
|
||||
id = dev_id
|
||||
dev_name = String(params[0])
|
||||
connector = String(params[1])
|
||||
delay = float(params[2])
|
||||
offset = float(params[3])
|
||||
tbl_row_id = row_id
|
||||
mode = 'Работа'
|
||||
func _init(dev_id : int, params : Array, row_id : int):
|
||||
id = dev_id
|
||||
dev_name = String(params[0])
|
||||
connector = String(params[1])
|
||||
delay = float(params[2])
|
||||
offset = float(params[3])
|
||||
tbl_row_id = row_id
|
||||
mode = 'Работа'
|
||||
|
||||
714
table/table.gd
714
table/table.gd
@@ -57,94 +57,94 @@ func defaultselector_color_proc(_i_row: int): return selector_color
|
||||
## [param scrl] - Прокрутка родитель таблицы.[br]
|
||||
## [param prnt] - Родитель прокрутки.[br]
|
||||
func pin_header(scrl: ScrollContainer, prnt: Control):
|
||||
scrl.remove_child(header)
|
||||
prnt.add_child(header)
|
||||
var v_separation = get_theme_constant('v_separation')
|
||||
header.position = scrl.position - Vector2(0, header.size.y + v_separation)
|
||||
scroll = scrl
|
||||
scroll_adj = scrl.position
|
||||
scrl.remove_child(header)
|
||||
prnt.add_child(header)
|
||||
var v_separation = get_theme_constant('v_separation')
|
||||
header.position = scrl.position - Vector2(0, header.size.y + v_separation)
|
||||
scroll = scrl
|
||||
scroll_adj = scrl.position
|
||||
|
||||
|
||||
## Перемещает указатель на одну строку вверх
|
||||
func selector_up():
|
||||
var i_rows: = []
|
||||
get_selected_rows(i_rows)
|
||||
for i in i_rows:
|
||||
set_row_selected(i, false)
|
||||
var rows_count: = get_rows_count()
|
||||
if not (i_rows.size() and (rows_count > 1)):
|
||||
return
|
||||
var i_row = i_rows[0]
|
||||
i_row -= 1
|
||||
if i_row < 0:
|
||||
i_row = rows_count - 1
|
||||
set_row_selected(i_row, true)
|
||||
var node = get_node2(0, i_row)
|
||||
if scroll is ScrollContainer:
|
||||
scroll.ensure_control_visible(node)
|
||||
emit_signal('selected_changed', i_row)
|
||||
var i_rows: = []
|
||||
get_selected_rows(i_rows)
|
||||
for i in i_rows:
|
||||
set_row_selected(i, false)
|
||||
var rows_count: = get_rows_count()
|
||||
if not (i_rows.size() and (rows_count > 1)):
|
||||
return
|
||||
var i_row = i_rows[0]
|
||||
i_row -= 1
|
||||
if i_row < 0:
|
||||
i_row = rows_count - 1
|
||||
set_row_selected(i_row, true)
|
||||
var node = get_node2(0, i_row)
|
||||
if scroll is ScrollContainer:
|
||||
scroll.ensure_control_visible(node)
|
||||
emit_signal('selected_changed', i_row)
|
||||
|
||||
|
||||
## Перемещает указатель на одну строку вниз
|
||||
func selector_down():
|
||||
var i_rows: = []
|
||||
get_selected_rows(i_rows)
|
||||
for i in i_rows:
|
||||
set_row_selected(i, false)
|
||||
var rows_count: = get_rows_count()
|
||||
if not (i_rows.size() and (rows_count > 1)):
|
||||
return
|
||||
var i_row = i_rows[0]
|
||||
i_row += 1
|
||||
i_row %= rows_count
|
||||
set_row_selected(i_row, true)
|
||||
var node = get_node2(0, i_row)
|
||||
if scroll is ScrollContainer:
|
||||
scroll.ensure_control_visible(node)
|
||||
emit_signal('selected_changed', i_row)
|
||||
var i_rows: = []
|
||||
get_selected_rows(i_rows)
|
||||
for i in i_rows:
|
||||
set_row_selected(i, false)
|
||||
var rows_count: = get_rows_count()
|
||||
if not (i_rows.size() and (rows_count > 1)):
|
||||
return
|
||||
var i_row = i_rows[0]
|
||||
i_row += 1
|
||||
i_row %= rows_count
|
||||
set_row_selected(i_row, true)
|
||||
var node = get_node2(0, i_row)
|
||||
if scroll is ScrollContainer:
|
||||
scroll.ensure_control_visible(node)
|
||||
emit_signal('selected_changed', i_row)
|
||||
|
||||
|
||||
## Делает ряд [param i_row] видимым.
|
||||
func ensure_row_visible(i_row: int):
|
||||
assert(scroll is ScrollContainer, 'Таблица должна быть дочерней к ScrollContainer')
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, 0, i_row)
|
||||
var node = nodes[key]
|
||||
scroll.ensure_control_visible(node)
|
||||
assert(scroll is ScrollContainer, 'Таблица должна быть дочерней к ScrollContainer')
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, 0, i_row)
|
||||
var node = nodes[key]
|
||||
scroll.ensure_control_visible(node)
|
||||
|
||||
|
||||
## Устанавливает выравнивание из массива [param alignments] для всех колонок.
|
||||
func set_columns_alignments(alignments: Array):
|
||||
assert(columns == alignments.size())
|
||||
var rows_count: = get_rows_count()
|
||||
for i_row in rows_count:
|
||||
for i_col in alignments.size():
|
||||
set_node_alligment(i_col, i_row, alignments[i_col])
|
||||
assert(columns == alignments.size())
|
||||
var rows_count: = get_rows_count()
|
||||
for i_row in rows_count:
|
||||
for i_col in alignments.size():
|
||||
set_node_alligment(i_col, i_row, alignments[i_col])
|
||||
|
||||
|
||||
##
|
||||
func load_selector_scene(file_name: String):
|
||||
selector_type_file = file_name
|
||||
ScnSelector = load(file_name)
|
||||
selector_type_file = file_name
|
||||
ScnSelector = load(file_name)
|
||||
|
||||
|
||||
##
|
||||
func load_node_scene(file_name: String):
|
||||
node_type_file = file_name
|
||||
ScnNode = load(file_name)
|
||||
node_type_file = file_name
|
||||
ScnNode = load(file_name)
|
||||
|
||||
|
||||
##
|
||||
func _ready():
|
||||
ScnSelector = load(selector_type_file)
|
||||
ScnNode = load(node_type_file)
|
||||
assert(ScnSelector is PackedScene)
|
||||
assert(ScnNode is PackedScene)
|
||||
ScnSelector = load(selector_type_file)
|
||||
ScnNode = load(node_type_file)
|
||||
assert(ScnSelector is PackedScene)
|
||||
assert(ScnNode is PackedScene)
|
||||
|
||||
|
||||
## Выравнивает по нижнему левому углу. Используется для выравнивания по заголовку.
|
||||
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
|
||||
position.x = hdr.position.x + gap.x
|
||||
position.y = hdr.position.y + hdr.size.y + gap.y
|
||||
|
||||
|
||||
## Устанавливает пользовательские данные для ячейки.[br]
|
||||
@@ -153,9 +153,9 @@ func align_to_left_bottompos(hdr: Control, gap: = Vector2(0, 0)):
|
||||
## [param pname] - Имя пользовательских данных.[br]
|
||||
## [param val] - Значение пользовательских данных.[br]
|
||||
func set_node_meta(i_col: int, i_row: int, pname: String, val) -> void:
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
var node = nodes[key]
|
||||
node.set_meta(pname, val)
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
var node = nodes[key]
|
||||
node.set_meta(pname, val)
|
||||
|
||||
|
||||
## Возвращает пользовательские данные для ячейки.[br]
|
||||
@@ -163,10 +163,10 @@ func set_node_meta(i_col: int, i_row: int, pname: String, val) -> void:
|
||||
## [param i_row] - Индекс ряда.[br]
|
||||
## [param pname] - Имя пользовательских данных.[br]
|
||||
func get_node_meta(i_col: int, i_row: int, pname: String):
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
var node = nodes[key]
|
||||
assert_meta(i_col, i_row, pname, node)
|
||||
return node.get_meta(pname)
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
var node = nodes[key]
|
||||
assert_meta(i_col, i_row, pname, node)
|
||||
return node.get_meta(pname)
|
||||
|
||||
|
||||
## Устанавливает свойство ячейки.[br]
|
||||
@@ -176,9 +176,9 @@ func get_node_meta(i_col: int, i_row: int, pname: String):
|
||||
## [param val] - Значение свойства.[br]
|
||||
## [i]Свойство[/i] [param pname] [i]ячейки должно существовать.[/i]
|
||||
func set_node_property(i_col: int, i_row: int, pname: String, val) -> void:
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
var node = nodes[key]
|
||||
node.set(pname, val)
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
var node = nodes[key]
|
||||
node.set(pname, val)
|
||||
|
||||
|
||||
## Возвращает значение поля ячейки.[br]
|
||||
@@ -186,9 +186,9 @@ func set_node_property(i_col: int, i_row: int, pname: String, val) -> void:
|
||||
## [param i_col] - Индекс колонки.[br]
|
||||
## [param i_row] - Индекс ряда.
|
||||
func get_node_property(i_col: int, i_row: int, pname: String):
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
var node = nodes[key]
|
||||
return node.get(pname)
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
var node = nodes[key]
|
||||
return node.get(pname)
|
||||
|
||||
|
||||
## Возвращает ключ для существующей ячейки. Если ячейки с заданными индексами нет,
|
||||
@@ -196,313 +196,313 @@ func get_node_property(i_col: int, i_row: int, pname: String):
|
||||
## [param i_col] - Индекс колонки.[br]
|
||||
## [param i_row] - Индекс ряда
|
||||
func get_node_key(format: String, i_col: int, i_row: int) -> String:
|
||||
var key: String = format % [i_row, i_col]
|
||||
assert(nodes.has(key), 'ошибка: нет такой ячейки - колонка:%d ряд:%d' % [i_col, i_row])
|
||||
return key
|
||||
var key: String = format % [i_row, i_col]
|
||||
assert(nodes.has(key), 'ошибка: нет такой ячейки - колонка:%d ряд:%d' % [i_col, i_row])
|
||||
return key
|
||||
|
||||
|
||||
## Возвращает массив с индексом ячейки:[br]
|
||||
## [b][0][/b] - индекс колонки,[br]
|
||||
## [b][1][/b] - индекс строки.
|
||||
func get_key_indexes(key: String) -> Array:
|
||||
var tokens: = key.split('_')
|
||||
assert(tokens.size() == 3, 'ошибка: неверный ключ: \"%s\"' % key)
|
||||
return [int(tokens[2]), int(tokens[1])]
|
||||
var tokens: = key.split('_')
|
||||
assert(tokens.size() == 3, 'ошибка: неверный ключ: \"%s\"' % key)
|
||||
return [int(tokens[2]), int(tokens[1])]
|
||||
|
||||
|
||||
##
|
||||
func set_columns_min_size(sizes: Array) -> void:
|
||||
assert((columns == 1) or (columns == sizes.size()))
|
||||
columns = sizes.size()
|
||||
var rows_count: = get_rows_count()
|
||||
columns_min_size.clear()
|
||||
for sz in sizes:
|
||||
columns_min_size.append(sz)
|
||||
for i_row in rows_count:
|
||||
set_nodes_min_size(i_row, sizes, NODE_KEY_FORMAT)
|
||||
if nodes.has(HEAD_KEY_FORMAT % [0, 0]):
|
||||
set_nodes_min_size(0, sizes, HEAD_KEY_FORMAT)
|
||||
assert((columns == 1) or (columns == sizes.size()))
|
||||
columns = sizes.size()
|
||||
var rows_count: = get_rows_count()
|
||||
columns_min_size.clear()
|
||||
for sz in sizes:
|
||||
columns_min_size.append(sz)
|
||||
for i_row in rows_count:
|
||||
set_nodes_min_size(i_row, sizes, NODE_KEY_FORMAT)
|
||||
if nodes.has(HEAD_KEY_FORMAT % [0, 0]):
|
||||
set_nodes_min_size(0, sizes, HEAD_KEY_FORMAT)
|
||||
|
||||
|
||||
##
|
||||
func set_columns_aligment(alignments: Array) -> void:
|
||||
var rows_count: = get_rows_count()
|
||||
for i_row in rows_count:
|
||||
for i_col in alignments.size():
|
||||
set_node_alligment(i_col, i_row, alignments[i_col])
|
||||
var rows_count: = get_rows_count()
|
||||
for i_row in rows_count:
|
||||
for i_col in alignments.size():
|
||||
set_node_alligment(i_col, i_row, alignments[i_col])
|
||||
|
||||
|
||||
##
|
||||
func _input(event) -> void:
|
||||
if not is_visible_in_tree(): return
|
||||
if event is InputEventKey:
|
||||
if event.pressed and in_focus:
|
||||
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')
|
||||
if not is_visible_in_tree(): return
|
||||
if event is InputEventKey:
|
||||
if event.pressed and in_focus:
|
||||
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
|
||||
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))
|
||||
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))
|
||||
|
||||
|
||||
##
|
||||
func setselector_color_proc(instance: Object, function: String) -> void:
|
||||
selector_color_proc = Callable(instance, function)
|
||||
assert(selector_color_proc.is_valid())
|
||||
selector_color_proc = Callable(instance, function)
|
||||
assert(selector_color_proc.is_valid())
|
||||
|
||||
|
||||
##
|
||||
func set_selector_size_proc(instance: Object, function: String) -> void:
|
||||
selector_size_proc = Callable(instance, function)
|
||||
assert(selector_size_proc.is_valid())
|
||||
selector_size_proc = Callable(instance, function)
|
||||
assert(selector_size_proc.is_valid())
|
||||
|
||||
|
||||
## [param i_row] - Индекс ряда
|
||||
func default_selector_size_proc(i_row: int, rect: Array) -> void:
|
||||
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
|
||||
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
|
||||
|
||||
|
||||
##
|
||||
func clear_rows_selected():
|
||||
var rows_count: = get_rows_count()
|
||||
for i_row in rows_count:
|
||||
set_row_selected(i_row, false)
|
||||
var rows_count: = get_rows_count()
|
||||
for i_row in rows_count:
|
||||
set_row_selected(i_row, false)
|
||||
|
||||
|
||||
## [param i_row] - Индекс ряда.
|
||||
func set_row_selected(i_row: int, selected: bool = true) -> void:
|
||||
call_deferred('_set_row_selected', i_row, selected)
|
||||
call_deferred('_set_row_selected', i_row, selected)
|
||||
|
||||
|
||||
## [param i_row] - Индекс ряда.
|
||||
func _set_row_selected(i_row: int, selected: bool = true) -> void:
|
||||
var selector_key: = SELECTOR_KEY_FORMAT % [i_row, 0]
|
||||
var node_key: = NODE_KEY_FORMAT % [i_row, 0]
|
||||
if not nodes.has(node_key):
|
||||
push_error('ошибка: нет такого ряда: %d' % i_row)
|
||||
return
|
||||
if nodes.has(selector_key) and (not selected):
|
||||
var node = nodes[node_key]
|
||||
var selector = nodes[selector_key]
|
||||
node.remove_child(selector)
|
||||
selector.queue_free()
|
||||
nodes.erase(selector_key)
|
||||
elif (not nodes.has(selector_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[selector_key] = selector
|
||||
var node = nodes[node_key]
|
||||
node.add_child(selector)
|
||||
var selector_key: = SELECTOR_KEY_FORMAT % [i_row, 0]
|
||||
var node_key: = NODE_KEY_FORMAT % [i_row, 0]
|
||||
if not nodes.has(node_key):
|
||||
push_error('ошибка: нет такого ряда: %d' % i_row)
|
||||
return
|
||||
if nodes.has(selector_key) and (not selected):
|
||||
var node = nodes[node_key]
|
||||
var selector = nodes[selector_key]
|
||||
node.remove_child(selector)
|
||||
selector.queue_free()
|
||||
nodes.erase(selector_key)
|
||||
elif (not nodes.has(selector_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[selector_key] = selector
|
||||
var node = nodes[node_key]
|
||||
node.add_child(selector)
|
||||
|
||||
|
||||
## [param i_row] - Индекс ряда.
|
||||
func is_row_selected(i_row: int) -> bool:
|
||||
var key: = SELECTOR_KEY_FORMAT % [i_row, 0]
|
||||
return nodes.has(key)
|
||||
var key: = SELECTOR_KEY_FORMAT % [i_row, 0]
|
||||
return nodes.has(key)
|
||||
|
||||
|
||||
## [param i_row] - Индексы рядов.
|
||||
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])
|
||||
for key in nodes.keys():
|
||||
if SLCT_PREFIX in key:
|
||||
var indexes = get_key_indexes(key)
|
||||
i_rows.append(indexes[1])
|
||||
|
||||
|
||||
## Возвращает количество рядов
|
||||
func get_rows_count() -> int:
|
||||
var nodes_count: int = 0
|
||||
for key in nodes:
|
||||
nodes_count += int(NODE_PREFIX in key)
|
||||
return nodes_count / columns
|
||||
var nodes_count: int = 0
|
||||
for key in nodes:
|
||||
nodes_count += int(NODE_PREFIX in key)
|
||||
return nodes_count / columns
|
||||
|
||||
|
||||
## [param i_col] - Индекс колонки. [param i_row] - Индекс ряда.
|
||||
func get_node2(i_col: int, i_row: int) -> Node:
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
return nodes[key]
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
return nodes[key]
|
||||
|
||||
|
||||
## Добавляет ряд. [param row_types] - Массив типов ячеек ряда
|
||||
func add_row(row_types: Array) -> void:
|
||||
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 i_row: int = get_rows_count()
|
||||
assert(i_row < MAX_INDEX, 'ошибка: слишком много рядов, больше %d' % (MAX_INDEX + 1))
|
||||
var allow_set_size = columns_min_size.size() >= row_types.size()
|
||||
for i_col in columns:
|
||||
var node_type = row_types[i_col]
|
||||
var node = node_type.instantiate()
|
||||
assert(node.name == node.name, 'ошибка: экземпляр не имеет поля \"name\"')
|
||||
var node_key: String = NODE_KEY_FORMAT % [i_row, i_col]
|
||||
node.name = node_key
|
||||
add_child(node)
|
||||
if allow_set_size:
|
||||
node.custom_minimum_size.x = columns_min_size[i_col]
|
||||
node.set_deferred('size.x', columns_min_size[i_col])
|
||||
nodes[node_key] = node
|
||||
var conn = Callable(self, '_on_focus_entered').bind(node)
|
||||
node.connect('focus_entered', conn)
|
||||
set_node_meta(i_col, i_row, 'callable_focus_entered', conn)
|
||||
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 i_row: int = get_rows_count()
|
||||
assert(i_row < MAX_INDEX, 'ошибка: слишком много рядов, больше %d' % (MAX_INDEX + 1))
|
||||
var allow_set_size = columns_min_size.size() >= row_types.size()
|
||||
for i_col in columns:
|
||||
var node_type = row_types[i_col]
|
||||
var node = node_type.instantiate()
|
||||
assert(node.name == node.name, 'ошибка: экземпляр не имеет поля \"name\"')
|
||||
var node_key: String = NODE_KEY_FORMAT % [i_row, i_col]
|
||||
node.name = node_key
|
||||
add_child(node)
|
||||
if allow_set_size:
|
||||
node.custom_minimum_size.x = columns_min_size[i_col]
|
||||
node.set_deferred('size.x', columns_min_size[i_col])
|
||||
nodes[node_key] = node
|
||||
var conn = Callable(self, '_on_focus_entered').bind(node)
|
||||
node.connect('focus_entered', conn)
|
||||
set_node_meta(i_col, i_row, 'callable_focus_entered', conn)
|
||||
|
||||
|
||||
##
|
||||
func _on_focus_entered(node):
|
||||
var indexes = get_key_indexes(node.name)
|
||||
emit_signal('row_pressed', indexes[1])
|
||||
var indexes = get_key_indexes(node.name)
|
||||
emit_signal('row_pressed', indexes[1])
|
||||
|
||||
|
||||
##
|
||||
func set_header(header_types: Array):
|
||||
assert(header_types.size() < MAX_INDEX, 'ошибка: количество колонок в заголовке: %d больше допустимого: %d' % [header_types.size(), MAX_INDEX + 1])
|
||||
if columns == 1:
|
||||
set_columns(header_types.size())
|
||||
else:
|
||||
assert(columns == header_types.size(), 'ошибка: количество колонок в заголовке %d, но ранее установлено: %d' % [header_types.size(), columns])
|
||||
var do_adj: = false
|
||||
if not header:
|
||||
header = GridContainer.new()
|
||||
var parent = scroll.get_parent()
|
||||
parent.add_child(header)
|
||||
header.position = position
|
||||
header.columns = header_types.size()
|
||||
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]
|
||||
assert(header_types.size() < MAX_INDEX, 'ошибка: количество колонок в заголовке: %d больше допустимого: %d' % [header_types.size(), MAX_INDEX + 1])
|
||||
if columns == 1:
|
||||
set_columns(header_types.size())
|
||||
else:
|
||||
assert(columns == header_types.size(), 'ошибка: количество колонок в заголовке %d, но ранее установлено: %d' % [header_types.size(), columns])
|
||||
var do_adj: = false
|
||||
if not header:
|
||||
header = GridContainer.new()
|
||||
var parent = scroll.get_parent()
|
||||
parent.add_child(header)
|
||||
header.position = position
|
||||
header.columns = header_types.size()
|
||||
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]
|
||||
|
||||
|
||||
##
|
||||
func set_header_text(headers: Array):
|
||||
assert(columns == headers.size())
|
||||
set_row_text(0, headers, 0, HEAD_KEY_FORMAT)
|
||||
assert(columns == headers.size())
|
||||
set_row_text(0, headers, 0, HEAD_KEY_FORMAT)
|
||||
|
||||
|
||||
## [param i_row] - индекс ряда.
|
||||
func remove_row(i_row: int):
|
||||
var sel_key: String = SELECTOR_KEY_FORMAT % [i_row, 0]
|
||||
var sel_key: String = SELECTOR_KEY_FORMAT % [i_row, 0]
|
||||
|
||||
if nodes.has(sel_key):
|
||||
var selector = nodes[sel_key]
|
||||
var prnt = selector.get_parent()
|
||||
prnt.remove_child(selector)
|
||||
selector.queue_free()
|
||||
nodes.erase(sel_key)
|
||||
if nodes.has(sel_key):
|
||||
var selector = nodes[sel_key]
|
||||
var prnt = selector.get_parent()
|
||||
prnt.remove_child(selector)
|
||||
selector.queue_free()
|
||||
nodes.erase(sel_key)
|
||||
|
||||
for i_col in columns:
|
||||
for i_col in columns:
|
||||
|
||||
var node_key: String = NODE_KEY_FORMAT % [i_row, i_col]
|
||||
var node = nodes[node_key]
|
||||
var node_key: String = NODE_KEY_FORMAT % [i_row, i_col]
|
||||
var node = nodes[node_key]
|
||||
|
||||
var conn = get_node_meta(i_col, i_row, 'callable_focus_entered')
|
||||
node.disconnect('focus_entered', conn)
|
||||
var conn = get_node_meta(i_col, i_row, 'callable_focus_entered')
|
||||
node.disconnect('focus_entered', conn)
|
||||
|
||||
if node.has_meta(META_CALLABLE):
|
||||
conn = node.get_meta(META_CALLABLE)
|
||||
var event_name = node.get_meta(META_EVENT_NAME)
|
||||
node.disconnect(event_name, conn)
|
||||
if node.has_meta(META_CALLABLE):
|
||||
conn = node.get_meta(META_CALLABLE)
|
||||
var event_name = node.get_meta(META_EVENT_NAME)
|
||||
node.disconnect(event_name, conn)
|
||||
|
||||
remove_child(node)
|
||||
nodes.erase(node_key)
|
||||
node.queue_free()
|
||||
rehash()
|
||||
remove_child(node)
|
||||
nodes.erase(node_key)
|
||||
node.queue_free()
|
||||
rehash()
|
||||
|
||||
|
||||
##
|
||||
func next_index(indexes: Array) -> void:
|
||||
indexes[0].x += 1
|
||||
if indexes[0].x == columns:
|
||||
indexes[0].x = 0
|
||||
indexes[0].y += 1
|
||||
indexes[0].x += 1
|
||||
if indexes[0].x == columns:
|
||||
indexes[0].x = 0
|
||||
indexes[0].y += 1
|
||||
|
||||
|
||||
##
|
||||
func swap_nodes(nodes_copy, node_key_format, i0, i1) -> void:
|
||||
var key0 = node_key_format % [i0.y, i0.x]
|
||||
var key1 = node_key_format % [i1.y, i1.x]
|
||||
nodes_copy[key1] = nodes[key0]
|
||||
nodes_copy[key1].name = key1
|
||||
var key0 = node_key_format % [i0.y, i0.x]
|
||||
var key1 = node_key_format % [i1.y, i1.x]
|
||||
nodes_copy[key1] = nodes[key0]
|
||||
nodes_copy[key1].name = key1
|
||||
|
||||
|
||||
## Переназначает ключи в соответствии с размерами таблицы.
|
||||
func rehash():
|
||||
var i_node: = [Vector2i()]
|
||||
var i_hdr: = [Vector2i()]
|
||||
var i_slct: = [Vector2i()]
|
||||
var nodes_copy = {}
|
||||
for key in nodes:
|
||||
var iv = get_key_indexes(key)
|
||||
var i0 = Vector2(iv[0], iv[1])
|
||||
if HEAD_PREFIX in key:
|
||||
swap_nodes(nodes_copy, HEAD_KEY_FORMAT, i0, i_hdr[0])
|
||||
next_index(i_hdr)
|
||||
elif NODE_PREFIX in key:
|
||||
swap_nodes(nodes_copy, NODE_KEY_FORMAT, i0, i_node[0])
|
||||
next_index(i_node)
|
||||
elif SLCT_PREFIX in key:
|
||||
swap_nodes(nodes_copy, SELECTOR_KEY_FORMAT, i0, i_slct[0])
|
||||
next_index(i_slct)
|
||||
nodes.clear()
|
||||
nodes.merge(nodes_copy)
|
||||
var i_node: = [Vector2i()]
|
||||
var i_hdr: = [Vector2i()]
|
||||
var i_slct: = [Vector2i()]
|
||||
var nodes_copy = {}
|
||||
for key in nodes:
|
||||
var iv = get_key_indexes(key)
|
||||
var i0 = Vector2(iv[0], iv[1])
|
||||
if HEAD_PREFIX in key:
|
||||
swap_nodes(nodes_copy, HEAD_KEY_FORMAT, i0, i_hdr[0])
|
||||
next_index(i_hdr)
|
||||
elif NODE_PREFIX in key:
|
||||
swap_nodes(nodes_copy, NODE_KEY_FORMAT, i0, i_node[0])
|
||||
next_index(i_node)
|
||||
elif SLCT_PREFIX in key:
|
||||
swap_nodes(nodes_copy, SELECTOR_KEY_FORMAT, i0, i_slct[0])
|
||||
next_index(i_slct)
|
||||
nodes.clear()
|
||||
nodes.merge(nodes_copy)
|
||||
|
||||
|
||||
## Удаляет все строки таблицы
|
||||
func clear_rows() -> void:
|
||||
var rows_count: int = get_rows_count()
|
||||
for i_row in range(rows_count - 1, -1, -1):
|
||||
remove_row(i_row)
|
||||
var rows_count: int = get_rows_count()
|
||||
for i_row in range(rows_count - 1, -1, -1):
|
||||
remove_row(i_row)
|
||||
|
||||
|
||||
## Настраевает обратные вызовы для колонок.[br]
|
||||
@@ -512,57 +512,57 @@ func clear_rows() -> void:
|
||||
## [param clmns] - Индексы колонок[br]
|
||||
## [param user_data] - Аргументы функции получателя события[br]
|
||||
func connect_columns(dest_node: Node, event_name: String, callback: String, clmns: Array, user_data: Array = []) -> void:
|
||||
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 = get_node2(i_col, i_row)
|
||||
if node.has_meta(META_CALLABLE):
|
||||
var conn_prev = node.get_meta(META_CALLABLE)
|
||||
node.disconnect(event_name, conn_prev)
|
||||
var conn = Callable(dest_node, callback).bind([node] + user_data)
|
||||
var rc = node.connect(event_name, conn)
|
||||
if rc == Error.OK:
|
||||
node.set_meta(META_CALLABLE, conn)
|
||||
node.set_meta(META_EVENT_NAME, event_name)
|
||||
else:
|
||||
var es = error_string(rc)
|
||||
push_error('ошибка: событие \"%s\" не может быть подключено к %s: %s' % [event_name, node, es])
|
||||
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 = get_node2(i_col, i_row)
|
||||
if node.has_meta(META_CALLABLE):
|
||||
var conn_prev = node.get_meta(META_CALLABLE)
|
||||
node.disconnect(event_name, conn_prev)
|
||||
var conn = Callable(dest_node, callback).bind([node] + user_data)
|
||||
var rc = node.connect(event_name, conn)
|
||||
if rc == Error.OK:
|
||||
node.set_meta(META_CALLABLE, conn)
|
||||
node.set_meta(META_EVENT_NAME, event_name)
|
||||
else:
|
||||
var es = error_string(rc)
|
||||
push_error('ошибка: событие \"%s\" не может быть подключено к %s: %s' % [event_name, node, es])
|
||||
|
||||
|
||||
##
|
||||
func set_rows_text(rows: Array) -> void:
|
||||
for i_row in rows.size():
|
||||
for i_col in columns:
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
var node = nodes[key]
|
||||
node.text = rows[i_row][i_col]
|
||||
for i_row in rows.size():
|
||||
for i_col in columns:
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
var node = nodes[key]
|
||||
node.text = rows[i_row][i_col]
|
||||
|
||||
|
||||
## [param i_row] - Индекс ряда.
|
||||
func set_nodes_min_size(i_row: int, sizes: Array, key_format: String = NODE_KEY_FORMAT) -> void:
|
||||
columns_min_size.clear()
|
||||
for sz in sizes:
|
||||
columns_min_size.append(sz)
|
||||
for i_col in columns:
|
||||
var key: = get_node_key(key_format, i_col, i_row)
|
||||
var node = nodes[key]
|
||||
node.custom_minimum_size.x = sizes[i_col]
|
||||
node.set_deferred('size.x', sizes[i_col])
|
||||
columns_min_size.clear()
|
||||
for sz in sizes:
|
||||
columns_min_size.append(sz)
|
||||
for i_col in columns:
|
||||
var key: = get_node_key(key_format, i_col, i_row)
|
||||
var node = nodes[key]
|
||||
node.custom_minimum_size.x = sizes[i_col]
|
||||
node.set_deferred('size.x', sizes[i_col])
|
||||
|
||||
|
||||
## [param i_col] - Индекс колонки.[br][param i_row] - Индекс ряда.
|
||||
func set_node_text(i_col: int, i_row: int, val: String) -> void:
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
nodes[key].text = val
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
nodes[key].text = val
|
||||
|
||||
|
||||
##
|
||||
func set_rows_state(rows: Array) -> void:
|
||||
for i_row in rows.size():
|
||||
for i_col in columns:
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
nodes[key].button_pressed = rows[i_row][i_col]
|
||||
for i_row in rows.size():
|
||||
for i_col in columns:
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
nodes[key].button_pressed = rows[i_row][i_col]
|
||||
|
||||
|
||||
## Устанавливает состояние ячейки.
|
||||
@@ -571,59 +571,59 @@ func set_rows_state(rows: Array) -> void:
|
||||
## [param val] - Новое состояние.[br]
|
||||
## [i]Ячейка должна иметь свойство[/i] [param button_pressed]
|
||||
func set_node_state(i_col: int, i_row: int, val: bool) -> void:
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
nodes[key].button_pressed = val
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
nodes[key].button_pressed = val
|
||||
|
||||
|
||||
## [param i_col] - Индекс колонки.[br]
|
||||
## [param i_row] - Индекс ряда.
|
||||
func set_node_frame(i_col: int, i_row: int, node_name: String, val: int) -> void:
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
var node = nodes[key]
|
||||
var sprite = node.get_node(node_name)
|
||||
sprite.frame = val
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
var node = nodes[key]
|
||||
var sprite = node.get_node(node_name)
|
||||
sprite.frame = val
|
||||
|
||||
|
||||
## Разрешает редактирование ячейки. Ячейка должна иметь свойство [param editable].[br]
|
||||
## [param i_col] - Индекс колонки.[br]
|
||||
## [param i_row] - Индекс ряда.
|
||||
func set_node_editable(i_col: int, i_row: int, val: bool) -> void:
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
nodes[key].editable = val
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
nodes[key].editable = val
|
||||
|
||||
|
||||
## Разрешает редактирование ряда. Ячейки ряда должны иметь свойство [param editable].[br]
|
||||
## [param i_row] - Индекс ряда.
|
||||
func set_row_editable(i_row: int, val: bool) -> void:
|
||||
for i_col in columns:
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
nodes[key].editable = val
|
||||
for i_col in columns:
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
nodes[key].editable = val
|
||||
|
||||
|
||||
## [param i_col] - Индекс колонки.[br]
|
||||
## [param i_row] - Индекс ряда.
|
||||
func set_node_alligment(i_col: int, i_row: int, val: int) -> void:
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
if 'horizontal_alignment' in nodes[key]:
|
||||
nodes[key].horizontal_alignment = val
|
||||
elif 'alignment' in nodes[key]:
|
||||
nodes[key].alignment = val
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
if 'horizontal_alignment' in nodes[key]:
|
||||
nodes[key].horizontal_alignment = val
|
||||
elif 'alignment' in nodes[key]:
|
||||
nodes[key].alignment = val
|
||||
|
||||
|
||||
## [param i_row] - Индекс ряда.
|
||||
func set_row_alligments(i_row: int, aligns: Array) -> void:
|
||||
for i_col in columns:
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
nodes[key].align = aligns[i_col]
|
||||
for i_col in columns:
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
nodes[key].align = aligns[i_col]
|
||||
|
||||
|
||||
## [param i_row] - Индекс ряда.
|
||||
func get_row_text(i_row: int) -> Array:
|
||||
var row: = []
|
||||
for i_col in columns:
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
row.append(nodes[key].text)
|
||||
return row
|
||||
var row: = []
|
||||
for i_col in columns:
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
row.append(nodes[key].text)
|
||||
return row
|
||||
|
||||
|
||||
## Устанавливает текст ячеек ряда.[br]
|
||||
@@ -632,51 +632,51 @@ func get_row_text(i_row: int) -> Array:
|
||||
## [param i_begin] - Начальный индекс колонки начиная с которого установить новые значения.[br]
|
||||
## [i]Ячейки ряда должны иметь свойство[/i] [param text]
|
||||
func set_row_text(i_row: int, row: Array, i_begin: int = 0, key_format: String = NODE_KEY_FORMAT) -> void:
|
||||
assert((i_begin >= 0) and (i_begin < columns))
|
||||
assert((columns - i_begin) >= row.size())
|
||||
for i_col in row.size():
|
||||
var key: = get_node_key(key_format, i_col + i_begin, i_row)
|
||||
nodes[key].text = row[i_col]
|
||||
assert((i_begin >= 0) and (i_begin < columns))
|
||||
assert((columns - i_begin) >= row.size())
|
||||
for i_col in row.size():
|
||||
var key: = get_node_key(key_format, i_col + i_begin, i_row)
|
||||
nodes[key].text = row[i_col]
|
||||
|
||||
|
||||
## Возвращает все строки таблицы в двумерном массиве
|
||||
func get_rows_text() -> Array:
|
||||
var rows_count: = get_rows_count()
|
||||
var rows: = []
|
||||
for i_row in rows_count:
|
||||
var row = get_row_text(i_row)
|
||||
rows.append(row)
|
||||
return rows
|
||||
var rows_count: = get_rows_count()
|
||||
var rows: = []
|
||||
for i_row in rows_count:
|
||||
var row = get_row_text(i_row)
|
||||
rows.append(row)
|
||||
return rows
|
||||
|
||||
|
||||
## Возвращает массив ячеек из ряда [param i_row]
|
||||
func get_row(i_row: int) -> Array:
|
||||
var row: = []
|
||||
for i_col in columns:
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
row.append(nodes[key])
|
||||
return row
|
||||
var row: = []
|
||||
for i_col in columns:
|
||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||
row.append(nodes[key])
|
||||
return row
|
||||
|
||||
|
||||
## Возвращает прямоугольник [param rect] занимаемый ячейкой в ряду [param i_row] и колонке [param i_col].
|
||||
## [param key_format] - Формат ключа ячейки
|
||||
func get_node_rect(i_col: int, i_row: int, rect: Array, key_format: String = NODE_KEY_FORMAT) -> void:
|
||||
assert(rect.size() >= 4, 'ошибка: мало элементов для возврата результата')
|
||||
var key: = get_node_key(key_format, i_col, i_row)
|
||||
var cell = nodes[key]
|
||||
rect[0] = cell.position.x
|
||||
rect[1] = cell.position.y
|
||||
rect[2] = cell.size.x
|
||||
rect[3] = cell.size.y
|
||||
assert(rect.size() >= 4, 'ошибка: мало элементов для возврата результата')
|
||||
var key: = get_node_key(key_format, i_col, i_row)
|
||||
var cell = nodes[key]
|
||||
rect[0] = cell.position.x
|
||||
rect[1] = cell.position.y
|
||||
rect[2] = cell.size.x
|
||||
rect[3] = cell.size.y
|
||||
|
||||
|
||||
## Возвращает прямоугольник [param rect] занимаемый рядом [param i_row].[br]
|
||||
## [param key_format] - Формат ключа ячейки
|
||||
func get_row_rect(i_row: int, rect: Array, key_format: String = NODE_KEY_FORMAT) -> void:
|
||||
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
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user