510 lines
19 KiB
GDScript
510 lines
19 KiB
GDScript
extends Node
|
||
|
||
var id_array: Array # Массив id целей
|
||
var treats : Dictionary # Словарь целей
|
||
var msg_counter : int = 0 # Счётчик отправленных пакетов
|
||
|
||
var g_table: GridContainer
|
||
|
||
|
||
const TableCellType1 = preload('res://ячейка-1.tscn')
|
||
const TableCellType2 = preload('res://кнопка-3.tscn')
|
||
const TableCellType3 = preload('res://кнопка-4.tscn')
|
||
const TableCellType4 = preload('res://заголовок.tscn')
|
||
const TableCellType5 = preload('res://ячейка-2.tscn')
|
||
const TableCellType6 = preload('res://кнопка-5.tscn')
|
||
const TableHeader = preload('res://table/header.tscn')
|
||
|
||
# Индекс колонки: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||
const TABLE_HEADERS = ['ID Цели', 'Курc.град', 'Частота', 'Ш. диап.', 'Ампл.', 'T обновл.', 'Мод.', 'Реж. см. F', 'Ск. пер.', 'Протокол', 'Ст. дол.', 'Ст. шир.', 'Cт. выс.', 'Тек. дол.', 'Тек. шир.', 'Тек. выс.', ]
|
||
const TABLE_HEADER_TYPES = [ TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader]
|
||
const TABLE_HEADER_ALIGNMENTS = [ HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER]
|
||
const TABLE_ROW_TYPES = [ TableCellType1, TableCellType5, TableCellType5, TableCellType5, TableCellType5, TableCellType5, TableCellType6, TableCellType6, TableCellType5, TableCellType6, TableCellType5, TableCellType5, TableCellType5, TableCellType5, TableCellType5, TableCellType5]
|
||
const TABLE_ROW_ALIGNMENTS = [ HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_LEFT, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER]
|
||
const TABLE_COLUMN_SIZES = [ 82, 82, 82, 82, 82, 90, 150, 150, 80, 150, 82, 82, 82, 82, 82, 82]
|
||
|
||
const COLUMN_ID = 0 # Идентификатор цели
|
||
const COLUMN_AOA = 1 # Курсовой угол на источник сигнала, градусы
|
||
const COLUMN_FREQ = 2 # Частота несущей или центральная частота, МГц
|
||
const COLUMN_WIDTH = 3 # Ширина занимаемого диапазона частот, МГц
|
||
const COLUMN_POW = 4 # Уровень принимаемого сигнала, дБ
|
||
const COLUMN_TICK = 5 # Относительное время обнаружения сигнала, мс.
|
||
const COLUMN_TMOD = 6 # Вид модуляции
|
||
const COLUMN_FREQM = 7 # Режим смены частоты.
|
||
const COLUMN_BAUD = 8 # Скорость передачи данных, бит/с
|
||
const COLUMN_PROTO = 9 # Тип протокола источника сигнала.
|
||
const COLUMN_SLON = 10 # Координаты старта, долгота в градусах
|
||
const COLUMN_SLAT = 11 # Координаты старта, широта в градусах
|
||
const COLUMN_SALT = 12 # Координаты старта, высота от уровня моря, метры
|
||
const COLUMN_LAT = 13 # Текущие координаты, долгота в градусах
|
||
const COLUMN_LON = 14 # Текущие координаты, широта в градусах
|
||
const COLUMN_ALT = 15 # Текущая высота, метры
|
||
|
||
# Индексы колонок, которым можно задавать выравнивание текста
|
||
const TABLE_ALLIGNED_COLUMNS = [
|
||
COLUMN_ID,
|
||
COLUMN_AOA,
|
||
COLUMN_FREQ,
|
||
COLUMN_WIDTH,
|
||
COLUMN_POW,
|
||
COLUMN_TICK,
|
||
COLUMN_BAUD,
|
||
COLUMN_SLON,
|
||
COLUMN_SLAT,
|
||
COLUMN_SALT,
|
||
COLUMN_LAT,
|
||
COLUMN_LON,
|
||
COLUMN_ALT ]
|
||
|
||
# Индексы колонок, в которых можно вводит текст
|
||
const TABLE_ENTRY_COLUMNS = [
|
||
COLUMN_AOA,
|
||
COLUMN_FREQ,
|
||
COLUMN_WIDTH,
|
||
COLUMN_POW,
|
||
COLUMN_TICK,
|
||
COLUMN_BAUD,
|
||
COLUMN_SLON,
|
||
COLUMN_SLAT,
|
||
COLUMN_SALT,
|
||
COLUMN_LAT,
|
||
COLUMN_LON,
|
||
COLUMN_ALT ]
|
||
|
||
# Типы модуляции
|
||
const MODE_TYPES = ['<неопр.>', 'am', 'ook', 'ask', 'fm', 'qpsk', 'oqpsk', 'pi4qpsk', 'qam16',
|
||
'qam32', 'qam64', 'qam128', 'qam256', 'qam512', 'fsk', 'cpfsk', 'psk','ofdm']
|
||
|
||
# Режим смены частоты
|
||
const FREQM = ['<неопр.>', 'fhss', 'lfm', 'const']
|
||
|
||
# Протоколы радиомодема
|
||
const M_PROTO = ['<неопр.>', '3dlink', 'skyhopperpro', 'picardiooem', 'solo7', 'j11',
|
||
'mavlink', 'ltm', 'hc12', 'df1', ]
|
||
|
||
# Номера колонок
|
||
const COLUMN_OPT = [[COLUMN_TMOD, MODE_TYPES], [COLUMN_FREQM, FREQM], [COLUMN_PROTO, M_PROTO]]
|
||
const COLUMN_OPT_BTN = [COLUMN_TMOD, COLUMN_FREQM, COLUMN_PROTO]
|
||
const ID_ARRAY_LEN = 100 # Размер пула номеров целей
|
||
|
||
|
||
# Цель
|
||
class Threat:
|
||
# параметры цели, второе значение, разрешение отправки.
|
||
var row: Dictionary = {
|
||
'id':[0,true],
|
||
'aoa':[10.0,true],
|
||
'freq':[2480.0,true],
|
||
'width':[20.0,true],
|
||
'power':[20.0,true],
|
||
'tick':[10,true],
|
||
'tmod':['<неопр.>',false],
|
||
'freqm':['<неопр.>',false],
|
||
'baud':[0.0,false],
|
||
'proto':['<неопр.>',false],
|
||
'slon':[0.0,false],
|
||
'slat':[0.0,false],
|
||
'salt':[0.0,false],
|
||
'lat':[0.0,false],
|
||
'lon':[0.0,false],
|
||
'alt':[0.0,false],
|
||
}
|
||
var row_id: int
|
||
|
||
func _init(th_id : int, row_i: int):
|
||
row.id[0] = th_id
|
||
row_id = row_i
|
||
|
||
func get_data():
|
||
var data_to_send : Dictionary
|
||
for key in row.keys():
|
||
var value = row[key]
|
||
var data = value[0]
|
||
var need_send = value[1]
|
||
if need_send:
|
||
data_to_send[key] = data
|
||
return data_to_send
|
||
|
||
func update_rows():
|
||
var new_rows: Array = []
|
||
new_rows.append(_check_value(row.id))
|
||
new_rows.append(_check_value(row.aoa))
|
||
new_rows.append(_check_value(row.freq))
|
||
new_rows.append(_check_value(row.width))
|
||
new_rows.append(_check_value(row.power))
|
||
new_rows.append(_check_value(row.tick))
|
||
new_rows.append(_check_value(row.tmod))
|
||
new_rows.append(_check_value(row.freqm))
|
||
new_rows.append(_check_value(row.baud))
|
||
new_rows.append(_check_value(row.proto))
|
||
new_rows.append(_check_value(row.slon))
|
||
new_rows.append(_check_value(row.slat))
|
||
new_rows.append(_check_value(row.salt))
|
||
new_rows.append(_check_value(row.lat))
|
||
new_rows.append(_check_value(row.lon))
|
||
new_rows.append(_check_value(row.alt))
|
||
return new_rows
|
||
|
||
|
||
func _check_value(val):
|
||
if val[1]:
|
||
return '%s' % val[0]
|
||
else:
|
||
return ''
|
||
|
||
|
||
func set_aoa(val):
|
||
var value = float(val)
|
||
value = Tools.check_low_high(value, 0, 360)
|
||
value = Tools.check_len(val, value)
|
||
row.aoa[0] = value
|
||
row.aoa[1] = Tools.check_empty(value)
|
||
return value
|
||
|
||
func set_freq(val):
|
||
var value = float(val)
|
||
value = Tools.check_negative(value)
|
||
value = Tools.check_len(val, value)
|
||
row.freq[0] = value
|
||
row.freq[1] = Tools.check_empty(value)
|
||
return value
|
||
|
||
func set_width(val):
|
||
var value = float(val)
|
||
value = Tools.check_negative(value)
|
||
value = Tools.check_len(val, value)
|
||
row.width[0] = value
|
||
row.width[1] = Tools.check_empty(value)
|
||
return value
|
||
|
||
func set_power(val):
|
||
var value = float(val)
|
||
value = Tools.check_negative(value)
|
||
value = Tools.check_len(val, value)
|
||
row.power[0] = value
|
||
row.power[1] = Tools.check_empty(value)
|
||
return value
|
||
|
||
func set_tick(val):
|
||
var value = int(val)
|
||
value = Tools.check_low_high(value, 0, 60000)
|
||
value = Tools.check_len(val, value)
|
||
row.tick[0] = value
|
||
row.tick[1] = Tools.check_empty(value)
|
||
return value
|
||
|
||
func set_baud(val):
|
||
var value = float(val)
|
||
value = Tools.check_negative(value)
|
||
value = Tools.check_len(val, value)
|
||
row.baud[0] = value
|
||
row.baud[1] = Tools.check_empty(value)
|
||
return value
|
||
|
||
func set_slon(val):
|
||
var value = float(val)
|
||
value = Tools.check_low_high(value, -90, 90)
|
||
value = Tools.check_len(val, value)
|
||
row.slon[0] = value
|
||
row.slon[1] = Tools.check_empty(value)
|
||
return value
|
||
|
||
func set_slat(val):
|
||
var value = float(val)
|
||
value = Tools.check_low_high(value, -180, 180)
|
||
value = Tools.check_len(val, value)
|
||
row.slat[0] = value
|
||
row.slat[1] = Tools.check_empty(value)
|
||
return value
|
||
|
||
func set_salt(val):
|
||
var value = float(val)
|
||
value = Tools.check_len(val, value)
|
||
row.salt[0] = value
|
||
row.salt[1] = Tools.check_empty(value)
|
||
return value
|
||
|
||
func set_lon(val):
|
||
var value = float(val)
|
||
value = Tools.check_low_high(value, -90, 90)
|
||
value = Tools.check_len(val, value)
|
||
row.lon[0] = value
|
||
row.lon[1] = Tools.check_empty(value)
|
||
return value
|
||
|
||
func set_lat(val):
|
||
var value = float(val)
|
||
value = Tools.check_low_high(value, -180, 180)
|
||
value = Tools.check_len(val, value)
|
||
row.lat[0] = value
|
||
row.lat[1] = Tools.check_empty(value)
|
||
return value
|
||
|
||
func set_alt_pressed(val):
|
||
var value = float(val)
|
||
value = Tools.check_len(val, value)
|
||
row.alt[0] = value
|
||
row.alt[1] = Tools.check_empty(value)
|
||
return value
|
||
|
||
func set_tmod(val):
|
||
var value = str(val)
|
||
row.tmod[0] = value
|
||
row.tmod[1] = false if value == '<неопр.>' else true
|
||
return value
|
||
|
||
func set_freqm(val):
|
||
var value = str(val)
|
||
row.freqm[0] = value
|
||
row.freqm[1] = false if value == '<неопр.>' else true
|
||
return value
|
||
|
||
func set_proto(val):
|
||
var value = str(val)
|
||
row.proto[0] = value
|
||
row.proto[1] = false if value == '<неопр.>' else true
|
||
return value
|
||
|
||
|
||
func init_treats(table, nodes): # Инициализация вкладки с целями
|
||
for i in range(ID_ARRAY_LEN): # Заполняет массив ID целей
|
||
id_array.append(i+1)
|
||
table.set_header(TABLE_HEADER_TYPES)
|
||
table.set_header_text(TABLE_HEADERS)
|
||
load_treats(table)
|
||
init_table(table, TABLE_COLUMN_SIZES)
|
||
g_table = table
|
||
table.set_columns_min_size(TABLE_COLUMN_SIZES)
|
||
table.connect('row_pressed', Callable(self, 'on_row_pressed').bind(table))
|
||
table.connect_columns(self, 'text_submitted', 'on_edit_entry', TABLE_ENTRY_COLUMNS, [])
|
||
table.connect_columns(self, 'item_selected', 'on_item_selected', COLUMN_OPT_BTN, [])
|
||
nodes.btn_add.connect('button_up', Callable(self, 'on_btn_add').bind(table))
|
||
nodes.btn_del.connect('button_up', Callable(self, 'on_btn_del').bind(table))
|
||
nodes.btn_save.connect('button_up', Callable(self, 'on_btn_save'))
|
||
nodes.thr_gen.connect('button_up', Callable(self, 'on_thr_gen'))
|
||
nodes.btn_load.connect('pressed', Callable(self, 'on_btn_load').bind(table))
|
||
nodes.btn_rt.connect('pressed', Callable(self, 'on_rotate_th').bind(nodes.entry_rt, table))
|
||
var timer = Timer.new()
|
||
timer.connect('timeout', Callable(self, 'on_timeout').bind(nodes.entry_rt, table, nodes.chkbx_rt))
|
||
add_child(timer) #to process
|
||
timer.start(1) #to start
|
||
|
||
func load_treats(table):
|
||
var file = FileAccess.open('user://save.json', FileAccess.READ)
|
||
if file == null:
|
||
return
|
||
var read = file.get_as_text()
|
||
file.close()
|
||
var json_conv: = JSON.new()
|
||
if Error.OK == json_conv.parse(read):
|
||
var json_data = json_conv.get_data()
|
||
for item in json_data:
|
||
if item.has('id'):
|
||
var id = item['id']
|
||
id_array.erase(int(id))
|
||
var threat : = Threat.new(id, table.get_rows_count())
|
||
treats['%d' % id] = threat
|
||
for key in item:
|
||
threat.row[key] = [item[key], true]
|
||
var row = threat.update_rows()
|
||
table.add_row(TABLE_ROW_TYPES)
|
||
table.set_row_text(table.get_rows_count()-1, row)
|
||
table.set_node_user_data(0, table.get_rows_count()-1, threat)
|
||
init_opt_btns(table.get_rows_count()-1, table, threat)
|
||
table.connect_columns(self, 'text_submitted', 'on_edit_entry', TABLE_ENTRY_COLUMNS, [])
|
||
table.connect_columns(self, 'item_selected', 'on_item_selected', COLUMN_OPT_BTN, [])
|
||
|
||
|
||
func on_btn_save():
|
||
var file = FileAccess.open('user://save.json', FileAccess.WRITE)
|
||
var data_to_json : Array
|
||
for key in treats:
|
||
var treat = treats[key]
|
||
var data = treat.get_data()
|
||
data_to_json.append(data)
|
||
var json = JSON.new().stringify(data_to_json)
|
||
file.store_string(json)
|
||
file.close()
|
||
|
||
|
||
func init_table(table: Table, sizes: Array):
|
||
for i_row in table.get_rows_count():
|
||
pass
|
||
|
||
|
||
func init_opt_btns(row : int, table, threat):
|
||
for item in COLUMN_OPT:
|
||
var i: int = 0
|
||
var i_col = item[0]
|
||
var opt_arr = item[1]
|
||
var cell = table.get_node2(i_col, row)
|
||
for opt in opt_arr:
|
||
cell.add_item(opt)
|
||
if i_col == COLUMN_TMOD:
|
||
var mode = threat.row['tmod'][0]
|
||
i = MODE_TYPES.find(mode)
|
||
if i_col == COLUMN_FREQM:
|
||
var freqm = threat.row['freqm'][0]
|
||
i = FREQM.find(freqm)
|
||
if i_col == COLUMN_PROTO:
|
||
var proto = threat.row['proto'][0]
|
||
i = M_PROTO.find(proto)
|
||
cell.select(i)
|
||
|
||
|
||
func on_item_selected(item_num, node):
|
||
var optbtn_text = node[0].text
|
||
var indexis = g_table.get_key_indexes(node[0].name)
|
||
var row_i = indexis[1]
|
||
var col_i = indexis[0]
|
||
var cell = g_table.get_node2(0,row_i)
|
||
var value = set_value(optbtn_text, cell.text, col_i)
|
||
|
||
|
||
func on_edit_entry(text : String, entry):
|
||
var indexis = g_table.get_key_indexes(entry[0].name)
|
||
var row_i = indexis[1]
|
||
var col_i = indexis[0]
|
||
var cell = g_table.get_node2(0,row_i)
|
||
var value = set_value(text, cell.text, col_i)
|
||
entry[0].text = str(value)
|
||
|
||
|
||
func set_value(val : String, treat_id : String, column : int):
|
||
var treat = treats[treat_id]
|
||
match column:
|
||
COLUMN_AOA:
|
||
return treat.set_aoa(val)
|
||
COLUMN_FREQ:
|
||
return treat.set_freq(val)
|
||
COLUMN_WIDTH:
|
||
return treat.set_width(val)
|
||
COLUMN_POW:
|
||
return treat.set_power(val)
|
||
COLUMN_TICK:
|
||
return treat.set_tick(val)
|
||
COLUMN_TMOD:
|
||
return treat.set_tmod(val)
|
||
COLUMN_FREQM:
|
||
return treat.set_freqm(val)
|
||
COLUMN_BAUD:
|
||
return treat.set_baud(val)
|
||
COLUMN_PROTO:
|
||
return treat.set_proto(val)
|
||
COLUMN_SLON:
|
||
return treat.set_slon(val)
|
||
COLUMN_SLAT:
|
||
return treat.set_slat(val)
|
||
COLUMN_SALT:
|
||
return treat.set_salt(val)
|
||
COLUMN_LAT:
|
||
return treat.set_lon(val)
|
||
COLUMN_LON:
|
||
return treat.set_lat(val)
|
||
COLUMN_ALT:
|
||
return treat.set_alt_pressed(val)
|
||
|
||
|
||
func on_row_pressed(i_row: int, table):
|
||
table.clear_rows_selected()
|
||
table.set_row_selected(i_row, true)
|
||
|
||
|
||
func on_btn_add(table):
|
||
var id = pop_id()
|
||
var threat : = Threat.new(id, table.get_rows_count())
|
||
treats['%d' % id] = threat
|
||
var row = threat.update_rows()
|
||
table.add_row(TABLE_ROW_TYPES)
|
||
table.set_row_text(table.get_rows_count()-1, row)
|
||
table.set_node_user_data(0, table.get_rows_count()-1, threat)
|
||
init_opt_btns(table.get_rows_count()-1, table, threat)
|
||
table.connect_columns(self, 'text_submitted', 'on_edit_entry', TABLE_ENTRY_COLUMNS, [])
|
||
table.connect_columns(self, 'item_selected', 'on_item_selected', COLUMN_OPT_BTN, [])
|
||
|
||
|
||
func on_btn_del(table):
|
||
var row_i = []
|
||
table.get_selected_rows(row_i)
|
||
if len(row_i) > 0:
|
||
var cell = table.get_node2(0, row_i[0])
|
||
treats.erase(cell.text)
|
||
table.remove_row(row_i[0])
|
||
for i in table.get_rows_count():
|
||
var treat = table.get_node_user_data(0, i)
|
||
treat.row_id = i
|
||
|
||
|
||
func pop_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)
|
||
|
||
|
||
func get_threats_data():
|
||
var data_to_json : Dictionary
|
||
data_to_json['ts'] = 5
|
||
msg_counter += 1
|
||
data_to_json['ss'] = msg_counter
|
||
data_to_json['msvk'] = []
|
||
for item in Interfers.interfers.values():
|
||
var msvk = {}
|
||
msvk['ispp'] = item.options['ispp']
|
||
msvk['svk'] = item.svk
|
||
data_to_json['msvk'].append(msvk)
|
||
data_to_json['mis'] = []
|
||
for key in treats:
|
||
var treat = treats[key]
|
||
set_ticks(treat)
|
||
var data = treat.get_data()
|
||
data_to_json['mis'].append(data)
|
||
var json = JSON.new().stringify(data_to_json)
|
||
var pac = json.to_utf8_buffer()
|
||
return pac
|
||
|
||
|
||
func set_ticks(treat):
|
||
var tick = Time.get_ticks_msec()
|
||
var cell = g_table.get_node2(COLUMN_TICK, treat.row_id)
|
||
cell.text = str(treat.set_tick(str(tick%60000)))
|
||
|
||
|
||
func on_rotate_th(entry, table):
|
||
if entry.text.is_valid_float():
|
||
for th in treats.values():
|
||
var aoa = th.row.aoa[0]
|
||
aoa += float(entry.text)
|
||
if aoa > 360.0:
|
||
aoa -= 360.0
|
||
elif aoa < 0:
|
||
aoa += 360.0
|
||
th.set_aoa(str(aoa))
|
||
var node_aoa = table.get_node2(1, th.row_id)
|
||
if th.row.aoa[1]:
|
||
node_aoa.text = str(th.row.aoa[0])
|
||
else:
|
||
print_debug('Угол поворота целей задан не верно')
|
||
|
||
|
||
func on_timeout(entry, table, chkbx_rt):
|
||
if chkbx_rt.button_pressed:
|
||
on_rotate_th(entry, table)
|
||
|
||
|
||
func on_btn_load(table):
|
||
for i in table.get_rows_count():
|
||
var cell = table.get_node2(0, 0)
|
||
treats.erase(cell.text)
|
||
table.remove_row(0)
|
||
load_treats(table)
|
||
|
||
|
||
func on_thr_gen():
|
||
print_debug()
|