class_name Iterfer extends Node ## Представление помехи. ## Режимы помехи. const ITERFER_MODE = { 'off': ['Откл', {}, 0], 'srni1': ['СРН-И1', {}, 1], 'srnm2': ['СРН-М2', {}, 2], 'srngps': ['СРН-GPS', {}, 3], 'lchm1': ['ЛЧМ-1', {}, 10], 'lchm2': ['ЛЧМ-2', {}, 16], 'mchm1': ['МЧМ-1', {}, 11], 'pdm2': ['ПД-М2', {}, 12], 'pdm4': ['ПД-М4', {}, 13], 'pdm4s': ['ПД-М4С', {}, 14], 'pdchm': ['ПД-ЧМ', {}, 15], 'svi1': ['СВ-И1', SVI1_PARAMS, 20], 'svm2': ['СВ-М2', SVM2_PARAMS, 21], 'k1': ['K1', K1_PARAMS, 50], 'ozp1': ['ОЗП-1', OZP1_PARAMS, 51] } const K1_PARAMS = {'files': ['K1'], 'call_proc': 'call_all_diap'} const OZP1_PARAMS = {'files': ['OZP1'], 'call_proc': 'call_all_diap'} # Файл : Диапазон: ['имя файла', частота] const SVI1_PARAMS = {'files': {1: ['SVI1_LIT2', 1017], 2: ['SVI1_LIT3', 1156]}, 'call_proc': 'call_diap'} const SVM2_PARAMS = {'files': {1: ['SVM2_LIT2', 1017], 2: ['SVM2_LIT3', 1156]}, 'call_proc': 'call_diap'} const PD_CHM = {'files': { }, 'call_proc': 'call_pd_chm'} const SOURCE_INTERFER = ['th','fs','cu'] const ID_INTERFERS_LEN = 63 ## Размер пула номеров целей. const INTERFER_OFF = 'off' const POW_DEFAULT: float = 100.0 var msg6_num: int = 0 ## Счётчик сообщений "тип 6" var msg8_num: int = 0 ## Счётчик сообщений "тип 8" var id_array: Array ## Массив id воздействий. var thrs: Dictionary ## Словарь воздействия для целей, ключ - id воздействия. var fs: Dictionary ## Словарь воздействий для секторов, ключ - id воздействия. var cu: Dictionary ## Словарь воздействий для 5П-28, ключ - id воздействия. var thrs_dict: Dictionary ## Ссылка на словарь целей var auto_enabled: bool = false ## Режим автомата var emit_enable: bool = true ## Разрешить излучение ## Сеанс помехи. class Interfer: var ispp: int = 0 ## Индекс сеанса. var svk: = 0 ## Состояние сеанса. Ответ КАПСРПБ. Возможные значения в [param ITERFER_STATE]. var krp: String = '' ## Тип помехи. Возможные значения в [param INTERFER_MODE]. var powp: float = 100.0 ## Мощность излучения выраженная в процентах. var kni: = 0.0 ## Курсовой угол направления излучения. var params: = {} ## Параметры помехи. var get_params: Array[String] ## Запрос массива параметров (список запрошенных параметров). var retss: int ## Значение счётчика сообщения в котором был произведён запрос массива параметров. var tick_tx: int ## Тик время обновления цели, мс. var source_interfer: String = '' ## Тип объекта по которой поставлена помеха. var modulation: bool ## Модуляция для включения усилителей var um: float ## Угол места для помехи. var nmfs: int = 0 ## Номер модуля ФС в нумерации СТЦ func _to_string() -> String: return 'номер: %d название: %s частота: %0.1f МГц пеленг: %0.1f гр.' % [ispp, ITERFER_MODE[krp][0], params['freq'], kni] func get_msg6_data(msg_num: int) -> PackedByteArray: var data_to_json : Dictionary = {} data_to_json['ts'] = 6 data_to_json['ss'] = msg_num data_to_json['ispp'] = ispp data_to_json['krp'] = krp data_to_json['nmfs'] = nmfs if krp != INTERFER_OFF: data_to_json['kni'] = kni data_to_json['powp'] = powp data_to_json['params'] = params data_to_json['get'] = get_params var pac = JSON.stringify(data_to_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 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) signal interfer_preparing(ecm: Interfer) ## Вызывается в момент запуска помехи. signal interfer_run(ecm: Interfer) ## Вызывается в момент начала работы помехи. signal interfer_error(ecm: Interfer, msg: String) ## Вызывается при ошибке. signal interfer_update(ecm: Interfer) ## Вызывается при обновлении помехи. signal interfer_resized(ecms: Dictionary) ## Вызывается при изменении количества сеансов помех. ## Отправляет словарь помех в юнит, для запаковки и отправки в 5П28. func on_get_interfers(unit, ecms) -> void: unit.pack_interfers(cu, ecms) ## Автомат выключен func on_manual_control() -> void: auto_enabled = false ## Автомат отключен func on_full_auto() -> void: auto_enabled = true func _ready() -> void: var ecms: Dictionary = {} ## Словарь помех. for i in ID_INTERFERS_LEN: # Заполняет массив ID целей id_array.append(i + 1) var unit_caps = network.get_unit_instance('уарэп-капсрпб') var unit_5p28 = network.get_unit_instance('уарэп-5п28') 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_caps, ecms, resend_timeout)) timer_check_state.start(resend_timeout / 1000.0) unit_caps.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_caps, ecms)) signaller.connect('interfer_rcv', Callable(self, 'on_interfer_rcv').bind(unit_5p28, ecms)) signaller.connect('interfer_new', Callable(self, 'send_ecm').bind(unit_caps)) signaller.connect('interfer_off_all', Callable(self, 'on_interfer_off_all').bind(unit_caps, ecms)) signaller.connect('th_aoa_update', Callable(self, 'on_th_aoa_update').bind(ecms, unit_caps)) signaller.connect('interfer_off', Callable(self, 'on_interfer_off')) signaller.connect('manual_control', Callable(self, 'on_manual_control')) signaller.connect('full_auto', Callable(self, 'on_full_auto')) signaller.connect('interfer_prinuditelno', Callable(self, 'on_interfer_prinuditelno')) signaller.connect('emit_changed', Callable(self, 'on_emit_changed').bind(ecms)) threats.connect('threat_lost', Callable(self, 'on_threats_lost').bind(ecms, unit_caps)) var unit_nav = network.get_unit_instance('навигация') unit_nav.connect('data_received', on_nav_data_received.bind(unit_caps)) threats.connect('threats_resized', Callable(self, 'on_threats_resized')) threats.connect('threat_update', Callable(self, 'on_threats_update').bind(ecms)) func on_nav_data_received(coords: Dictionary, unit_caps): var data_to_json = { 'ts': 8, 'ss': msg8_num, 'roll': coords.get('bk', 0), 'trim': coords.get('kk', 0), 'long': coords.get('longitude', 0), 'lat': coords.get('latitude', 0), 'course': coords.get('k', 0), 'speed': coords.get('speed', 0) } var json_data = JSON.stringify(data_to_json).to_utf8_buffer() unit_caps.tx_stack.append(json_data) msg8_num += 1 msg8_num %= 0xffffffff ## Проверяет состояние отправки пакета и если не доставлен, повторяет отправку. func on_timer_check_state(unit, ecms, resend_timeout) -> void: var tick = Time.get_ticks_msec() for ecm in ecms.values(): if (tick - ecm.tick_tx) >= resend_timeout: send_ecm(ecm, unit) ecm.tick_tx = tick func on_th_aoa_update(threats: Dictionary, ecms: Dictionary, unit) -> void: for thr in threats.values(): var th_id = thr.id for ecm_i in thrs.keys(): if thrs[ecm_i] == th_id: var ecm = ecms[ecm_i] ecm.params['freq'] = thr.freq ecm.kni = thr.aoa send_ecm(ecm, unit) signaller.emit_signal('fs_update_color', ecms) prd.update_fs_state(ecms) if not auto_enabled: return if auto_enabled: for thr in threats.values(): thr.auto_selected = true signaller.emit_signal('interfer_init', 'lchm1', [], interfer.POW_DEFAULT) thr.auto_selected = false ## Производит приём состояния помех. [param unit] -> [param ecms]. func on_data_capsrpb_received(unit0: capsrpb.CapsRpb, ecms: Dictionary) -> void: if not unit0.json_dic.has('ts'): return if not (unit0.json_dic['ts'] is float): return if unit0.json_dic['ts'] != 5: return if not unit0.json_dic.has('msvk'): return if not (unit0.json_dic['msvk'] is Array): return var msvk = unit0.json_dic['msvk'] for dic_msvk in msvk: if not (dic_msvk is Dictionary): continue if dic_msvk.has('ispp'): var ispp = int(dic_msvk['ispp']) var errmsg = dic_msvk.get('errmsg', '') if errmsg: log.error('сеанс %d: \"%s\"' % [ispp, errmsg]) 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, unit0) ## Вызыватся, когда пользователь выбрал помеху и выбраны цели. func on_interfer_create(interfer_name, sel_threats, fs_arr, power, u, ecms) -> void: for item in sel_threats: var param: Dictionary = {} var kni: float = item.aoa var id = item.id param['freq'] = item.freq param['width'] = item.width if (param['width'] < settings.WIDTH_MIN): param['width'] = settings.WIDTH_MIN elif (param['width'] > settings.WIDTH_MAX): param['width'] = settings.WIDTH_MAX interfer_create(u, interfer_name, ecms, param, kni, id, thrs, SOURCE_INTERFER[0], power) for item in fs_arr: var param: Dictionary = {} var kni: float = item[0] var id = item[3] param['freq'] = item[1] param['width'] = item[2] if (param['width'] < settings.WIDTH_MIN): param['width'] = settings.WIDTH_MIN elif (param['width'] > settings.WIDTH_MAX): param['width'] = settings.WIDTH_MAX interfer_create(u, interfer_name, ecms, param, kni, id, fs, SOURCE_INTERFER[1], power) func on_interfer_rcv(interfer_params: Array, unit0, ecms) -> void: var err: bool = false var mode = interfer_params[0] var id = interfer_params[1] var aoa = interfer_params[2] var um = interfer_params[3] if (aoa < 0.0) and (aoa > 360.0): err = true var param: Dictionary = {} if (um < -settings.UM_MIN) and (um > settings.UM_MAX): err = true param['um'] = um param['freq'] = interfer_params[4] if (param['freq'] < settings.FREQ_MIN) and (param['freq'] > settings.FREQ_MAX): err = true param['width'] = interfer_params[5] if (param['width'] < settings.WIDTH_MIN) and (param['width'] > settings.WIDTH_MAX): err = true var interfer_name: = '' 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(unit0, interfer_name, ecms, param, aoa, id, cu, SOURCE_INTERFER[2], POW_DEFAULT) unit0.on_interfer_accept(err) func interfer_create(u, interfer_name, ecms, param, kni, id, dict, source_interfer, power) -> void: var sz = ecms.size() 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 var ecm: Interfer if ecms.has(ispp): ecm = ecms[ispp] else: ecm = Interfer.new() ecm.ispp = ispp ecms[ispp] = ecm ecm.kni = kni ecm.krp = interfer_name ecm.params = param ecm.powp = power ecm.source_interfer = source_interfer ecm.modulation = emit_enable ecm.um = param.get('um', 15.0) # Значение по умолчанию var ecm_params = ITERFER_MODE[interfer_name][1] if ecm_params.has('call_proc'): var call_set_params = Callable(self, ecm_params['call_proc']).bind(ecm, ecm_params) call_set_params.call() var set_nmfs_ok = set_nmfs(ecm) if set_nmfs_ok != Error.OK: log.error('Ошибка выбора модуля ФС для помехи: %s' %[ecm.ispp]) signaller.emit_signal('interfer_new', ecm) if interfer_name == 'off': signaller.emit_signal('interfer_off', ecm, ecms, thrs) thrs.erase(ispp) ecm.tick_tx = Time.get_ticks_msec() send_ecm(ecm, u) if sz != ecms.size(): call_deferred('emit_signal', 'interfer_resized', ecms) func send_ecm(ecm, unit0) -> void: if ecm.krp != INTERFER_OFF: if not emit_enable: return elif not ecm.modulation: return msg6_num += 1 var json_data = ecm.get_msg6_data(msg6_num) unit0.tx_stack.append(json_data) func on_interfer_off_all(unit0, ecms: Dictionary) -> void: for ecm in ecms.values(): ecm.krp = INTERFER_OFF send_ecm(ecm, unit0) signaller.emit_signal('interfer_off', ecm, ecms, thrs) func on_threats_lost(th, ecms, unit0) -> void: for key in interfer.thrs: if interfer.thrs[key] == th.id: var ecm_id = key var ecm = ecms[ecm_id] ecm.krp = INTERFER_OFF send_ecm(ecm, unit0) signaller.emit_signal('interfer_off', ecm, ecms, thrs) func pop_id() -> int: var id = 0 if len(id_array): id = id_array[0] id_array.remove_at(0) return id func push_id(id: int) -> void: id_array.append(id) id_array.sort() func on_emit_changed(state, _ecms) -> void: emit_enable = state func call_all_diap(ecm, ecm_params: Dictionary): ecm.params['filename'] = ecm_params['files'] func call_diap(ecm, ecm_params: Dictionary): var fs_index_arr: Array prd.get_fs_index(ecm, fs_index_arr) if len(fs_index_arr): var band = fs_index_arr[0] / 4 if ecm_params['files'].has(band): ecm.params['filename'] = ecm_params['files'][band][0] ecm.params['freq'] = ecm_params['files'][band][1] func set_nmfs(ecm): var fs_index_arr: Array prd.get_fs_index(ecm, fs_index_arr) if len(fs_index_arr): ecm.nmfs = prd.FS_PRD[fs_index_arr[0]][1] return Error.OK else: return Error.FAILED func on_threats_resized(th_dic): thrs_dict = th_dic func on_threats_update(threat, ecms): if threat.tmod != 'fm': return var th_fm_dict: Dictionary for th_index in thrs_dict: if thrs_dict[th_index].tmod != 'fm': continue var fs_index_arr: Array prd.find_fs_index(thrs_dict[th_index].aoa, thrs_dict[th_index].freq, fs_index_arr) if fs_index_arr.size() == 0: continue if th_fm_dict.has(fs_index_arr[0]): th_fm_dict[fs_index_arr[0]][th_index] = thrs_dict[th_index] else: var th_dict: Dictionary th_fm_dict[fs_index_arr[0]] = th_dict th_fm_dict[fs_index_arr[0]][th_index] = thrs_dict[th_index] for key in th_fm_dict: if len(th_fm_dict[key]) < 2: continue var nmfs = prd.FS_PRD[key][1] for ecm in ecms.values(): if nmfs != ecm.nmfs: continue if ecm.krp != 'pdchm': continue func get_freq_range(freq_range_dict: Dictionary, th_dict: Dictionary): var min_range_abs: int = 6000 var max_range_abs: int = 0 for key_i in th_dict: var min_range: int = 6000 var max_range: int = 0 for key_j in th_dict: if key_i == key_j: continue var freq_range = abs(th_dict[key_i].freq - th_dict[key_j].freq) if freq_range < min_range: min_range = freq_range if freq_range > max_range: max_range = freq_range if min_range < min_range_abs: min_range_abs = min_range if max_range > max_range_abs: max_range_abs = max_range