285 lines
11 KiB
GDScript
285 lines
11 KiB
GDScript
class_name trassa_unit extends Node
|
||
|
||
const ONLINE_TIMEOUT: int = 5000 # Время ожидания данных
|
||
const REQUEST_PERIOD: int = 3000 # Период отправки, мс
|
||
const WORDS_TOTAL: int = 75
|
||
const NOINFO: int = 0x80000000
|
||
|
||
class Trassa extends unit.Unit:
|
||
static var json_conv: = JSON.new() ## Аппарат для разбора JSON сообщений
|
||
var source_addr: = []
|
||
var unit_caps = network.get_unit_instance('уарэп-капсрпб')
|
||
var tx_stack: Array[int] = []
|
||
var msg_counter: int = 0
|
||
var ecms: Dictionary = {} # Словарь всех активных помех
|
||
var srn = 0
|
||
var jtids = 0
|
||
var prinud_but: Array = []
|
||
var forced_buttons: Array = [] # Для хранения ссылок на кнопки
|
||
var json_dic: Dictionary = {} # Для хранения распарсенного JSON
|
||
var target: bool = false # Флаг наличия значения 21930
|
||
var data_type: String = "unknown" # Тип полученных данных: "json" или "binary"
|
||
var current_index: int = 0
|
||
var set_klaster = [
|
||
[390, 510, 224, 50],
|
||
[390, 1065, 250, 100],
|
||
[800, 1065, 274, 50],
|
||
[800, 1210, 300, 100],
|
||
[1065, 1210, 324, 50],
|
||
[1065, 1380, 350, 100],
|
||
[1150, 1380, 374, 50],
|
||
[1150, 2000, 400, 100],
|
||
[1380, 2000, 424, 50],
|
||
[1380, 3500, 450, 100],
|
||
[2000, 3500, 474, 50],
|
||
[2000, 6000, 500, 100],
|
||
[3500, 6000, 524, 50],
|
||
[390, 6000, 374, 50*7]]
|
||
var lfb = 0
|
||
var hfb = 0
|
||
var dap = 0
|
||
var daa = 0
|
||
|
||
# Инициализация
|
||
func _init(nm: StringName, buttons: Array = []) -> void:
|
||
self.name = nm
|
||
self.forced_buttons = buttons
|
||
tx_stack.resize(WORDS_TOTAL)
|
||
tx_stack.fill(NOINFO)
|
||
interfer.connect('interfer_resized', Callable(self, 'on_interfer_resized'))
|
||
|
||
|
||
# Обработка полученного пакета - определение типа
|
||
func parse(rx_data: PackedByteArray, tick: int):
|
||
rx_tick = tick
|
||
if not online:
|
||
online = true
|
||
emit_signal('line_changed', self)
|
||
data_type = detect_data(rx_data)
|
||
if data_type == "json":
|
||
parse_json(rx_data)
|
||
elif data_type == "binary":
|
||
parse_byte(rx_data)
|
||
else:
|
||
emit_signal('parse_failed', self)
|
||
|
||
|
||
# Определение типа данных
|
||
func detect_data(data: PackedByteArray) -> String:
|
||
if data.size() > 0:
|
||
var first_char = data[0]
|
||
if first_char == 123 or first_char == 91:
|
||
return "json"
|
||
if data.size() >= 2:
|
||
var potential_json = data.slice(0, min(100, data.size()))
|
||
var test_string = potential_json.get_string_from_ascii()
|
||
if test_string and (test_string.begins_with("{") or test_string.begins_with("[")):
|
||
return "json"
|
||
return "binary"
|
||
|
||
|
||
# Обработка JSON данных
|
||
func parse_json(rx_data: PackedByteArray) -> void:
|
||
var json_string = rx_data.get_string_from_utf8()
|
||
if json_string:
|
||
if Error.OK == json_conv.parse(json_string):
|
||
json_dic = json_conv.get_data()
|
||
target = check_target(json_dic)
|
||
sector_draw(json_dic)
|
||
emit_signal('data_received', self)
|
||
else:
|
||
emit_signal('parse_failed', self)
|
||
else:
|
||
emit_signal('parse_failed', self)
|
||
|
||
|
||
func sector_draw(data: Dictionary) -> void:
|
||
var sector_data = {
|
||
"draw": false,
|
||
"color": Color.GREEN * Color(1, 1, 1, 0.1),
|
||
"rect": Rect2(),
|
||
"index": 0 }
|
||
if data.get("clean_all", false) == true:
|
||
current_index = 0
|
||
signaller.emit_signal('clear_klaster')
|
||
return
|
||
if data.has("txe") and data.has("rxe"):
|
||
var txe = data["txe"]
|
||
var rxe = data["rxe"]
|
||
if txe == true or rxe == true:
|
||
sector_data["draw"] = true
|
||
if data.has("lfb") and data.has("hfb") and data.has("dap") and data.has("daa"):
|
||
lfb = int(data["lfb"])
|
||
hfb = int(data["hfb"])
|
||
dap = int(data["dap"])
|
||
daa = int(data["daa"])
|
||
for i in range(set_klaster.size()):
|
||
var mapping = set_klaster[i]
|
||
if lfb == mapping[0] and hfb == mapping[1]:
|
||
lfb = mapping[2]
|
||
hfb = mapping[3]
|
||
break
|
||
sector_data["rect"] = Rect2(lfb, daa, dap, hfb)
|
||
sector_data["index"] = sector_index()
|
||
signaller.emit_signal('sector_klaster', sector_data)
|
||
|
||
|
||
func sector_index() -> int:
|
||
current_index += 1
|
||
return current_index - 1
|
||
|
||
|
||
# Обработка бинарных данных
|
||
func parse_byte(rx_data: PackedByteArray):
|
||
var words: Array[int] = []
|
||
var offset: int = 0
|
||
if rx_data.size() < 40:
|
||
emit_signal('parse_failed', self)
|
||
return
|
||
while offset < rx_data.size():
|
||
if offset + 4 <= rx_data.size():
|
||
var word = rx_data.decode_u32(offset)
|
||
words.append(word)
|
||
offset += 4
|
||
else:
|
||
break
|
||
if words.size() < 10:
|
||
emit_signal('parse_failed', self)
|
||
return
|
||
tx_stack.fill(NOINFO)
|
||
tx_stack[0] = words[0] # ID
|
||
tx_stack[1] = msg_counter # Nc
|
||
tx_stack[2] = 0x01 # Nб
|
||
tx_stack[3] = 0x00 # Ск
|
||
tx_stack[4] = 0x0194 # НТС
|
||
tx_stack[5] = (0x0001 << 16) | 0x0080 # Ии
|
||
tx_stack[6] = 0x01 # РКС
|
||
srn = words[7] # SRN
|
||
jtids = words[8] # JTIDS
|
||
btn_trassa_pressed()
|
||
interfer_data()
|
||
tx_stack[74] = _calc_crc(tx_stack)
|
||
emit_signal("data_received", self)
|
||
|
||
|
||
# Проверка на нужный JSON файл
|
||
func check_target(data, current_path: String = "root") -> bool:
|
||
if data == null:
|
||
return false
|
||
if data is int or data is float:
|
||
if int(data) == 21930:
|
||
return true
|
||
return false
|
||
var found = false
|
||
if data is Dictionary:
|
||
for key in data:
|
||
var new_path = current_path + "." + str(key)
|
||
if check_target(data[key], new_path):
|
||
found = true
|
||
elif data is Array:
|
||
for i in range(data.size()):
|
||
var new_path = current_path + "[" + str(i) + "]"
|
||
if check_target(data[i], new_path):
|
||
found = true
|
||
return found
|
||
|
||
|
||
func interfer_data() -> void:
|
||
for i in range(67, 74):
|
||
tx_stack[i] = 0
|
||
for ecm in ecms.values():
|
||
if ecm.svk == 1:
|
||
var nmfs_value = ecm.nmfs
|
||
var fs_key = get_fs_key(nmfs_value)
|
||
if fs_key != NOINFO:
|
||
var string_index = fs_key / 4
|
||
var bit_position = fs_key % 4
|
||
if string_index >= 0 and string_index < 7:
|
||
var target_string = 67 + string_index
|
||
tx_stack[target_string] |= (1 << bit_position)
|
||
|
||
|
||
func get_fs_key(nmfs_value: int) -> int:
|
||
if prd.fs_caps_id.has(nmfs_value):
|
||
return prd.fs_caps_id[nmfs_value]
|
||
return NOINFO
|
||
|
||
|
||
# Отправка пакета от uarep-ctl
|
||
func process(now_tick: int) -> int:
|
||
if online and ((now_tick - rx_tick) > ONLINE_TIMEOUT):
|
||
online = false
|
||
emit_signal('line_changed', self)
|
||
if (now_tick - tx_tick) > REQUEST_PERIOD:
|
||
tx_tick = now_tick
|
||
msg_counter += 1
|
||
interfer_uarep()
|
||
interfer_data()
|
||
var data = PackedByteArray()
|
||
data.resize(WORDS_TOTAL * 4)
|
||
for i in range(WORDS_TOTAL):
|
||
data.encode_u32(i * 4, tx_stack[i])
|
||
tx_data = data
|
||
tx_len = WORDS_TOTAL * 4
|
||
return Error.OK
|
||
return Error.ERR_BUSY
|
||
|
||
|
||
# Контрольная сумма
|
||
func _calc_crc(data: Array) -> int:
|
||
var acc: int = 0
|
||
for i in range(data.size() - 1): # кроме CRC
|
||
if i in [0, 1]:
|
||
continue
|
||
acc = (acc + (data[i] & 0xFFFFFFFF)) & 0xFFFFFFFF
|
||
return acc
|
||
|
||
|
||
# Обновление всех активных помех
|
||
func on_interfer_resized(ecms_dic: Dictionary) -> void: ecms = ecms_dic
|
||
|
||
|
||
func interfer_uarep() -> void:
|
||
tx_stack[65] = 0
|
||
tx_stack[66] = 0
|
||
for ecm in ecms.values():
|
||
if ecm.krp == 'srni1' and ecm.svk == 1:
|
||
tx_stack[65] = 1
|
||
if ecm.krp == 'svi1' and ecm.svk == 1:
|
||
tx_stack[66] = 1
|
||
tx_stack[1] = msg_counter
|
||
|
||
|
||
# Выполнение указаний по кнопке Трасса
|
||
func btn_trassa_pressed() -> void:
|
||
var state = ProjectSettings.get_setting('application/config/Внешнее указание Трасса', false)
|
||
if state == true:
|
||
var tree: SceneTree = Engine.get_main_loop()
|
||
if tree is SceneTree:
|
||
var nodes: Array = tree.get_nodes_in_group('группа-принудительно')
|
||
for btn in nodes:
|
||
if btn.name == 'btn_srn':
|
||
btn.pressed = (srn == 1)
|
||
elif btn.name == 'btn_jtids':
|
||
btn.pressed = (jtids == 1)
|
||
if srn == 1:
|
||
tx_stack[65] = 1
|
||
signaller.emit_signal('interfer_prinuditelno', frm_ecm_list.srn_sectors)
|
||
else:
|
||
tx_stack[65] = 0
|
||
for ecm in ecms.values():
|
||
if ecm.krp == "srni1" and ecm.svk == 1:
|
||
ecm.krp = interfer.INTERFER_OFF
|
||
interfer.send_ecm(ecm, unit_caps)
|
||
signaller.emit_signal('interfer_off', ecm)
|
||
if jtids == 1:
|
||
tx_stack[66] = 1
|
||
signaller.emit_signal('interfer_prinuditelno', frm_ecm_list.jtids_sectors)
|
||
else:
|
||
tx_stack[66] = 0
|
||
for ecm in ecms.values():
|
||
if ecm.krp == 'svi1' and ecm.svk == 1:
|
||
ecm.krp = interfer.INTERFER_OFF
|
||
interfer.send_ecm(ecm, unit_caps)
|
||
signaller.emit_signal('interfer_off', ecm)
|