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)