class_name Iterfer extends Node ## Представление помехи. ## Режимы помехи. const ITERFER_MODE = { INTERFER_OFF: [INTERFER_OFF, {}, 0], 'srni1': ['ПСП + ФМ-2', SRNI1_PARAMS, 1], 'srnm2': ['Линейная ЧМ', SRNM2_PARAMS, 2], 'srngps': [INTERFER_IQFILE, SRNGPS_PARAMS, 3], 'lchm1': ['Линейная ЧМ', LCHM1_PARAMS, 10], 'lchm2': ['Линейная ЧМ', LCHM2_PARAMS, 16], 'mchm1': [INTERFER_IQFILE, MCHM1_PARAMS, 11], 'pdm2': [INTERFER_IQFILE, PDM2_PARAMS, 12], 'pdm4': [INTERFER_IQFILE, PDM4_PARAMS, 13], 'pdm4s': [INTERFER_IQFILE, PDM4S_PARAMS, 14], 'pdchm': [INTERFER_IQFILE, PDCHM_PARAMS, 15], 'svi1': [INTERFER_IQFILE, SVI1_PARAMS, 20], 'svm2': [INTERFER_IQFILE, SVM2_PARAMS, 21], 'k1': [INTERFER_IQFILE, K1_PARAMS, 50], 'ozp1': [INTERFER_IQFILE, OZP1_PARAMS, 51] } const SRNI1_PARAMS = {'par_names' : ['freq', 'width']} const SRNM2_PARAMS = {'par_names' : ['freq', 'width', 'period']} const SRNGPS_PARAMS = {'par_names' : ['freq', 'filename'], 'files': 'SRNGPS.pcm', 'call_proc': 'call_all_diap'} const LCHM1_PARAMS = {'par_names' : ['freq', 'width', 'period']} const LCHM2_PARAMS = {'par_names' : ['freq', 'width', 'period']} const MCHM1_PARAMS = {'par_names' : ['freq', 'filename'], 'files': 'MCHM1.pcm', 'call_proc': 'call_all_diap'} const PDM2_PARAMS = {'par_names' : ['freq', 'filename'], 'files': 'PDM2_20.pcm', 'call_proc': 'call_all_diap'} const PDM4_PARAMS = {'par_names' : ['freq', 'filename'], 'files': 'PDM4_20.pcm', 'call_proc': 'call_all_diap'} const PDM4S_PARAMS = {'par_names' : ['freq', 'filename'], 'files': 'PDM4S_5.pcm', 'call_proc': 'call_all_diap'} const K1_PARAMS = {'files' : 'K1.pcm', 'call_proc' : 'call_all_diap', 'par_names' : ['freq', 'filename']} const OZP1_PARAMS = {'files': 'OZP1.pcm', 'call_proc': 'call_all_diap', 'par_names' : ['freq', 'filename']} # Файл : Диапазон: ['имя файла', частота] const SVI1_PARAMS = {'files': {1: ['SVI1_LIT2.pcm', 1017], 2: ['SVI1_LIT3.pcm', 1156]}, 'call_proc': 'call_diap', 'par_names' : ['freq', 'filename']} const SVM2_PARAMS = {'files': {1: ['SVM2_LIT2.pcm', 1017], 2: ['SVM2_LIT3.pcm', 1156]}, 'call_proc': 'call_diap', 'par_names' : ['freq', 'filename']} # Файл : Ключ (ширина): ['имя файла'] const PDCHM_PARAMS = {'files': { 5 : 'pdchm_5.pcm', 10: 'pdchm__0.pcm', 20: 'pdchm_20.pcm', 40: 'pdchm_40.pcm' }, 'call_proc': 'call_pdchm', 'par_names' : ['freq', 'filename'],} const SOURCE_INTERFER = ['th','fs','cu'] const EXCLUDE_INTERFER = ['srni1', 'srnm2', 'srngps', 'svi1', 'svm2'] const ID_INTERFERS_LEN = 63 ## Размер пула номеров целей. const INTERFER_OFF = 'off' const INTERFER_IQFILE = 'IQ-файл' 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'] = ITERFER_MODE[krp][0] data_to_json['nmfs'] = nmfs if krp != INTERFER_OFF: data_to_json['kni'] = kni data_to_json['powp'] = powp data_to_json['params'] = {} for key in ITERFER_MODE[krp][1]['par_names']: if params.has(key): data_to_json['params'][key] = params[key] 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: 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) var ecms: Dictionary = {} ## Словарь помех. var seczaps: Dictionary = {} ## Словарь секторов запрета 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, seczaps)) 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)) threats.connect('threats_resized', Callable(self, 'on_threats_resized')) threats.connect('threat_update', Callable(self, 'on_threats_update').bind(ecms, unit_caps)) var unit_nav = network.get_unit_instance('навигация') unit_nav.connect('data_received', on_nav_data_received.bind(unit_caps)) func on_nav_data_received(coords: Dictionary, unit_caps): var ship_time = Time.get_datetime_dict_from_system() 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), 'year': ship_time['year'], 'month': ship_time['month'], 'day': ship_time['day'], 'hour': ship_time['hour'], 'minute': ship_time['minute'], 'second': ship_time['second'],} 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_instance, 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_instance) ecm.tick_tx = tick func on_th_aoa_update(threats: Dictionary, ecms: Dictionary, unit_instance) -> 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_instance) 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(unit_instance: capsrpb.CapsRpb, ecms: Dictionary, seczaps: Dictionary) -> void: if not unit_instance.json_dic.has('ts'): return if not tools.type_is_num(unit_instance.json_dic['ts']): return if unit_instance.json_dic['ts'] != 5: return map_msvk_to_ecms(unit_instance, ecms) map_mpchf_to_seczaps(unit_instance, seczaps) ## Извлекает массив состояний выполнения команды func map_msvk_to_ecms(unit_instance: unit.Unit, ecms: Dictionary): var json_dic = unit_instance.json_dic if not json_dic.has('msvk'): return var msvk = unit_instance.json_dic.get('msvk', []) for dic_msvk in msvk: if dic_msvk is not Dictionary: continue if not dic_msvk.has('ispp'): continue 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, unit_instance) ## Извлекает массив пространственно-частотных фильтров func map_mpchf_to_seczaps(unit_instance: unit.Unit, seczaps: Dictionary): var json_dic: = unit_instance.json_dic as Dictionary var mpchf = json_dic.get('mpchf', []) if mpchf is not Array: return for item in mpchf: if item is not Dictionary: continue var id = item.get('index', -1) if id < 0: continue var freq = item.get('freq', 0) if freq == 0: continue ## Вызыватся, когда пользователь выбрал помеху и выбраны цели. 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] var th = null if not interfer_name in EXCLUDE_INTERFER: th = find_threat(item[1], kni) if th != null: param['freq'] = th.freq param['width'] = th.width else: 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 if th == null: interfer_create(u, interfer_name, ecms, param, kni, id, fs, SOURCE_INTERFER[1], power) else: id = th.id interfer_create(u, interfer_name, ecms, param, kni, id, thrs, SOURCE_INTERFER[0], 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 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 call_pdchm(ecm, ecm_params: Dictionary): var temp_key: float = settings.WIDTH_MIN for key in ecm_params['files'].keys(): if key > temp_key: temp_key = key for key in ecm_params['files'].keys(): if key < ecm.params['width']: continue if key < temp_key: temp_key = key ecm.params['filename'] = ecm_params['files'][int(temp_key)] 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, unit_caps): var th_id = threat.id var ecm = null for ecm_i in thrs.keys(): if thrs[ecm_i] == th_id: ecm = ecms[ecm_i] ecm.params['freq'] = threat.freq ecm.kni = threat.aoa set_nmfs(ecm) if threat.tmod != 'fm': if ecm != null: send_ecm(ecm, unit_caps) return var th_fm_dict: Dictionary var fs_index_arr: Array prd.find_fs_index(threat.aoa, threat.freq, fs_index_arr) if fs_index_arr.size() == 0: if ecm != null: send_ecm(ecm, unit_caps) return var fs_index = fs_index_arr[0] var nmfs = prd.FS_PRD[fs_index][1] if ecm == null: for ecm_i in ecms.values(): if nmfs != ecm_i.nmfs: continue if ecm_i.svk != 1: continue ecm = ecm_i if ecm == null: return for th_index in thrs_dict: if thrs_dict[th_index].tmod != 'fm': continue fs_index_arr = [] 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 fs_index_arr[0] != fs_index: continue th_fm_dict[th_index] = thrs_dict[th_index] if len(th_fm_dict) > 1: pass send_ecm(ecm, unit_caps) func get_freq_range(freq_range_dict: Dictionary, th_dict: Dictionary): for key_i in th_dict: var min_range: int = 6000 var key_min = null for key_j in th_dict: if key_i == key_j: continue var width = (th_dict[key_i].width / 2) + (th_dict[key_j].width / 2) var freq_range = abs(th_dict[key_i].freq - th_dict[key_j].freq) + width if freq_range < min_range: key_min = key_j min_range = freq_range var max_width = 0 for key in PDCHM_PARAMS['files'].keys(): if max_width < key: max_width = key if min_range > max_width: th_dict.erase(key_i) continue else: if key_min == null: continue freq_range_dict[key_i] = [th_dict[key_i], th_dict[key_min], min_range] func find_threat(freq: int, aoa: float): var fs_index_arr = [] prd.find_fs_index(aoa, freq, fs_index_arr) if not fs_index_arr.size(): return null var fs_index = fs_index_arr[0] for th in thrs_dict.values(): fs_index_arr = [] prd.find_fs_index(th.aoa, th.freq, fs_index_arr) if not fs_index_arr.size(): continue if fs_index_arr[0] == fs_index: return th return null