Tag Cloudlog as 2.6.19
Tag Cloudlog as 2.6.19
这个提交包含在:
当前提交
5f51d60f49
共有 23 个文件被更改,包括 846 次插入 和 349 次删除
|
|
@ -22,7 +22,7 @@ $config['migration_enabled'] = TRUE;
|
|||
|
|
||||
*/
|
||||
|
||||
$config['migration_version'] = 196;
|
||||
$config['migration_version'] = 199;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
<?php if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
class Activated_gridmap extends CI_Controller {
|
||||
class Activated_gridmap extends CI_Controller
|
||||
{
|
||||
|
||||
function __construct() {
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function index() {
|
||||
public function index()
|
||||
{
|
||||
$data['page_title'] = "Activated Gridsquare Map";
|
||||
|
||||
$this->load->model('bands');
|
||||
|
|
@ -44,7 +47,8 @@ class Activated_gridmap extends CI_Controller {
|
|||
$this->load->view('interface_assets/footer', $footerData);
|
||||
}
|
||||
|
||||
public function getGridsjs() {
|
||||
public function getGridsjs()
|
||||
{
|
||||
$band = $this->security->xss_clean($this->input->post('band'));
|
||||
$mode = $this->security->xss_clean($this->input->post('mode'));
|
||||
$qsl = $this->security->xss_clean($this->input->post('qsl'));
|
||||
|
|
|
|||
|
|
@ -37,27 +37,33 @@ class Clublog extends CI_Controller {
|
|||
|
||||
$this->load->model('clublog_model');
|
||||
|
||||
// Retrieve all station profiles for the user with their QSO counts
|
||||
$station_profiles = $this->clublog_model->all_with_count($clean_userid);
|
||||
|
||||
if($station_profiles->num_rows()){
|
||||
foreach ($station_profiles->result() as $station_row)
|
||||
{
|
||||
// Only process stations that have QSOs to upload
|
||||
if($station_row->qso_total > 0) {
|
||||
// Get QSOs for this station that haven't been uploaded to Clublog yet
|
||||
$data['qsos'] = $this->clublog_model->get_clublog_qsos($station_row->station_id);
|
||||
|
||||
if($data['qsos']->num_rows()){
|
||||
// Generate ADIF file content from the view template
|
||||
$string = $this->load->view('adif/data/clublog', $data, TRUE);
|
||||
|
||||
// Generate a unique ID for the temporary file
|
||||
$ranid = uniqid();
|
||||
|
||||
// Write the ADIF data to a temporary file
|
||||
if ( ! write_file('uploads/clublog'.$ranid.$station_row->station_id.'.adi', $string)) {
|
||||
echo 'Unable to write the file - Make the folder Upload folder has write permissions.';
|
||||
}
|
||||
else {
|
||||
|
||||
// Get details of the created ADIF file
|
||||
$file_info = get_file_info('uploads/clublog'.$ranid.$station_row->station_id.'.adi');
|
||||
|
||||
// initialise the curl request
|
||||
// Initialize the CURL request to Clublog's API endpoint
|
||||
$request = curl_init('https://clublog.org/putlogs.php');
|
||||
|
||||
if($this->config->item('directory') != "") {
|
||||
|
|
@ -138,13 +144,12 @@ class Clublog extends CI_Controller {
|
|||
$this->clublog_model->mark_qsos_sent($clean_station_id);
|
||||
}
|
||||
|
||||
function markallnotsent() {
|
||||
function markallnotsent($station_id) {
|
||||
$clean_station_id = $this->security->xss_clean($station_id);
|
||||
$this->load->model('clublog_model');
|
||||
$this->clublog_model->mark_all_qsos_notsent($clean_station_id);
|
||||
}
|
||||
|
||||
|
||||
// Find DXCC
|
||||
function find_dxcc($callsign) {
|
||||
$clean_callsign = $this->security->xss_clean($callsign);
|
||||
|
|
|
|||
|
|
@ -576,6 +576,12 @@ class User extends CI_Controller
|
|||
$data['user_winkey'] = $q->winkey;
|
||||
}
|
||||
|
||||
if ($this->input->post('user_winkey_websocket')) {
|
||||
$data['user_winkey_websocket'] = $this->input->post('user_winkey_websocket', true);
|
||||
} else {
|
||||
$data['user_winkey_websocket'] = $q->winkey_websocket;
|
||||
}
|
||||
|
||||
$this->load->model('user_options_model');
|
||||
$callbook_type_object = $this->user_options_model->get_options('callbook')->result();
|
||||
|
||||
|
|
@ -730,7 +736,13 @@ class User extends CI_Controller
|
|||
$this->load->view('interface_assets/footer');
|
||||
} else {
|
||||
unset($data);
|
||||
switch ($this->user_model->edit($this->input->post())) {
|
||||
|
||||
|
||||
$post_data = $this->input->post();
|
||||
if (!isset($post_data['user_winkey_websocket'])) {
|
||||
$post_data['user_winkey_websocket'] = '0';
|
||||
}
|
||||
switch ($this->user_model->edit($post_data)) {
|
||||
// Check for errors
|
||||
case EUSERNAMEEXISTS:
|
||||
$data['username_error'] = 'Username <b>' . $this->input->post('user_name', true) . '</b> already in use!';
|
||||
|
|
@ -892,6 +904,7 @@ class User extends CI_Controller
|
|||
$data['user_quicklog_enter'] = $this->input->post('user_quicklog_enter');
|
||||
$data['language'] = $this->input->post('language');
|
||||
$data['user_winkey'] = $this->input->post('user_winkey');
|
||||
$data['user_winkey_websocket'] = $this->input->post('user_winkey_websocket');
|
||||
$data['user_hamsat_key'] = $this->input->post('user_hamsat_key');
|
||||
$data['user_hamsat_workable_only'] = $this->input->post('user_hamsat_workable_only');
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/*
|
||||
* This adds a field to user-table to hold winkey websocket setting
|
||||
*/
|
||||
|
||||
// Migration: 197_add_winkey_websocket
|
||||
class Migration_add_winkey_websocket extends CI_Migration {
|
||||
|
||||
public function up()
|
||||
{
|
||||
// Check if winkey_websocket exists in the user table if not create a boolean field
|
||||
if (!$this->db->field_exists('winkey_websocket', 'users')) {
|
||||
$fields = array(
|
||||
'winkey_websocket boolean default 0',
|
||||
);
|
||||
|
||||
$this->dbforge->add_column('users', $fields);
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->field_exists('winkey_websocket', 'users')) {
|
||||
$this->dbforge->drop_column('users', 'winkey_websocket');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Migration_sat_name_change_hadesicm_so125 extends CI_Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
// update column COL_SAT_NAME to SO-125 if its HADES-ICM
|
||||
$this->db->set('COL_SAT_NAME', 'SO-125');
|
||||
$this->db->where('COL_SAT_NAME', 'HADES-ICM');
|
||||
$this->db->update($this->config->item('table_name'));
|
||||
log_message('info', 'Migration: Updated COL_SAT_NAME to SO-125 for HADES-ICM');
|
||||
|
||||
// update column COL_LOTW_QSL_SENT to N if its SO-125
|
||||
$this->db->set('COL_LOTW_QSL_SENT', 'N');
|
||||
$this->db->where('COL_SAT_NAME', 'SO-125');
|
||||
$this->db->update($this->config->item('table_name'));
|
||||
log_message('info', 'Migration: Set COL_LOTW_QSL_SENT to N for SO-125');
|
||||
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
//Change back to HADES-ICM
|
||||
$this->db->set('COL_SAT_NAME', 'HADES-ICM');
|
||||
$this->db->where('COL_SAT_NAME', 'SO-125');
|
||||
$this->db->update($this->config->item('table_name'));
|
||||
log_message('info', 'Migration: Reverted COL_SAT_NAME back to HADES-ICM');
|
||||
|
||||
// Set COL_LOTW_QSL_SENT back to N for HADES-ICM
|
||||
$this->db->set('COL_LOTW_QSL_SENT', 'N');
|
||||
$this->db->where('COL_SAT_NAME', 'HADES-ICM');
|
||||
$this->db->update($this->config->item('table_name'));
|
||||
log_message('info', 'Migration: Reverted COL_LOTW_QSL_SENT back to N for HADES-ICM');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/*
|
||||
* Tag Cloudlog as 2.6.19
|
||||
*/
|
||||
|
||||
class Migration_tag_2_6_19 extends CI_Migration {
|
||||
|
||||
public function up()
|
||||
{
|
||||
|
||||
// Tag Cloudlog 2.6.19
|
||||
$this->db->where('option_name', 'version');
|
||||
$this->db->update('options', array('option_value' => '2.6.19'));
|
||||
|
||||
// Trigger Version Info Dialog
|
||||
$this->db->where('option_type', 'version_dialog');
|
||||
$this->db->where('option_name', 'confirmed');
|
||||
$this->db->update('user_options', array('option_value' => 'false'));
|
||||
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->db->where('option_name', 'version');
|
||||
$this->db->update('options', array('option_value' => '2.6.18'));
|
||||
}
|
||||
}
|
||||
|
|
@ -267,6 +267,7 @@ class User_Model extends CI_Model {
|
|||
'user_quicklog_enter' => xss_clean($fields['user_quicklog_enter']),
|
||||
'language' => xss_clean($fields['language']),
|
||||
'winkey' => xss_clean($fields['user_winkey']),
|
||||
'winkey_websocket' => xss_clean($fields['user_winkey_websocket']),
|
||||
);
|
||||
|
||||
$this->db->query("replace into user_options (user_id, option_type, option_name, option_key, option_value) values (" . $fields['id'] . ", 'hamsat','hamsat_key','api','".xss_clean($fields['user_hamsat_key'])."');");
|
||||
|
|
@ -426,6 +427,7 @@ class User_Model extends CI_Model {
|
|||
'active_station_logbook' => $u->row()->active_station_logbook,
|
||||
'language' => isset($u->row()->language) ? $u->row()->language: 'english',
|
||||
'isWinkeyEnabled' => $u->row()->winkey,
|
||||
'isWinkeyWebsocketEnabled' => (bool)$u->row()->winkey_websocket,
|
||||
'hasQrzKey' => $this->hasQrzKey($u->row()->user_id),
|
||||
'callbook_type' => $callbook_type,
|
||||
'callbook_username' => $callbook_username,
|
||||
|
|
|
|||
|
|
@ -1125,11 +1125,222 @@ if ($this->session->userdata('user_id') != null) {
|
|||
<?php if ($this->uri->segment(1) == "qso") { ?>
|
||||
|
||||
<script src="<?php echo base_url(); ?>assets/js/sections/qso.js"></script>
|
||||
<?php if ($this->session->userdata('isWinkeyEnabled')) { ?>
|
||||
<?php if ($this->session->userdata('isWinkeyEnabled') && !$this->session->userdata('isWinkeyWebsocketEnabled')) { ?>
|
||||
<script src="<?php echo base_url(); ?>assets/js/winkey.js"></script>
|
||||
<?php }
|
||||
<?php } elseif ($this->session->userdata('isWinkeyEnabled') && $this->session->userdata('isWinkeyWebsocketEnabled')) { ?>
|
||||
<script>
|
||||
console.log('Winkey Websocket enabled');
|
||||
</script>
|
||||
|
||||
if ($this->optionslib->get_option('dxcache_url') != '') { ?>
|
||||
<script>
|
||||
let ws = null;
|
||||
|
||||
function connectWebSocket() {
|
||||
if (ws !== null) {
|
||||
ws.close();
|
||||
}
|
||||
|
||||
const chatRoom = "cw_room";
|
||||
const wsUrl = `ws://localhost:8181?chatRoom=${encodeURIComponent(chatRoom)}`;
|
||||
|
||||
ws = new WebSocket(wsUrl);
|
||||
|
||||
ws.onopen = function() {
|
||||
document.getElementById('cw_socket_status').className = 'badge bg-success';
|
||||
document.getElementById('cw_socket_status').innerHTML = `Status: Connected`;
|
||||
logMessage(`Connected to WebSocket server in room: ${chatRoom}`);
|
||||
};
|
||||
|
||||
ws.onclose = function() {
|
||||
document.getElementById('cw_socket_status').className = 'badge bg-secondary';
|
||||
document.getElementById('cw_socket_status').innerHTML = 'Status: Disconnected';
|
||||
logMessage('Disconnected from WebSocket server');
|
||||
ws = null;
|
||||
};
|
||||
|
||||
ws.onerror = function(error) {
|
||||
logMessage('WebSocket Error: ' + error);
|
||||
};
|
||||
|
||||
ws.onmessage = function(event) {
|
||||
logMessage('Received: ' + event.data);
|
||||
};
|
||||
}
|
||||
|
||||
function disconnectWebSocket() {
|
||||
if (ws !== null) {
|
||||
ws.close();
|
||||
}
|
||||
}
|
||||
|
||||
function sendMessage() {
|
||||
if (ws === null) {
|
||||
alert('Please connect to the WebSocket server first');
|
||||
return;
|
||||
}
|
||||
|
||||
const message = document.getElementById('message').value;
|
||||
if (message.trim() === '') {
|
||||
alert('Please enter a message');
|
||||
return;
|
||||
}
|
||||
|
||||
// Prefix the message with "CW:" to indicate it's a CW message
|
||||
const cwMessage = 'CW:' + message;
|
||||
ws.send(cwMessage);
|
||||
logMessage('Sent: ' + cwMessage);
|
||||
|
||||
// Clear the input field
|
||||
document.getElementById('message').value = '';
|
||||
}
|
||||
|
||||
function logMessage(message) {
|
||||
const messageLog = document.getElementById('messageLog');
|
||||
messageLog.value += message + '\n';
|
||||
// Auto-scroll to bottom
|
||||
messageLog.scrollTop = messageLog.scrollHeight;
|
||||
}
|
||||
|
||||
// Support for Enter key in the input field
|
||||
document.getElementById('message').addEventListener('keypress', function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
sendMessage();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
connectWebSocket();
|
||||
|
||||
|
||||
function morsekey_func1() {
|
||||
console.log("F1: " + UpdateMacros(function1Macro));
|
||||
|
||||
const cwMessage = 'CW:' + UpdateMacros(function1Macro);
|
||||
ws.send(cwMessage);
|
||||
}
|
||||
|
||||
function morsekey_func2() {
|
||||
console.log("F2: " + UpdateMacros(function2Macro));
|
||||
const cwMessage = 'CW:' + UpdateMacros(function2Macro);
|
||||
ws.send(cwMessage);
|
||||
}
|
||||
|
||||
function morsekey_func3() {
|
||||
console.log("F3: " + UpdateMacros(function3Macro));
|
||||
const cwMessage = 'CW:' + UpdateMacros(function3Macro);
|
||||
ws.send(cwMessage);
|
||||
}
|
||||
|
||||
function morsekey_func4() {
|
||||
console.log("F4: " + UpdateMacros(function4Macro));
|
||||
const cwMessage = 'CW:' + UpdateMacros(function4Macro);
|
||||
ws.send(cwMessage);
|
||||
}
|
||||
|
||||
function morsekey_func5() {
|
||||
console.log("F5: " + UpdateMacros(function5Macro));
|
||||
const cwMessage = 'CW:' + UpdateMacros(function5Macro);
|
||||
ws.send(cwMessage);
|
||||
}
|
||||
|
||||
let function1Name, function1Macro, function2Name, function2Macro, function3Name, function3Macro, function4Name, function4Macro, function5Name, function5Macro;
|
||||
|
||||
getMacros();
|
||||
|
||||
document.addEventListener('keydown', function(event) {
|
||||
|
||||
if (event.key === 'F1') {
|
||||
event.preventDefault();
|
||||
morsekey_func1();
|
||||
}
|
||||
|
||||
if (event.key === 'F2') {
|
||||
event.preventDefault();
|
||||
morsekey_func2();
|
||||
}
|
||||
|
||||
if (event.key === 'F3') {
|
||||
event.preventDefault();
|
||||
morsekey_func3();
|
||||
}
|
||||
|
||||
if (event.key === 'F4') {
|
||||
event.preventDefault();
|
||||
morsekey_func4();
|
||||
}
|
||||
|
||||
if (event.key === 'F5') {
|
||||
event.preventDefault();
|
||||
morsekey_func5();
|
||||
}
|
||||
});
|
||||
|
||||
function UpdateMacros(macrotext) {
|
||||
|
||||
// Get the values from the form set to uppercase
|
||||
let CALL = document.getElementById("callsign").value.toUpperCase();
|
||||
let RSTS = document.getElementById("rst_sent").value;
|
||||
|
||||
let newString;
|
||||
newString = macrotext.replace(/\[MYCALL\]/g, my_call);
|
||||
newString = newString.replace(/\[CALL\]/g, CALL);
|
||||
newString = newString.replace(/\[RSTS\]/g, RSTS);
|
||||
console.log(newString);
|
||||
return newString;
|
||||
}
|
||||
|
||||
// Call url and store the returned json data as variables
|
||||
function getMacros() {
|
||||
fetch(base_url + 'index.php/qso/cwmacros_json')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
function1Name = data.function1_name;
|
||||
function1Macro = data.function1_macro;
|
||||
function2Name = data.function2_name;
|
||||
function2Macro = data.function2_macro;
|
||||
function3Name = data.function3_name;
|
||||
function3Macro = data.function3_macro;
|
||||
function4Name = data.function4_name;
|
||||
function4Macro = data.function4_macro;
|
||||
function5Name = data.function5_name;
|
||||
function5Macro = data.function5_macro;
|
||||
|
||||
const morsekey_func1_Button = document.getElementById('morsekey_func1');
|
||||
morsekey_func1_Button.textContent = 'F1 (' + function1Name + ')';
|
||||
|
||||
const morsekey_func2_Button = document.getElementById('morsekey_func2');
|
||||
morsekey_func2_Button.textContent = 'F2 (' + function2Name + ')';
|
||||
|
||||
const morsekey_func3_Button = document.getElementById('morsekey_func3');
|
||||
morsekey_func3_Button.textContent = 'F3 (' + function3Name + ')';
|
||||
|
||||
const morsekey_func4_Button = document.getElementById('morsekey_func4');
|
||||
morsekey_func4_Button.textContent = 'F4 (' + function4Name + ')';
|
||||
|
||||
const morsekey_func5_Button = document.getElementById('morsekey_func5');
|
||||
morsekey_func5_Button.textContent = 'F5 (' + function5Name + ')';
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function sendMyMessage() {
|
||||
const message = document.getElementById('sendText').value;
|
||||
if (message.trim() === '') {
|
||||
alert('Please enter a message');
|
||||
return;
|
||||
}
|
||||
|
||||
const cwMessage = 'CW:' + message;
|
||||
ws.send(cwMessage);
|
||||
logMessage('Sent: ' + cwMessage);
|
||||
|
||||
// Clear the input field
|
||||
document.getElementById('sendText').value = '';
|
||||
}
|
||||
</script>
|
||||
<?php } ?>
|
||||
<?php if ($this->optionslib->get_option('dxcache_url') != '') { ?>
|
||||
<script type="text/javascript">
|
||||
var dxcluster_provider = '<?php echo base_url(); ?>index.php/dxcluster';
|
||||
$(document).ready(function() {
|
||||
|
|
@ -1470,7 +1681,7 @@ if ($this->session->userdata('user_id') != null) {
|
|||
$('#notice-alerts').delay(1000).fadeOut(5000);
|
||||
|
||||
function setRst(mode) {
|
||||
if (mode == 'JT65' || mode == 'JT65B' || mode == 'JT6C' || mode == 'JTMS' || mode == 'ISCAT' || mode == 'MSK144' || mode == 'JTMSK' || mode == 'QRA64' || mode == 'FT8' || mode == 'FT4' || mode == 'JS8' || mode == 'JT9' || mode == 'JT9-1' || mode == 'ROS') {
|
||||
if (mode == 'JT65' || mode == 'JT65B' || mode == 'JT6C' || mode == 'JTMS' || mode == 'ISCAT' || mode == 'MSK144' || mode == 'JTMSK' || mode == 'QRA64' || mode == 'FT8' || mode == 'FT4' || mode == 'JS8' || mode == 'JT9' || mode == 'JT9-1' || mode == 'ROS' || mode == 'Q65' || mode == 'FST4' || mode == 'FST4W') {
|
||||
$('#rst_sent').val('-5');
|
||||
$('#rst_rcvd').val('-5');
|
||||
} else if (mode == 'FSK441' || mode == 'JT6M') {
|
||||
|
|
@ -1622,6 +1833,28 @@ if ($this->session->userdata('user_id') != null) {
|
|||
|
||||
// Event listeners
|
||||
$(document).ready(() => {
|
||||
|
||||
/**
|
||||
* Prevents multiple form submissions by tracking submission state
|
||||
*
|
||||
* This script prevents duplicate QSO (contact) submissions by:
|
||||
* - Maintaining an isSubmitting flag to track form submission state
|
||||
* - Adding an event listener to the 'qso_input' form
|
||||
* - Preventing form submission if a submission is already in progress
|
||||
* - Setting the flag to true when a valid submission begins
|
||||
*
|
||||
* @since Unknown
|
||||
* @global boolean isSubmitting Flag to track if form is currently being submitted
|
||||
*/
|
||||
let isSubmitting = false;
|
||||
document.getElementById('qso_input').addEventListener('submit', function(e) {
|
||||
if (isSubmitting) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
isSubmitting = true;
|
||||
});
|
||||
|
||||
// Update frequency every three seconds for the selected radio
|
||||
setInterval(() => {
|
||||
const selectedRadioID = $('select.radios option:selected').val();
|
||||
|
|
|
|||
|
|
@ -673,9 +673,49 @@
|
|||
|
||||
<!-- Winkey Starts -->
|
||||
|
||||
<?php if ($this->session->userdata('isWinkeyEnabled') && $this->session->userdata('isWinkeyWebsocketEnabled')) { ?>
|
||||
<div id="winkey" class="card winkey-settings" style="margin-bottom: 10px;">
|
||||
<div class="card-header">
|
||||
<h4 style="font-size: 16px; font-weight: bold;" class="card-title">Winkey Web Sockets
|
||||
|
||||
<div id="cw_socket_status" class="badge text-bg-danger">
|
||||
Status: Disconnected
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-secondary"
|
||||
hx-get="<?php echo base_url(); ?>index.php/qso/winkeysettings"
|
||||
hx-target="#modals-here"
|
||||
hx-trigger="click"
|
||||
class="btn btn-primary"
|
||||
_="on htmx:afterOnLoad wait 10ms then add .show to #modal then add .show to #modal-backdrop"><i class="fas fa-cog"></i> Settings</button>
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<div id="modals-here"></div>
|
||||
|
||||
<div id="winkey_buttons" class="card-body">
|
||||
<button id="morsekey_func1" onclick="morsekey_func1()" class="btn btn-warning">F1</button>
|
||||
<button id="morsekey_func2" onclick="morsekey_func2()" class="btn btn-warning">F2</button>
|
||||
<button id="morsekey_func3" onclick="morsekey_func3()" class="btn btn-warning">F3</button>
|
||||
<button id="morsekey_func4" onclick="morsekey_func4()" class="btn btn-warning">F4</button>
|
||||
<button id="morsekey_func5" onclick="morsekey_func5()" class="btn btn-warning">F5</button>
|
||||
<br><br>
|
||||
<input id="sendText" type="text"><input onclick="sendMyMessage()" id="sendButton" type="button" value="Send" class="btn btn-success">
|
||||
|
||||
<div>
|
||||
<strong>Message Log:</strong>
|
||||
<textarea id="messageLog" class="form-control mt-2" rows="4" readonly></textarea>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
|
||||
<?php
|
||||
// if isWinkeyEnabled in session data is true
|
||||
if ($this->session->userdata('isWinkeyEnabled')) { ?>
|
||||
// if isWinkeyEnabled in session data is true and isWinkeyWebsocketEnabled is false
|
||||
|
||||
if ($this->session->userdata('isWinkeyEnabled') && !$this->session->userdata('isWinkeyWebsocketEnabled')) { ?>
|
||||
|
||||
<div id="winkey" class="card winkey-settings" style="margin-bottom: 10px;">
|
||||
<div class="card-header">
|
||||
|
|
|
|||
|
|
@ -8,7 +8,10 @@
|
|||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h2><?php echo $page_title; ?></h2>
|
||||
<a href="<?php echo site_url('station/create'); ?>" class="btn btn-primary"><i class="fas fa-plus"></i> <?php echo lang('station_location_create'); ?></a>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
|
|
@ -16,8 +19,6 @@
|
|||
<p class="card-text"><?php echo lang('station_location_header_ln2'); ?></p>
|
||||
<p class="card-text"><?php echo lang('station_location_header_ln3'); ?></p>
|
||||
|
||||
<p><a href="<?php echo site_url('station/create'); ?>" class="btn btn-primary"><i class="fas fa-plus"></i> <?php echo lang('station_location_create'); ?></a></p>
|
||||
|
||||
<?php if ($stations->num_rows() > 0) { ?>
|
||||
|
||||
<?php if($current_active == 0) { ?>
|
||||
|
|
@ -28,8 +29,7 @@
|
|||
|
||||
<?php if (($is_there_qsos_with_no_station_id >= 1) && ($is_admin)) { ?>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<span class="badge rounded-pill text-bg-warning"><?php echo lang('general_word_warning'); ?></span> <?php echo lang('station_location_warning_reassign'); ?>
|
||||
</br>
|
||||
<span class="badge rounded-pill text-bg-warning"><?php echo lang('general_word_warning'); ?></span> <?php echo lang('station_location_warning_reassign'); ?> <br>
|
||||
<?php echo lang('station_location_reassign_at'); ?> <a href="<?php echo site_url('maintenance/'); ?>" class="btn btn-warning"><i class="fas fa-sync"></i><?php echo lang('account_word_admin') . "/" . lang('general_word_maintenance'); ?></a>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
|
@ -73,17 +73,16 @@
|
|||
<?php if($row->user_id == "") { ?>
|
||||
<a href="<?php echo site_url('station/claim_user')."/".$row->station_id; ?>" class="btn btn-outline-primary btn-sm"><i class="fas fa-user-plus"></i> <?php echo lang('station_location_claim_ownership'); ?></a>
|
||||
<?php } ?>
|
||||
<a href="<?php echo site_url('station/edit')."/".$row->station_id; ?>" title=<?php echo lang('admin_edit'); ?> class="btn btn-outline-primary btn-sm"><i class="fas fa-edit"></i></a>
|
||||
<a href="<?php echo site_url('station/edit')."/".$row->station_id; ?>" title="<?php echo lang('admin_edit'); ?>" class="btn btn-outline-primary btn-sm"><i class="fas fa-edit"></i></a>
|
||||
</td>
|
||||
<td style="text-align: center; vertical-align: middle;">
|
||||
<a href="<?php echo site_url('station/copy')."/".$row->station_id; ?>" title=<?php echo lang('admin_copy'); ?> class="btn btn-outline-primary btn-sm"><i class="fas fa-copy"></i></a>
|
||||
<a href="<?php echo site_url('station/copy')."/".$row->station_id; ?>" title="<?php echo lang('admin_copy'); ?>" class="btn btn-outline-primary btn-sm"><i class="fas fa-copy"></i></a>
|
||||
</td>
|
||||
<td style="text-align: center; vertical-align: middle;">
|
||||
<a href="<?php echo site_url('station/deletelog')."/".$row->station_id; ?>" class="btn btn-danger btn-sm" title=<?php echo lang('station_location_emptylog'); ?> onclick="return confirm('<?php echo lang('station_location_confirm_del_qso'); ?>');"><i class="fas fa-trash-alt"></i></a></td>
|
||||
<td style="text-align: center; vertical-align: middle;"> <a href="<?php echo site_url('station/deletelog')."/".$row->station_id; ?>" class="btn btn-danger btn-sm" title="<?php echo lang('station_location_emptylog'); ?>" onclick="return confirm('<?php echo lang('station_location_confirm_del_qso'); ?>');"><i class="fas fa-trash-alt"></i></a>
|
||||
</td>
|
||||
<td style="text-align: center; vertical-align: middle;">
|
||||
<?php if($row->station_active != 1) { ?>
|
||||
<a href="<?php echo site_url('station/delete')."/".$row->station_id; ?>" class="btn btn-danger btn-sm" title=<?php echo lang('admin_delete'); ?> onclick="return confirm('<?php echo lang('station_location_confirm_del_stationlocation'); ?> <?php echo $row->station_profile_name; ?> <?php echo lang('station_location_confirm_del_stationlocation_qso'); ?>');"><i class="fas fa-trash-alt"></i></a>
|
||||
<a href="<?php echo site_url('station/delete')."/".$row->station_id; ?>" class="btn btn-danger btn-sm" title="<?php echo lang('admin_delete'); ?>" onclick="return confirm('<?php echo lang('station_location_confirm_del_stationlocation'); ?> <?php echo $row->station_profile_name; ?> <?php echo lang('station_location_confirm_del_stationlocation_qso'); ?>');"><i class="fas fa-trash-alt"></i></a>
|
||||
<?php } ?>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
|||
|
|
@ -61,5 +61,3 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -46,45 +46,56 @@
|
|||
<!-- Account Information -->
|
||||
<div class="col-md">
|
||||
<div class="card">
|
||||
<div class="card-header"><?php echo lang('account_account_information'); ?></div>
|
||||
<div class="card-header">
|
||||
<?php echo lang('account_account_information'); ?>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label><?php echo lang('account_username'); ?></label>
|
||||
<label class="form-label"><?php echo lang('account_username'); ?></label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="fa fa-user"></i></span>
|
||||
<input class="form-control" type="text" name="user_name" value="<?php if (isset($user_name)) {
|
||||
echo $user_name;
|
||||
} ?>" />
|
||||
</div>
|
||||
<?php if (isset($username_error)) {
|
||||
echo "<small class=\"error\">" . $username_error . "</small>";
|
||||
echo "<small class=\"text-danger\"><i class=\"fa fa-exclamation-circle\"></i> " . $username_error . "</small>";
|
||||
} ?>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label><?php echo lang('account_email_address'); ?></label>
|
||||
<input class="form-control" type="text" name="user_email" value="<?php if (isset($user_email)) {
|
||||
<label class="form-label"><?php echo lang('account_email_address'); ?></label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="fa fa-envelope"></i></span>
|
||||
<input class="form-control" type="email" name="user_email" value="<?php if (isset($user_email)) {
|
||||
echo $user_email;
|
||||
} ?>" />
|
||||
</div>
|
||||
<?php if (isset($email_error)) {
|
||||
echo "<small class=\"error\">" . $email_error . "</small>";
|
||||
echo "<small class=\"text-danger\"><i class=\"fa fa-exclamation-circle\"></i> " . $email_error . "</small>";
|
||||
} ?>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label><?php echo lang('account_password'); ?></label>
|
||||
<label class="form-label"><?php echo lang('account_password'); ?></label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="fa fa-lock"></i></span>
|
||||
<input class="form-control" type="password" name="user_password" />
|
||||
<span class="input-group-btn"><button class="btn btn-default btn-pwd-showhide" type="button"><i class="fa fa-eye-slash"></i></button></span>
|
||||
<button class="btn btn-outline-secondary btn-pwd-showhide" type="button"><i class="fa fa-eye-slash"></i></button>
|
||||
</div>
|
||||
<?php if (isset($password_error)) {
|
||||
echo "<small class=\"error\">" . $password_error . "</small>";
|
||||
echo "<small class=\"text-danger\"><i class=\"fa fa-exclamation-circle\"></i> " . $password_error . "</small>";
|
||||
} else { ?>
|
||||
<small class="form-text text-muted"><?php echo lang('account_leave_blank_to_keep_existing_password'); ?></small>
|
||||
<small class="form-text text-muted"><i class="fa fa-info-circle"></i> <?php echo lang('account_leave_blank_to_keep_existing_password'); ?></small>
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<hr class="my-4" />
|
||||
<div class="mb-3">
|
||||
<label><?php echo lang('account_user_role'); ?></label>
|
||||
<label class="form-label"><?php echo lang('account_user_role'); ?></label>
|
||||
<?php if ($this->session->userdata('user_type') == 99) { ?>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="fa fa-users"></i></span>
|
||||
<select class="form-select" name="user_type">
|
||||
<?php
|
||||
$levels = $this->config->item('auth_level');
|
||||
|
|
@ -93,9 +104,13 @@
|
|||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
<?php } else {
|
||||
$l = $this->config->item('auth_level');
|
||||
echo $l[$user_type];
|
||||
echo '<div class="input-group">
|
||||
<span class="input-group-text"><i class="fa fa-user-tag"></i></span>
|
||||
<input type="text" class="form-control" value="' . $l[$user_type] . '" disabled>
|
||||
</div>';
|
||||
} ?>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -281,27 +296,37 @@
|
|||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<div class="form-check form-switch">
|
||||
<input name="user_dashboard_enable_dxpedition_card" class="form-check-input" type="checkbox" role="switch" id="DashboardUpcomingDXpeditionCheck" <?php if ($dashboard_upcoming_dx_card) { echo 'checked'; } ?>>
|
||||
<input name="user_dashboard_enable_dxpedition_card" class="form-check-input" type="checkbox" role="switch" id="DashboardUpcomingDXpeditionCheck" <?php if ($dashboard_upcoming_dx_card) {
|
||||
echo 'checked';
|
||||
} ?>>
|
||||
<label class="form-check-label" for="DashboardUpcomingDXpeditionCheck">Enable Upcoming DXPedition Card</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check form-switch">
|
||||
<input name="user_dashboard_enable_qslcards_card" class="form-check-input" type="checkbox" role="switch" id="DashboardQSLCardCheck" <?php if ($dashboard_qslcard_card) { echo 'checked'; } ?>>
|
||||
<input name="user_dashboard_enable_qslcards_card" class="form-check-input" type="checkbox" role="switch" id="DashboardQSLCardCheck" <?php if ($dashboard_qslcard_card) {
|
||||
echo 'checked';
|
||||
} ?>>
|
||||
<label class="form-check-label" for="DashboardQSLCardCheck">Enable QSL Cards Card</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check form-switch">
|
||||
<input name="user_dashboard_enable_eqslcards_card" class="form-check-input" type="checkbox" role="switch" id="DashboardeQSLCardCheck" <?php if ($dashboard_eqslcard_card) { echo 'checked'; } ?>>
|
||||
<input name="user_dashboard_enable_eqslcards_card" class="form-check-input" type="checkbox" role="switch" id="DashboardeQSLCardCheck" <?php if ($dashboard_eqslcard_card) {
|
||||
echo 'checked';
|
||||
} ?>>
|
||||
<label class="form-check-label" for="DashboardeQSLCardCheck">Enable eQSL Cards Card</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check form-switch">
|
||||
<input name="user_dashboard_enable_lotw_card" class="form-check-input" type="checkbox" role="switch" id="DashboardlotwCardCheck" <?php if ($dashboard_lotw_card) { echo 'checked'; } ?>>
|
||||
<input name="user_dashboard_enable_lotw_card" class="form-check-input" type="checkbox" role="switch" id="DashboardlotwCardCheck" <?php if ($dashboard_lotw_card) {
|
||||
echo 'checked';
|
||||
} ?>>
|
||||
<label class="form-check-label" for="DashboardlotwCardCheck">Enable Logbook of the World Card</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check form-switch">
|
||||
<input name="user_dashboard_enable_vuccgrids_card" class="form-check-input" type="checkbox" role="switch" id="DashboardvuccgridsCardCheck" <?php if ($dashboard_vuccgrids_card) { echo 'checked'; } ?>>
|
||||
<input name="user_dashboard_enable_vuccgrids_card" class="form-check-input" type="checkbox" role="switch" id="DashboardvuccgridsCardCheck" <?php if ($dashboard_vuccgrids_card) {
|
||||
echo 'checked';
|
||||
} ?>>
|
||||
<label class="form-check-label" for="DashboardvuccgridsCardCheck">Enable VUCC-Grids Card</label>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1166,21 +1191,29 @@
|
|||
<div class="card-header"><?php echo lang('account_winkeyer'); ?> <span class="badge text-bg-danger float-end"><?php echo lang('admin_experimental'); ?></span></div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label><?php echo lang('account_winkeyer_enabled'); ?></label>
|
||||
<div class="form-check form-switch">
|
||||
<?php if (!isset($user_winkey)) {
|
||||
$user_winkey = '0';
|
||||
} ?>
|
||||
<select class="form-select" name="user_winkey" id="user_winkeyer">
|
||||
<option value="0" <?php if ($user_winkey == 0) {
|
||||
echo 'selected="selected"';
|
||||
} ?>><?php echo lang('general_word_no'); ?></option>
|
||||
<option value="1" <?php if ($user_winkey == 1) {
|
||||
echo 'selected="selected"';
|
||||
} ?>><?php echo lang('general_word_yes'); ?></option>
|
||||
</select>
|
||||
<small class="form-text text-muted"><?php echo lang('account_winkeyer_hint'); ?></small>
|
||||
<input name="user_winkey" class="form-check-input" type="checkbox" role="switch" id="user_winkeyer" value="1" <?php if ($user_winkey == 1) {
|
||||
echo 'checked';
|
||||
} ?>>
|
||||
<label class="form-check-label" for="user_winkeyer"><?php echo lang('account_winkeyer_enabled'); ?></label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<div class="mb-3">
|
||||
<div class="form-check form-switch">
|
||||
<input name="user_winkey_websocket" class="form-check-input" type="checkbox" role="switch" id="user_winkey_websocket" value="1" <?php if ($user_winkey_websocket == 1) {
|
||||
echo 'checked';
|
||||
} ?>>
|
||||
<label class="form-check-label" for="user_winkey_websocket">Winkey Web Sockets</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<small class="form-text text-muted d-block mt-3"><?php echo lang('account_winkeyer_hint'); ?></small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -12,37 +12,50 @@
|
|||
<table class="profile">
|
||||
<tr>
|
||||
<td width="100px">Username</td>
|
||||
<td><?php if(isset($user_name)) { echo $user_name; } ?></td>
|
||||
<td><?php if (isset($user_name)) {
|
||||
echo $user_name;
|
||||
} ?></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Level</td>
|
||||
<td><?php $l = $this->config->item('auth_level'); echo $l[$user_type]; ?></td>
|
||||
<td><?php $l = $this->config->item('auth_level');
|
||||
echo $l[$user_type]; ?></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>E-mail</td>
|
||||
<td><?php if(isset($user_email)) { echo $user_email; } ?></td>
|
||||
<td><?php if (isset($user_email)) {
|
||||
echo $user_email;
|
||||
} ?></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Callsign</td>
|
||||
<td><?php if(isset($user_callsign)) { echo $user_callsign; } ?></td>
|
||||
<td><?php if (isset($user_callsign)) {
|
||||
echo $user_callsign;
|
||||
} ?></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Gridsquare</td>
|
||||
<td><?php if(isset($user_locator)) { echo $user_locator; } ?></td>
|
||||
<td><?php if (isset($user_locator)) {
|
||||
echo $user_locator;
|
||||
} ?></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>First name</td>
|
||||
<td><?php if(isset($user_firstname)) { echo $user_firstname; } ?></td>
|
||||
<td><?php if (isset($user_firstname)) {
|
||||
echo $user_firstname;
|
||||
} ?></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Last name</td>
|
||||
<td><?php if(isset($user_lastname)) { echo $user_lastname; } ?></td>
|
||||
<td><?php if (isset($user_lastname)) {
|
||||
echo $user_lastname;
|
||||
} ?></td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
|
|
|||
|
|
@ -174,14 +174,13 @@ function handleInput() {
|
|||
/^[A-Z0-9]{1,3}\/[A-Z]{2}-\d{3}|[AENOS]*[FNSUACA]-\d{3}|(?!.*FF)[A-Z0-9]{1,3}-\d{4,5}|[A-Z0-9]{1,3}[F]{2}-\d{4}$/i
|
||||
)
|
||||
) {
|
||||
sotaWwff = item.toUpperCase();
|
||||
} else if (
|
||||
sotaWwff = item.toUpperCase(); } else if (
|
||||
item.match(
|
||||
/([a-zA-Z0-9]{1,3}[0-9][a-zA-Z0-9]{0,3}[a-zA-Z])|.*\/([a-zA-Z0-9]{1,3}[0-9][a-zA-Z0-9]{0,3}[a-zA-Z])|([a-zA-Z0-9]{1,3}[0-9][a-zA-Z0-9]{0,3}[a-zA-Z])\/.*/
|
||||
)
|
||||
) {
|
||||
callsign = item.toUpperCase();
|
||||
} else if (itemNumber > 0 && item.match(/^\d{1,3}$/)) {
|
||||
} else if (itemNumber > 0 && (item.match(/^\d{1,3}$/) || item.match(/^[+-]\d{1,2}$/))) {
|
||||
if (rst_s === null) {
|
||||
rst_s = item;
|
||||
} else {
|
||||
|
|
@ -566,6 +565,15 @@ function getReportByMode(rst, mode) {
|
|||
|
||||
return "599";
|
||||
}
|
||||
// Handle digital modes with dB signal reports (e.g., -09, +00)
|
||||
if ((mode.toUpperCase() === "FT8" || mode.toUpperCase() === "FT4" || mode.toUpperCase() === "JS8" ||
|
||||
mode.toUpperCase() === "JT65" || mode.toUpperCase() === "JT65B" || mode.toUpperCase() === "JT6C" ||
|
||||
mode.toUpperCase() === "JTMS" || mode.toUpperCase() === "ISCAT" || mode.toUpperCase() === "MSK144" ||
|
||||
mode.toUpperCase() === "JTMSK" || mode.toUpperCase() === "QRA64" || mode.toUpperCase() === "JT9" ||
|
||||
mode.toUpperCase() === "JT9-1" || mode.toUpperCase() === "ROS" || mode.toUpperCase() === "Q65" ||
|
||||
mode.toUpperCase() === "FST4" || mode.toUpperCase() === "FST4W") && rst.match(/^[+-]\d{1,2}$/)) {
|
||||
return rst;
|
||||
}
|
||||
|
||||
if (settingsMode === "SSB") {
|
||||
if (rst.length === 1) {
|
||||
|
|
|
|||
|
|
@ -88,6 +88,45 @@ async function clickConnect() {
|
|||
|
||||
//Define outputstream, inputstream and port so they can be used throughout the sketch
|
||||
var outputStream, inputStream, port;
|
||||
|
||||
// Auto-reconnect functionality
|
||||
async function autoReconnect() {
|
||||
try {
|
||||
// Get previously connected ports
|
||||
const ports = await navigator.serial.getPorts();
|
||||
if (ports.length > 0) {
|
||||
// Try to reconnect to the first available port
|
||||
port = ports[0];
|
||||
await port.open({ baudRate: 1200 });
|
||||
await port.setSignals({ dataTerminalReady: true });
|
||||
|
||||
statusBar.innerText = "Auto-reconnected";
|
||||
connectButton.innerText = "Disconnect";
|
||||
|
||||
let decoder = new TextDecoderStream();
|
||||
inputDone = port.readable.pipeTo(decoder.writable);
|
||||
inputStream = decoder.readable;
|
||||
|
||||
const encoder = new TextEncoderStream();
|
||||
outputDone = encoder.readable.pipeTo(port.writable);
|
||||
outputStream = encoder.writable;
|
||||
|
||||
writeToByte("0x00, 0x02");
|
||||
writeToByte("0x02, 0x00");
|
||||
|
||||
$('#winkey_buttons').show();
|
||||
|
||||
reader = inputStream.getReader();
|
||||
readLoop();
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Auto-reconnect failed:", e);
|
||||
// If auto-reconnect fails, just continue with normal flow
|
||||
}
|
||||
}
|
||||
|
||||
// Call auto-reconnect when page loads
|
||||
window.addEventListener('load', autoReconnect);
|
||||
navigator.serial.addEventListener('connect', e => {
|
||||
statusBar.innerText = `Connected to ${e.port}`;
|
||||
connectButton.innerText = "Disconnect"
|
||||
|
|
@ -182,9 +221,11 @@ async function disconnect() {
|
|||
statusBar.innerText = "Disconnected";
|
||||
connectButton.innerText = "Connect"
|
||||
//Close the port.
|
||||
if (port) {
|
||||
await port.close();
|
||||
port = null;
|
||||
}
|
||||
}
|
||||
|
||||
//When the send button is pressed
|
||||
function clickSend() {
|
||||
|
|
|
|||
|
|
@ -511,6 +511,18 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"SO-125":{
|
||||
"Modes":{
|
||||
"V/U":[
|
||||
{
|
||||
"Uplink_Mode":"FM",
|
||||
"Uplink_Freq":"145875000",
|
||||
"Downlink_Mode":"FM",
|
||||
"Downlink_Freq":"436666000"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"SONATE-2":{
|
||||
"Modes":{
|
||||
"V":[
|
||||
|
|
|
|||
正在加载…
在新工单中引用