load->model('user_model'); // Check if users logged in if ($this->user_model->validate_session() == 0) { // user is not logged in redirect('user/login'); } session_write_close(); // load the view $data['page_title'] = __("Hardware Interfaces"); $footerData = []; $footerData['scripts'] = [ 'assets/js/sections/radio.js?' . filemtime(realpath(__DIR__ . "/../../assets/js/sections/radio.js")), ]; $this->load->view('interface_assets/header', $data); $this->load->view('radio/index'); $this->load->view('interface_assets/footer', $footerData); } function status() { $this->load->model('user_model'); if(!$this->user_model->authorize(3)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } session_write_close(); $this->load->model('cat'); $query = $this->cat->status(); if ($query->num_rows() > 0) { echo ""; echo "" . __("Radio") . ""; if ($this->session->userdata('clubstation') == 1 && clubaccess_check(9)) { echo "" . __("Operator") . ""; } echo "" . __("Frequency") . ""; echo "" . __("Mode") . ""; echo "" . __("Timestamp") . ""; echo " "; echo "" . __("Options") . ""; echo "" . __("Settings") . ""; echo ""; echo ""; foreach ($query->result() as $row) { echo ""; echo "" . $row->radio . ""; $this->load->model('user_model'); if ($this->session->userdata('clubstation') == 1 && clubaccess_check(9)) { $operator = $this->user_model->get_by_id($row->operator)->row(); if ($operator) { echo "" . $operator->user_callsign . ""; } else { echo "" . __("UNKNOWN") . ""; } } if (empty($row->frequency) || $row->frequency == "0") { echo "- / -"; } elseif (empty($row->frequency_rx) || $row->frequency_rx == "0") { echo "" . $this->frequency->qrg_conversion($row->frequency) . ""; } else { echo "" . $this->frequency->qrg_conversion($row->frequency_rx) . " / " . $this->frequency->qrg_conversion($row->frequency) . ""; } if (empty($row->mode) || $row->mode == "non") { echo "N/A"; } elseif (empty($row->mode_rx) || $row->mode_rx == "non") { echo "" . $row->mode . ""; } else { echo "" . $row->mode_rx . " / " . $row->mode . ""; } // Get Date format if ($this->session->userdata('user_date_format')) { // If Logged in and session exists $custom_date_format = $this->session->userdata('user_date_format'); } else { // Get Default date format from /config/wavelog.php $custom_date_format = $this->config->item('qso_date_format'); } $phpdate = strtotime($row->timestamp); echo "" . date($custom_date_format . ' H:i:s', $phpdate) . ""; $last_updated = $this->cat->last_updated()->row()->id; if ($last_updated == $row->id) { echo '' . __("last updated") . ''; } else { echo ''; } if ($this->session->userdata('clubstation') != 1) { $defaul_user_radio = $this->user_options_model->get_options('cat', array('option_name' => 'default_radio'))->row()->option_value ?? NULL; if (!$defaul_user_radio) { echo '"; echo "id . "\" class=\"btn btn-sm btn-danger\"> " . __("Delete") . ""; echo ""; } echo ""; } else { echo ""; echo "
" . __("No CAT interfaced radios found.") . "
"; echo ""; } } public function saveCatUrl() { $url = $this->input->post('caturl', true); $id = $this->input->post('id', true); $this->load->model('cat'); $this->cat->updateCatUrl($id,$url); } public function editCatUrl() { $this->load->model('cat'); $data['container'] = $this->cat->radio_status($this->input->post('id', true))->row(); $data['page_title'] = __("Edit CAT Settings"); $this->load->view('radio/edit', $data); } function json($id) { $clean_id = $this->security->xss_clean($id); $this->load->model('user_model'); // Check if users logged in if ($this->user_model->validate_session() == 0) { // user is not logged in // Return Json data header('Content-Type: application/json'); echo json_encode(array( "error" => "not_logged_in" ), JSON_PRETTY_PRINT); } else { session_write_close(); header('Content-Type: application/json'); $this->load->model('cat'); $query = $this->cat->radio_status($clean_id); if ($query->num_rows() > 0) { foreach ($query->result() as $row) { $frequency = $row->frequency; $frequency_rx = $row->frequency_rx; $power = $row->power; $prop_mode = $row->prop_mode; $cat_url = $row->cat_url;; // Check Mode if (isset($row->mode) && ($row->mode != null)) { $mode = strtoupper($row->mode); if ($mode == "FMN") { $mode = "FM"; } } else { $mode = null; } if ($row->prop_mode == "SAT") { // Get Satellite Name if ($row->sat_name == "AO-07") { $sat_name = "AO-7"; } elseif ($row->sat_name == "LILACSAT") { $sat_name = "CAS-3H"; } else { $sat_name = strtoupper($row->sat_name); } // Get Satellite Mode $sat_mode_uplink = $this->get_mode_designator($row->frequency); $sat_mode_downlink = $this->get_mode_designator($row->frequency_rx); if (empty($sat_mode_uplink)) { $sat_mode = ""; } elseif ($sat_mode_uplink !== $sat_mode_downlink) { $sat_mode = $sat_mode_uplink . "/" . $sat_mode_downlink; } else { $sat_mode = $sat_mode_uplink; } } else { $sat_name = ""; $sat_mode = ""; } // Calculate how old the data is in minutes $datetime1 = new DateTime("now", new DateTimeZone('UTC')); // Today's Date/Time $datetime2 = new DateTime($row->timestamp, new DateTimeZone('UTC')); $interval = $datetime1->diff($datetime2); $minutes = $interval->days * 24 * 60; $minutes += $interval->h * 60; $minutes += $interval->i; $updated_at = $minutes; // Return Json data $a_ret['frequency'] = $frequency; $a_ret['frequency_formatted'] = $this->frequency->qrg_conversion($frequency); if (isset($frequency_rx) && ($frequency_rx != null)) { $a_ret['frequency_rx'] = $frequency_rx; $a_ret['frequency_rx_formatted'] = $this->frequency->qrg_conversion($frequency_rx); } if (isset($mode) && ($mode != null)) { $a_ret['mode'] = $mode; } if (isset($sat_mode) && ($sat_mode != null)) { $a_ret['satmode'] = $sat_mode; } if (isset($sat_name) && ($sat_name != null)) { $a_ret['satname'] = $sat_name; } if (isset($power) && ($power != null)) { $a_ret['power'] = $power; } if (isset($prop_mode) && ($prop_mode != null)) { $a_ret['prop_mode'] = $prop_mode; } if (isset($cat_url) && ($cat_url != null)) { $a_ret['cat_url'] = $cat_url; } $a_ret['updated_minutes_ago'] = $updated_at; echo json_encode($a_ret, JSON_PRETTY_PRINT); } } } } function get_mode_designator($frequency) { if ($frequency > 21000000 && $frequency < 22000000) return "H"; if ($frequency > 28000000 && $frequency < 30000000) return "A"; if ($frequency > 144000000 && $frequency < 147000000) return "V"; if ($frequency > 432000000 && $frequency < 438000000) return "U"; if ($frequency > 1240000000 && $frequency < 1300000000) return "L"; if ($frequency > 2320000000 && $frequency < 2450000000) return "S"; if ($frequency > 3400000000 && $frequency < 3475000000) return "S2"; if ($frequency > 5650000000 && $frequency < 5850000000) return "C"; if ($frequency > 10000000000 && $frequency < 10500000000) return "X"; if ($frequency > 24000000000 && $frequency < 24250000000) return "K"; if ($frequency > 47000000000 && $frequency < 47200000000) return "R"; return ""; } function delete($id) { $clean_id = $this->security->xss_clean($id); // Check Auth $this->load->model('user_model'); if (!$this->user_model->authorize(3)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } $this->load->model('cat'); $this->cat->delete($clean_id); if ($clean_id == $this->user_options_model->get_options('cat', array('option_name' => 'default_radio'))->row()->option_value ?? '') { $this->release_default_radio(); } $this->session->set_flashdata('message', 'Radio Profile Deleted'); session_write_close(); redirect('radio'); } function set_default_radio() { // get the radio_id from POST $clean_radio_id = $this->security->xss_clean($this->input->post('radio_id')); // Check Auth $this->load->model('user_model'); if (!$this->user_model->authorize(3)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } // we unset the current default radio $this->release_default_radio(); // Set the user_option and session data $this->user_options_model->set_option('cat', 'default_radio', array('radio_id' => $clean_radio_id)); $this->session->set_userdata('radio', $clean_radio_id); } function release_default_radio() { // Check Auth $this->load->model('user_model'); if (!$this->user_model->authorize(3)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } // Unset the user_option and session data $this->user_options_model->del_option('cat', 'default_radio'); $this->session->unset_userdata('radio'); } function set_radio_frequency() { // Get parameters from POST $radio_id = $this->security->xss_clean($this->input->post('radio_id')); $frequency = $this->security->xss_clean($this->input->post('frequency')); $mode = $this->security->xss_clean($this->input->post('mode')); // Check Auth $this->load->model('user_model'); if (!$this->user_model->authorize(3)) { header('Content-Type: application/json'); echo json_encode(array('error' => 'not_authorized'), JSON_PRETTY_PRINT); return; } // Validate frequency parameter (must be numeric and positive) if (empty($frequency) || !is_numeric($frequency) || $frequency <= 0) { header('Content-Type: application/json'); echo json_encode(array('error' => 'invalid_frequency'), JSON_PRETTY_PRINT); return; } // If radio_id is empty or null, get the default radio for the user if (empty($radio_id)) { $default_radio = $this->user_options_model->get_options('cat', array('option_name' => 'default_radio'))->row()->option_value ?? NULL; if ($default_radio) { $radio_id = $default_radio; } else { header('Content-Type: application/json'); echo json_encode(array('error' => 'no_radio_configured'), JSON_PRETTY_PRINT); return; } } // Check if radio_id is 'ws' (WebSocket) - use default localhost URL if ($radio_id === 'ws') { $cat_url = 'http://127.0.0.1:54321'; } else { // Load CAT model and get radio details from database $this->load->model('cat'); $radio = $this->cat->radio_status($radio_id); if ($radio->num_rows() == 0) { header('Content-Type: application/json'); echo json_encode(array('error' => 'radio_not_found'), JSON_PRETTY_PRINT); return; } $radio_data = $radio->row(); $cat_url = $radio_data->cat_url; if (empty($cat_url)) { header('Content-Type: application/json'); echo json_encode(array('error' => 'no_cat_url'), JSON_PRETTY_PRINT); return; } } // Validate and normalize mode parameter $valid_modes = array('lsb', 'usb', 'cw', 'fm', 'am', 'rtty', 'pkt', 'dig', 'pktlsb', 'pktusb', 'pktfm'); $cat_mode = !empty($mode) ? strtolower($mode) : 'usb'; if (!in_array($cat_mode, $valid_modes)) { $cat_mode = 'usb'; // Default to USB for invalid modes } // Format: {cat_url}/{frequency}/{mode} $url = $cat_url . '/' . $frequency . '/' . $cat_mode; // Initialize cURL for GET request $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 5); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2); // Separate connection timeout // Execute request (gateway requires two requests due to known issue of changing mode see https://github.com/wavelog/WaveLogGate/issues/82) // First request $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $curl_error = curl_error($ch); // Wait 100ms before second request usleep(100000); // 100ms = 100,000 microseconds // Second request (after first completes) - gateway workaround curl_setopt($ch, CURLOPT_URL, $url); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $curl_error = curl_error($ch); curl_close($ch); // Return response // Note: Gateway returns empty response with HTTP 200 on success header('Content-Type: application/json'); if ($response === false || ($http_code != 200 && $http_code != 0)) { echo json_encode(array( 'success' => false, 'error' => $curl_error ?: 'request_failed', 'http_code' => $http_code ), JSON_PRETTY_PRINT); } else { echo json_encode(array( 'success' => true, 'frequency' => $frequency, 'mode' => $cat_mode, 'radio_id' => $radio_id ), JSON_PRETTY_PRINT); } } }