some code linting

This commit is contained in:
DJ2LS 2023-10-03 15:15:17 +02:00
parent b49c223dd2
commit 37c176ff41
42 changed files with 5124 additions and 5363 deletions

View file

@ -7,7 +7,9 @@
"start": "vite", "start": "vite",
"dev": "vite", "dev": "vite",
"build": "vue-tsc && vite build && electron-builder", "build": "vue-tsc && vite build && electron-builder",
"preview": "vite preview" "preview": "vite preview",
"lint": "eslint --ext .js,.vue src",
"lint-fix": "eslint --ext .js,.vue --fix src"
}, },
"dependencies": { "dependencies": {
"@vueuse/electron": "^10.4.1", "@vueuse/electron": "^10.4.1",
@ -36,10 +38,19 @@
"winston": "^3.10.0" "winston": "^3.10.0"
}, },
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "^6.7.4",
"@vitejs/plugin-vue": "^4.1.0", "@vitejs/plugin-vue": "^4.1.0",
"electron": "^24.8.2", "electron": "^24.8.2",
"electron-builder": "^23.6.0", "electron-builder": "^23.6.0",
"typescript": "^5.0.2", "eslint": "^8.50.0",
"eslint-config-prettier": "^9.0.0",
"eslint-config-standard-with-typescript": "^39.1.0",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-n": "^16.1.0",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-vue": "^9.17.0",
"typescript": "^5.2.2",
"vite": "^4.3.2", "vite": "^4.3.2",
"vite-plugin-electron": "^0.11.2", "vite-plugin-electron": "^0.11.2",
"vite-plugin-electron-renderer": "^0.14.5", "vite-plugin-electron-renderer": "^0.14.5",

View file

@ -1,16 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import FreeDATAMain from "./components/main.vue";
import FreeDATAMain from './components/main.vue'
</script> </script>
<template> <template>
<FreeDATAMain /> <FreeDATAMain />
</template> </template>

View file

@ -1,39 +1,30 @@
<script setup lang="ts"> <script setup lang="ts">
import { saveSettingsToFile } from "../js/settingsHandler";
import { setActivePinia } from "pinia";
import {saveSettingsToFile} from '../js/settingsHandler'; import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
import { useStateStore } from '../store/stateStore.js'; import { useStateStore } from "../store/stateStore.js";
const state = useStateStore(pinia); const state = useStateStore(pinia);
import { useChatStore } from '../store/chatStore.js'; import { useChatStore } from "../store/chatStore.js";
const chat = useChatStore(pinia); const chat = useChatStore(pinia);
import chat_navbar from "./chat_navbar.vue";
import chat_conversations from "./chat_conversations.vue";
import chat_messages from "./chat_messages.vue";
import chat_new_message from "./chat_new_message.vue";
import chat_navbar from './chat_navbar.vue' import { updateAllChat, newMessage } from "../js/chatHandler";
import chat_conversations from './chat_conversations.vue'
import chat_messages from './chat_messages.vue'
import chat_new_message from './chat_new_message.vue'
import {updateAllChat, newMessage} from '../js/chatHandler'
updateAllChat()
updateAllChat();
</script> </script>
<template> <template>
<div class="container-fluid m-0 p-0"> <div class="container-fluid m-0 p-0">
<!------ chat navbar ----------------------------------------------------------------------> <!------ chat navbar ---------------------------------------------------------------------->
@ -44,7 +35,6 @@ updateAllChat()
<!------Chats area ----------------------------------------------------------------------> <!------Chats area ---------------------------------------------------------------------->
<div class="container-fluid m-0 p-0"> <div class="container-fluid m-0 p-0">
<chat_conversations /> <chat_conversations />
</div> </div>
<div class="overflow-auto vh-100"> <div class="overflow-auto vh-100">
<div <div
@ -77,17 +67,13 @@ updateAllChat()
<chat_messages /> <chat_messages />
</div> </div>
<!------ new message area ----------------------------------------------------------------------> <!------ new message area ---------------------------------------------------------------------->
<chat_new_message /> <chat_new_message />
</div> </div>
</div> </div>
</div> </div>
<!-- user modal --> <!-- user modal -->
<div <div
@ -115,10 +101,7 @@ updateAllChat()
class="col position-absolute image-overlay text-white justify-content-center align-items-center d-flex align-middle h-100 opacity-0" class="col position-absolute image-overlay text-white justify-content-center align-items-center d-flex align-middle h-100 opacity-0"
id="userImageSelector" id="userImageSelector"
> >
<i <i class="bi bi-upload" style="font-size: 2.2rem"></i>
class="bi bi-upload"
style="font-size: 2.2rem"
></i>
</div> </div>
</div> </div>
</div> </div>
@ -298,39 +281,32 @@ updateAllChat()
class="badge bg-secondary" class="badge bg-secondary"
id="dx_user_info_name" id="dx_user_info_name"
></span> ></span>
<span <span class="badge bg-secondary" id="dx_user_info_age"></span>
class="badge bg-secondary"
id="dx_user_info_age"
></span>
</h5> </h5>
<ul class="card-text list-unstyled"> <ul class="card-text list-unstyled">
<li> <li>
<strong class="col" <strong class="col"><i class="bi bi-house"></i> </strong
><i class="bi bi-house"></i> </strong ><span id="dx_user_info_location"></span> (<span
><span id="dx_user_info_location"></span> id="dx_user_info_gridsquare"
(<span id="dx_user_info_gridsquare"></span>) ></span
>)
</li> </li>
<li> <li>
<strong class="col" <strong class="col"><i class="bi bi-envelope"></i> </strong
><i class="bi bi-envelope"></i> </strong
><span id="dx_user_info_email"></span> ><span id="dx_user_info_email"></span>
</li> </li>
<li> <li>
<strong class="col" <strong class="col"><i class="bi bi-globe"></i> </strong
><i class="bi bi-globe"></i> </strong
><span id="dx_user_info_website"></span> ><span id="dx_user_info_website"></span>
</li> </li>
<li> <li>
<strong class="col" <strong class="col"
><i ><i class="bi bi-broadcast-pin"></i> </strong
class="bi bi-broadcast-pin"
></i> </strong
><span id="dx_user_info_antenna"></span> ><span id="dx_user_info_antenna"></span>
</li> </li>
<li> <li>
<strong class="col" <strong class="col"><i class="bi bi-projector"></i> </strong
><i class="bi bi-projector"></i> </strong
><span id="dx_user_info_radio"></span> ><span id="dx_user_info_radio"></span>
</li> </li>
<li> <li>
@ -378,10 +354,7 @@ updateAllChat()
<div class="modal-dialog modal-dialog-scrollable"> <div class="modal-dialog modal-dialog-scrollable">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h1 <h1 class="modal-title fs-5" id="sharedFolderModalLabel">
class="modal-title fs-5"
id="sharedFolderModalLabel"
>
My Shared folder My Shared folder
<button <button
type="button" type="button"
@ -404,8 +377,7 @@ updateAllChat()
<div class="container-fluid p-0"> <div class="container-fluid p-0">
<div class="center mb-1"> <div class="center mb-1">
<div class="badge text-bg-info"> <div class="badge text-bg-info">
<i class="bi bi-info"></i> Change folder in <i class="bi bi-info"></i> Change folder in settings!
settings!
</div> </div>
</div> </div>
<div class="table-responsive"> <div class="table-responsive">
@ -451,29 +423,22 @@ updateAllChat()
<div class="card mb-3"> <div class="card mb-3">
<div class="card-body"> <div class="card-body">
<p class="card-text"> <p class="card-text">
Welcome to the chat window. Heard stations are Welcome to the chat window. Heard stations are listed in the
listed in the list on the left. Clicking on a list on the left. Clicking on a station will show messages sent
station will show messages sent and/or received and/or received from the selected station. Additional help is
from the selected station. Additional help is
available on various extra features below. available on various extra features below.
</p> </p>
</div> </div>
</div> </div>
<div class="card mb-3"> <div class="card mb-3">
<div class="card-body"> <div class="card-body">
<button <button type="button" class="btn btn-sm btn-primary ms-2">
type="button" <i class="bi bi-person" style="font-size: 1.2rem"></i>
class="btn btn-sm btn-primary ms-2"
>
<i
class="bi bi-person"
style="font-size: 1.2rem"
></i>
</button> </button>
<p class="card-text"> <p class="card-text">
Set your station information and picture. This Set your station information and picture. This information can
information can be requested by a remote station be requested by a remote station and can be enabled/disabled via
and can be enabled/disabled via settings. settings.
</p> </p>
</div> </div>
</div> </div>
@ -483,10 +448,7 @@ updateAllChat()
type="button" type="button"
class="btn btn-sm btn-outline-secondary ms-2" class="btn btn-sm btn-outline-secondary ms-2"
> >
<i <i class="bi bi-person" style="font-size: 1.2rem"></i>
class="bi bi-person"
style="font-size: 1.2rem"
></i>
</button> </button>
<p class="card-text"> <p class="card-text">
Request the selected station's information. Request the selected station's information.
@ -499,25 +461,15 @@ updateAllChat()
type="button" type="button"
class="btn btn-sm btn-outline-secondary ms-2" class="btn btn-sm btn-outline-secondary ms-2"
> >
<i <i class="bi bi-files" style="font-size: 1.2rem"></i>
class="bi bi-files"
style="font-size: 1.2rem"
></i>
</button> </button>
<p class="card-text"> <p class="card-text">
Request the selected station's shared file(s) Request the selected station's shared file(s) list. Clicking
list. Clicking <button type="button" class="btn btn-sm btn-primary ms-2">
<button <i class="bi bi-files" style="font-size: 1.2rem"></i>
type="button"
class="btn btn-sm btn-primary ms-2"
>
<i
class="bi bi-files"
style="font-size: 1.2rem"
></i>
</button> </button>
will allow you to preview your shared files. will allow you to preview your shared files. Shared file can be
Shared file can be enabled/disabled in settings. enabled/disabled in settings.
</p> </p>
</div> </div>
</div> </div>
@ -530,10 +482,9 @@ updateAllChat()
<i class="bi bi-funnel-fill"></i> <i class="bi bi-funnel-fill"></i>
</button> </button>
<p class="card-text"> <p class="card-text">
The filter button allows you to show or hide The filter button allows you to show or hide certain types of
certain types of messages. A lot of data is logged messages. A lot of data is logged and this allows you to modify
and this allows you to modify what is shown. By what is shown. By default sent and received messages and ping
default sent and received messages and ping
acknowlegements are displayed. acknowlegements are displayed.
</p> </p>
</div> </div>
@ -553,10 +504,7 @@ updateAllChat()
<div class="modal-dialog modal-dialog-scrollable"> <div class="modal-dialog modal-dialog-scrollable">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h1 <h1 class="modal-title fs-5" id="sharedFolderModalDXLabel">
class="modal-title fs-5"
id="sharedFolderModalDXLabel"
>
Shared folder Shared folder
</h1> </h1>
<button <button
@ -601,7 +549,4 @@ updateAllChat()
</div> </div>
</div> </div>
</div> </div>
</template> </template>

View file

@ -1,77 +1,75 @@
<script setup lang="ts"> <script setup lang="ts">
import { saveSettingsToFile } from "../js/settingsHandler";
import { setActivePinia } from "pinia";
import {saveSettingsToFile} from '../js/settingsHandler'; import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import {deleteChatByCallsign} from '../js/chatHandler' import { deleteChatByCallsign } from "../js/chatHandler";
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
import { useStateStore } from '../store/stateStore.js'; import { useStateStore } from "../store/stateStore.js";
const state = useStateStore(pinia); const state = useStateStore(pinia);
import { useChatStore } from '../store/chatStore.js'; import { useChatStore } from "../store/chatStore.js";
const chat = useChatStore(pinia); const chat = useChatStore(pinia);
function deleteChat(callsign) { function deleteChat(callsign) {
deleteChatByCallsign(callsign) deleteChatByCallsign(callsign);
} }
import chat_conversations_entry from "./chat_conversations_entry.vue";
import chat_conversations_entry from './chat_conversations_entry.vue'
function chatSelected(callsign) { function chatSelected(callsign) {
chat.selectedCallsign = callsign.toUpperCase();
chat.selectedCallsign = callsign.toUpperCase()
// scroll message container to bottom // scroll message container to bottom
var messageBody = document.getElementById("message-container"); var messageBody = document.getElementById("message-container");
messageBody.scrollTop = messageBody.scrollHeight - messageBody.clientHeight; messageBody.scrollTop = messageBody.scrollHeight - messageBody.clientHeight;
try { try {
chat.beaconLabelArray = Object.values(chat.sorted_beacon_list[chat.selectedCallsign].timestamp) chat.beaconLabelArray = Object.values(
chat.beaconDataArray = Object.values(chat.sorted_beacon_list[chat.selectedCallsign].snr) chat.sorted_beacon_list[chat.selectedCallsign].timestamp,
);
chat.beaconDataArray = Object.values(
chat.sorted_beacon_list[chat.selectedCallsign].snr,
);
} catch (e) { } catch (e) {
console.log("beacon data not fetched: " + e) console.log("beacon data not fetched: " + e);
chat.beaconLabelArray = [] chat.beaconLabelArray = [];
chat.beaconDataArray = [] chat.beaconDataArray = [];
} }
console.log(chat.beaconDataArray) console.log(chat.beaconDataArray);
} }
</script> </script>
<template> <template>
<div class="list-group m-0 p-0" id="chat-list-tab" role="chat-tablist"> <div class="list-group m-0 p-0" id="chat-list-tab" role="chat-tablist">
<template v-for="(item, key) in chat.callsign_list" :key="item.dxcallsign"> <template v-for="(item, key) in chat.callsign_list" :key="item.dxcallsign">
<a class="list-group-item list-group-item-action border-0 border-bottom rounded-0" :class="{ active: key==0 }" :id="`list-chat-list-${item}`" data-bs-toggle="list" :href="`#list-${item}-messages`" role="tab" aria-controls="list-{{item}}-messages" @click="chatSelected(item)"> <a
class="list-group-item list-group-item-action border-0 border-bottom rounded-0"
:class="{ active: key == 0 }"
:id="`list-chat-list-${item}`"
data-bs-toggle="list"
:href="`#list-${item}-messages`"
role="tab"
aria-controls="list-{{item}}-messages"
@click="chatSelected(item)"
>
<div class="row"> <div class="row">
<div class="col-9">{{ item }}</div> <div class="col-9">{{ item }}</div>
<div class="col-3"> <div class="col-3">
<button
<button class="btn btn-sm btn-outline-danger ms-2" @click="deleteChat(item)"><i class="bi bi-trash"></i></button> class="btn btn-sm btn-outline-danger ms-2"
@click="deleteChat(item)"
>
<i class="bi bi-trash"></i>
</button>
</div> </div>
</div> </div>
</a> </a>
</template> </template>
<!--<chat_conversations_entry/>--> <!--<chat_conversations_entry/>-->
</div> </div>
</template> </template>

View file

@ -1,28 +1,26 @@
<script setup lang="ts"> <script setup lang="ts">
import { saveSettingsToFile } from "../js/settingsHandler";
import { setActivePinia } from "pinia";
import {saveSettingsToFile} from '../js/settingsHandler'; import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
import { useStateStore } from '../store/stateStore.js'; import { useStateStore } from "../store/stateStore.js";
const state = useStateStore(pinia); const state = useStateStore(pinia);
import { useChatStore } from '../store/chatStore.js'; import { useChatStore } from "../store/chatStore.js";
const chat = useChatStore(pinia); const chat = useChatStore(pinia);
import SentMessage from './chat_messages_sent.vue'; // Import the chat_messages_sent component import SentMessage from "./chat_messages_sent.vue"; // Import the chat_messages_sent component
import ReceivedMessage from './chat_messages_received.vue'; // Import the chat_messages_sent component import ReceivedMessage from "./chat_messages_received.vue"; // Import the chat_messages_sent component
import ReceivedBroadcastMessage from './chat_messages_broadcast_received.vue'; // Import the chat_messages_sent component for broadcasts import ReceivedBroadcastMessage from "./chat_messages_broadcast_received.vue"; // Import the chat_messages_sent component for broadcasts
import SentBroadcastMessage from './chat_messages_broadcast_sent.vue'; // Import the chat_messages_sent component for broadcasts import SentBroadcastMessage from "./chat_messages_broadcast_sent.vue"; // Import the chat_messages_sent component for broadcasts
//helper function for saving the last messages day for disaplying the day based divider //helper function for saving the last messages day for disaplying the day based divider
var prevChatMessageDay = '' var prevChatMessageDay = "";
function getDateTime(timestampRaw) { function getDateTime(timestampRaw) {
var datetime = new Date(timestampRaw * 1000).toLocaleString( var datetime = new Date(timestampRaw * 1000).toLocaleString(
@ -34,19 +32,28 @@ function getDateTime(timestampRaw){
day: "2-digit", day: "2-digit",
}, },
); );
return datetime return datetime;
} }
</script> </script>
<template> <template>
<div class="tab-content" id="nav-tabContent-chat-messages"> <div class="tab-content" id="nav-tabContent-chat-messages">
<template v-for="(callsign, key) in chat.callsign_list"> <template v-for="(callsign, key) in chat.callsign_list">
<div class="tab-pane fade show" :class="{ active: key==0 }" :id="`list-${callsign}-messages`" role="tabpanel" :aria-labelledby="`list-chat-list-${callsign}`"> <div
<template v-for="item in chat.sorted_chat_list[callsign]" :key="item._id"> class="tab-pane fade show"
:class="{ active: key == 0 }"
:id="`list-${callsign}-messages`"
role="tabpanel"
:aria-labelledby="`list-chat-list-${callsign}`"
>
<template
v-for="item in chat.sorted_chat_list[callsign]"
:key="item._id"
>
<div v-if="prevChatMessageDay !== getDateTime(item.timestamp)"> <div v-if="prevChatMessageDay !== getDateTime(item.timestamp)">
<div class="separator my-2">{{prevChatMessageDay = getDateTime(item.timestamp)}}</div> <div class="separator my-2">
{{ (prevChatMessageDay = getDateTime(item.timestamp)) }}
</div>
</div> </div>
<div v-if="item.type === 'beacon' && item.status === 'received'"> <div v-if="item.type === 'beacon' && item.status === 'received'">
@ -65,12 +72,10 @@ return datetime
{{ chat.beaconDataArray }} {{ chat.beaconDataArray }}
</div> </div>
<div v-if="item.type === 'transmit'"> <div v-if="item.type === 'transmit'">
<sent-message :message="item" /> <sent-message :message="item" />
</div> </div>
<div v-else-if="item.type === 'received'"> <div v-else-if="item.type === 'received'">
<received-message :message="item" /> <received-message :message="item" />
</div> </div>
<div v-if="item.type === 'broadcast_transmit'"> <div v-if="item.type === 'broadcast_transmit'">
@ -79,18 +84,13 @@ return datetime
<div v-else-if="item.type === 'broadcast_received'"> <div v-else-if="item.type === 'broadcast_received'">
<received-broadcast-message :message="item" /> <received-broadcast-message :message="item" />
</div> </div>
</template> </template>
</div> </div>
</template> </template>
</div> </div>
</template> </template>
<style> <style>
/* https://stackoverflow.com/a/26634224 */ /* https://stackoverflow.com/a/26634224 */
.separator { .separator {
display: flex; display: flex;
@ -100,16 +100,16 @@ return datetime
.separator::before, .separator::before,
.separator::after { .separator::after {
content: ''; content: "";
flex: 1; flex: 1;
border-bottom: 1px solid #000; border-bottom: 1px solid #000;
} }
.separator:not(:empty)::before { .separator:not(:empty)::before {
margin-right: .25em; margin-right: 0.25em;
} }
.separator:not(:empty)::after { .separator:not(:empty)::after {
margin-left: .25em; margin-left: 0.25em;
} }
</style> </style>

View file

@ -12,15 +12,15 @@ export default {
methods: { methods: {
onDelete() { onDelete() {
// Implement delete action // Implement delete action
this.$emit('delete'); this.$emit("delete");
}, },
onCopy() { onCopy() {
// Implement copy action // Implement copy action
this.$emit('copy'); this.$emit("copy");
}, },
onQuote() { onQuote() {
// Implement quote action // Implement quote action
this.$emit('quote'); this.$emit("quote");
}, },
}, },
}; };

View file

@ -2,9 +2,12 @@
<div class="row justify-content-start mb-2"> <div class="row justify-content-start mb-2">
<div :class="messageWidthClass"> <div :class="messageWidthClass">
<div class="card bg-light border-0 text-dark"> <div class="card bg-light border-0 text-dark">
<div class="card-header" v-if="getFileContent['filesize'] !== 0"> <div class="card-header" v-if="getFileContent['filesize'] !== 0">
<p class="card-text">{{ getFileContent["filename"] }} | {{ getFileContent["filesize"] }} Bytes | {{ getFileContent["filetype"] }}</p> <p class="card-text">
{{ getFileContent["filename"] }} |
{{ getFileContent["filesize"] }} Bytes |
{{ getFileContent["filetype"] }}
</p>
</div> </div>
<div class="card-body"> <div class="card-body">
@ -12,32 +15,29 @@
</div> </div>
<div class="card-footer p-0 bg-light border-top-0"> <div class="card-footer p-0 bg-light border-top-0">
<p class="text-muted p-0 m-0 me-1 text-end">{{ getDateTime }}</p> <!-- Display formatted timestamp in card-footer --> <p class="text-muted p-0 m-0 me-1 text-end">{{ getDateTime }}</p>
<!-- Display formatted timestamp in card-footer -->
</div> </div>
<span class="position-absolute top-0 start-100 translate-middle badge rounded-1 bg-secondary border border-white"> <span
class="position-absolute top-0 start-100 translate-middle badge rounded-1 bg-secondary border border-white"
>
{{ message.broadcast_sender }} {{ message.broadcast_sender }}
</span> </span>
</div> </div>
</div> </div>
<!-- Delete button outside of the card --> <!-- Delete button outside of the card -->
<div class="col-auto"> <div class="col-auto">
<button class="btn btn-outline-secondary border-0" @click="deleteMessage"><i class="bi bi-trash"></i></button> <button class="btn btn-outline-secondary border-0" @click="deleteMessage">
<i class="bi bi-trash"></i>
</button>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { deleteMessageFromDB } from "../js/chatHandler";
import {deleteMessageFromDB} from '../js/chatHandler'
export default { export default {
props: { props: {
@ -46,47 +46,48 @@ export default {
computed: { computed: {
getFileContent() { getFileContent() {
try { try {
var filename = Object.keys(this.message._attachments)[0] var filename = Object.keys(this.message._attachments)[0];
var filesize = this.message._attachments[filename]["length"] var filesize = this.message._attachments[filename]["length"];
var filetype = filename.split(".")[1] var filetype = filename.split(".")[1];
// ensure filesize is 0 for hiding message header if no data is available // ensure filesize is 0 for hiding message header if no data is available
if (typeof filename === 'undefined' || filename === '' || filename === '-' || filename === 'null'){ if (
filesize = 0 typeof filename === "undefined" ||
filename === "" ||
filename === "-" ||
filename === "null"
) {
filesize = 0;
} }
return { filename: filename, filesize: filesize, filetype: filetype };
return {filename: filename, filesize: filesize, filetype: filetype}
} catch (e) { } catch (e) {
console.log("file not loaded from database - empty?") console.log("file not loaded from database - empty?");
// we are only checking against filesize for displaying attachments // we are only checking against filesize for displaying attachments
return {filesize: 0} return { filesize: 0 };
} }
}, },
messageWidthClass() { messageWidthClass() {
// Calculate a Bootstrap grid class based on message length // Calculate a Bootstrap grid class based on message length
// Adjust the logic as needed to fit your requirements // Adjust the logic as needed to fit your requirements
if (this.message.msg.length <= 50) { if (this.message.msg.length <= 50) {
return 'col-4'; return "col-4";
} else if (this.message.msg.length <= 100) { } else if (this.message.msg.length <= 100) {
return 'col-6'; return "col-6";
} else { } else {
return 'col-9'; return "col-9";
} }
}, },
deleteMessage() { deleteMessage() {
deleteMessageFromDB(this.message._id) deleteMessageFromDB(this.message._id);
}, },
getDateTime() { getDateTime() {
var datetime = new Date(this.message.timestamp * 1000).toLocaleString( var datetime = new Date(this.message.timestamp * 1000).toLocaleString(
navigator.language, navigator.language,
{ {
hour: "2-digit",
hour: '2-digit', minute: "2-digit",
minute: '2-digit', },
}
); );
return datetime; return datetime;
}, },

View file

@ -2,17 +2,26 @@
<div class="row justify-content-end mb-2"> <div class="row justify-content-end mb-2">
<!-- control area --> <!-- control area -->
<div class="col-auto p-0 m-0"> <div class="col-auto p-0 m-0">
<button class="btn btn-outline-secondary border-0 me-1" @click="repeatMessage"><i class="bi bi-arrow-repeat"></i></button> <button
<button class="btn btn-outline-secondary border-0" @click="deleteMessage"><i class="bi bi-trash"></i></button> class="btn btn-outline-secondary border-0 me-1"
@click="repeatMessage"
>
<i class="bi bi-arrow-repeat"></i>
</button>
<button class="btn btn-outline-secondary border-0" @click="deleteMessage">
<i class="bi bi-trash"></i>
</button>
</div> </div>
<!-- message area --> <!-- message area -->
<div :class="messageWidthClass"> <div :class="messageWidthClass">
<div class="card bg-primary text-white"> <div class="card bg-primary text-white">
<div class="card-header" v-if="getFileContent['filesize'] !== 0"> <div class="card-header" v-if="getFileContent['filesize'] !== 0">
<p class="card-text">{{ getFileContent["filename"] }} | {{ getFileContent["filesize"] }} Bytes | {{ getFileContent["filetype"] }}</p> <p class="card-text">
{{ getFileContent["filename"] }} |
{{ getFileContent["filesize"] }} Bytes |
{{ getFileContent["filetype"] }}
</p>
</div> </div>
<div class="card-body"> <div class="card-body">
@ -20,7 +29,8 @@
</div> </div>
<div class="card-footer p-0 bg-primary border-top-0"> <div class="card-footer p-0 bg-primary border-top-0">
<p class="text p-0 m-0 me-1 text-end">{{ getDateTime }}</p> <!-- Display formatted timestamp in card-footer --> <p class="text p-0 m-0 me-1 text-end">{{ getDateTime }}</p>
<!-- Display formatted timestamp in card-footer -->
</div> </div>
<div class="card-footer p-0 border-top-0" v-if="message.percent < 100"> <div class="card-footer p-0 border-top-0" v-if="message.percent < 100">
@ -42,12 +52,11 @@
</div> </div>
</template> </template>
<script> <script>
import {
import {repeatMessageTransmission, deleteMessageFromDB} from '../js/chatHandler' repeatMessageTransmission,
deleteMessageFromDB,
} from "../js/chatHandler";
export default { export default {
props: { props: {
@ -55,50 +64,47 @@ export default {
}, },
computed: { computed: {
getFileContent() { getFileContent() {
var filename = Object.keys(this.message._attachments)[0];
var filename = Object.keys(this.message._attachments)[0] var filesize = this.message._attachments[filename]["length"];
var filesize = this.message._attachments[filename]["length"] var filetype = filename.split(".")[1];
var filetype = filename.split(".")[1]
// ensure filesize is 0 for hiding message header if no data is available // ensure filesize is 0 for hiding message header if no data is available
if (typeof filename === 'undefined' || filename === '' || filename === '-' || filename === 'null'){ if (
filesize = 0 typeof filename === "undefined" ||
filename === "" ||
filename === "-" ||
filename === "null"
) {
filesize = 0;
} }
return { filename: filename, filesize: filesize, filetype: filetype };
return {filename: filename, filesize: filesize, filetype: filetype}
}, },
messageWidthClass() { messageWidthClass() {
// Calculate a Bootstrap grid class based on message length // Calculate a Bootstrap grid class based on message length
// Adjust the logic as needed to fit your requirements // Adjust the logic as needed to fit your requirements
if (this.message.msg.length <= 50) { if (this.message.msg.length <= 50) {
return 'col-4'; return "col-4";
} else if (this.message.msg.length <= 100) { } else if (this.message.msg.length <= 100) {
return 'col-6'; return "col-6";
} else { } else {
return 'col-9'; return "col-9";
} }
}, },
repeatMessage() { repeatMessage() {
repeatMessageTransmission(this.message._id) repeatMessageTransmission(this.message._id);
}, },
deleteMessage() { deleteMessage() {
deleteMessageFromDB(this.message._id) deleteMessageFromDB(this.message._id);
}, },
getDateTime() { getDateTime() {
var datetime = new Date(this.message.timestamp * 1000).toLocaleString( var datetime = new Date(this.message.timestamp * 1000).toLocaleString(
navigator.language, navigator.language,
{ {
hour: "2-digit",
hour: '2-digit', minute: "2-digit",
minute: '2-digit', },
}
); );
return datetime; return datetime;
}, },

View file

@ -2,9 +2,12 @@
<div class="row justify-content-start mb-2"> <div class="row justify-content-start mb-2">
<div :class="messageWidthClass"> <div :class="messageWidthClass">
<div class="card bg-light border-0 text-dark"> <div class="card bg-light border-0 text-dark">
<div class="card-header" v-if="getFileContent['filesize'] !== 0"> <div class="card-header" v-if="getFileContent['filesize'] !== 0">
<p class="card-text">{{ getFileContent["filename"] }} | {{ getFileContent["filesize"] }} Bytes | {{ getFileContent["filetype"] }}</p> <p class="card-text">
{{ getFileContent["filename"] }} |
{{ getFileContent["filesize"] }} Bytes |
{{ getFileContent["filetype"] }}
</p>
</div> </div>
<div class="card-body"> <div class="card-body">
@ -12,25 +15,23 @@
</div> </div>
<div class="card-footer p-0 bg-light border-top-0"> <div class="card-footer p-0 bg-light border-top-0">
<p class="text-muted p-0 m-0 me-1 text-end">{{ getDateTime }}</p> <!-- Display formatted timestamp in card-footer --> <p class="text-muted p-0 m-0 me-1 text-end">{{ getDateTime }}</p>
<!-- Display formatted timestamp in card-footer -->
</div> </div>
</div> </div>
</div> </div>
<!-- Delete button outside of the card --> <!-- Delete button outside of the card -->
<div class="col-auto"> <div class="col-auto">
<button class="btn btn-outline-secondary border-0" @click="deleteMessage"><i class="bi bi-trash"></i></button> <button class="btn btn-outline-secondary border-0" @click="deleteMessage">
<i class="bi bi-trash"></i>
</button>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { deleteMessageFromDB } from "../js/chatHandler";
import {deleteMessageFromDB} from '../js/chatHandler'
export default { export default {
props: { props: {
@ -39,40 +40,38 @@ export default {
computed: { computed: {
getFileContent() { getFileContent() {
try { try {
var filename = Object.keys(this.message._attachments)[0] var filename = Object.keys(this.message._attachments)[0];
var filesize = this.message._attachments[filename]["length"] var filesize = this.message._attachments[filename]["length"];
var filetype = filename.split(".")[1] var filetype = filename.split(".")[1];
return {filename: filename, filesize: filesize, filetype: filetype} return { filename: filename, filesize: filesize, filetype: filetype };
} catch (e) { } catch (e) {
console.log("file not loaded from database - empty?") console.log("file not loaded from database - empty?");
// we are only checking against filesize for displaying attachments // we are only checking against filesize for displaying attachments
return {filesize: 0} return { filesize: 0 };
} }
}, },
messageWidthClass() { messageWidthClass() {
// Calculate a Bootstrap grid class based on message length // Calculate a Bootstrap grid class based on message length
// Adjust the logic as needed to fit your requirements // Adjust the logic as needed to fit your requirements
if (this.message.msg.length <= 50) { if (this.message.msg.length <= 50) {
return 'col-4'; return "col-4";
} else if (this.message.msg.length <= 100) { } else if (this.message.msg.length <= 100) {
return 'col-6'; return "col-6";
} else { } else {
return 'col-9'; return "col-9";
} }
}, },
deleteMessage() { deleteMessage() {
deleteMessageFromDB(this.message._id) deleteMessageFromDB(this.message._id);
}, },
getDateTime() { getDateTime() {
var datetime = new Date(this.message.timestamp * 1000).toLocaleString( var datetime = new Date(this.message.timestamp * 1000).toLocaleString(
navigator.language, navigator.language,
{ {
hour: "2-digit",
hour: '2-digit', minute: "2-digit",
minute: '2-digit', },
}
); );
return datetime; return datetime;
}, },

View file

@ -2,17 +2,26 @@
<div class="row justify-content-end mb-2"> <div class="row justify-content-end mb-2">
<!-- control area --> <!-- control area -->
<div class="col-auto p-0 m-0"> <div class="col-auto p-0 m-0">
<button class="btn btn-outline-secondary border-0 me-1" @click="repeatMessage"><i class="bi bi-arrow-repeat"></i></button> <button
<button class="btn btn-outline-secondary border-0" @click="deleteMessage"><i class="bi bi-trash"></i></button> class="btn btn-outline-secondary border-0 me-1"
@click="repeatMessage"
>
<i class="bi bi-arrow-repeat"></i>
</button>
<button class="btn btn-outline-secondary border-0" @click="deleteMessage">
<i class="bi bi-trash"></i>
</button>
</div> </div>
<!-- message area --> <!-- message area -->
<div :class="messageWidthClass"> <div :class="messageWidthClass">
<div class="card bg-primary text-white"> <div class="card bg-primary text-white">
<div class="card-header" v-if="getFileContent['filesize'] !== 0"> <div class="card-header" v-if="getFileContent['filesize'] !== 0">
<p class="card-text">{{ getFileContent["filename"] }} | {{ getFileContent["filesize"] }} Bytes | {{ getFileContent["filetype"] }}</p> <p class="card-text">
{{ getFileContent["filename"] }} |
{{ getFileContent["filesize"] }} Bytes |
{{ getFileContent["filetype"] }}
</p>
</div> </div>
<div class="card-body"> <div class="card-body">
@ -20,11 +29,15 @@
</div> </div>
<div class="card-footer p-0 bg-primary border-top-0"> <div class="card-footer p-0 bg-primary border-top-0">
<p class="text p-0 m-0 me-1 text-end">{{ getDateTime }}</p> <!-- Display formatted timestamp in card-footer --> <p class="text p-0 m-0 me-1 text-end">{{ getDateTime }}</p>
<!-- Display formatted timestamp in card-footer -->
</div> </div>
<div class="card-footer p-0 border-top-0" v-if="message.percent < 100"> <div class="card-footer p-0 border-top-0" v-if="message.percent < 100">
<div class="progress bg-secondary rounded-0 rounded-bottom" :style="{ height: '10px' }"> <div
class="progress bg-secondary rounded-0 rounded-bottom"
:style="{ height: '10px' }"
>
<div <div
class="progress-bar progress-bar-striped overflow-visible" class="progress-bar progress-bar-striped overflow-visible"
role="progressbar" role="progressbar"
@ -42,12 +55,11 @@
</div> </div>
</template> </template>
<script> <script>
import {
import {repeatMessageTransmission, deleteMessageFromDB} from '../js/chatHandler' repeatMessageTransmission,
deleteMessageFromDB,
} from "../js/chatHandler";
export default { export default {
props: { props: {
@ -55,50 +67,46 @@ export default {
}, },
computed: { computed: {
getFileContent() { getFileContent() {
var filename = Object.keys(this.message._attachments)[0];
var filename = Object.keys(this.message._attachments)[0] var filesize = this.message._attachments[filename]["length"];
var filesize = this.message._attachments[filename]["length"] var filetype = filename.split(".")[1];
var filetype = filename.split(".")[1]
// ensure filesize is 0 for hiding message header if no data is available // ensure filesize is 0 for hiding message header if no data is available
if (typeof filename === 'undefined' || filename === '' || filename === '-'){ if (
filesize = 0 typeof filename === "undefined" ||
filename === "" ||
filename === "-"
) {
filesize = 0;
} }
return { filename: filename, filesize: filesize, filetype: filetype };
return {filename: filename, filesize: filesize, filetype: filetype}
}, },
messageWidthClass() { messageWidthClass() {
// Calculate a Bootstrap grid class based on message length // Calculate a Bootstrap grid class based on message length
// Adjust the logic as needed to fit your requirements // Adjust the logic as needed to fit your requirements
if (this.message.msg.length <= 50) { if (this.message.msg.length <= 50) {
return 'col-4'; return "col-4";
} else if (this.message.msg.length <= 100) { } else if (this.message.msg.length <= 100) {
return 'col-6'; return "col-6";
} else { } else {
return 'col-9'; return "col-9";
} }
}, },
repeatMessage() { repeatMessage() {
repeatMessageTransmission(this.message._id) repeatMessageTransmission(this.message._id);
}, },
deleteMessage() { deleteMessage() {
deleteMessageFromDB(this.message._id) deleteMessageFromDB(this.message._id);
}, },
getDateTime() { getDateTime() {
var datetime = new Date(this.message.timestamp * 1000).toLocaleString( var datetime = new Date(this.message.timestamp * 1000).toLocaleString(
navigator.language, navigator.language,
{ {
hour: "2-digit",
hour: '2-digit', minute: "2-digit",
minute: '2-digit', },
}
); );
return datetime; return datetime;
}, },

View file

@ -1,19 +1,17 @@
<script setup lang="ts"> <script setup lang="ts">
import { saveSettingsToFile } from "../js/settingsHandler";
import { setActivePinia } from "pinia";
import {saveSettingsToFile} from '../js/settingsHandler'; import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
import { useStateStore } from '../store/stateStore.js'; import { useStateStore } from "../store/stateStore.js";
const state = useStateStore(pinia); const state = useStateStore(pinia);
import { useChatStore } from '../store/chatStore.js'; import { useChatStore } from "../store/chatStore.js";
const chat = useChatStore(pinia); const chat = useChatStore(pinia);
import { import {
@ -25,11 +23,10 @@ import {
Title, Title,
Tooltip, Tooltip,
Legend, Legend,
BarElement BarElement,
} from 'chart.js' } from "chart.js";
import { Line, Scatter, Bar } from 'vue-chartjs' import { Line, Scatter, Bar } from "vue-chartjs";
import { ref, computed } from 'vue'; import { ref, computed } from "vue";
ChartJS.register( ChartJS.register(
CategoryScale, CategoryScale,
@ -38,11 +35,11 @@ ChartJS.register(
Title, Title,
Tooltip, Tooltip,
Legend, Legend,
BarElement BarElement,
) );
var beaconHistogramOptions = { var beaconHistogramOptions = {
type: 'bar', type: "bar",
bezierCurve: false, //remove curves from your plot bezierCurve: false, //remove curves from your plot
scaleShowLabels: false, //remove labels scaleShowLabels: false, //remove labels
tooltipEvents: [], //remove trigger from tooltips so they will'nt be show tooltipEvents: [], //remove trigger from tooltips so they will'nt be show
@ -51,8 +48,8 @@ ChartJS.register(
maintainAspectRatio: true, maintainAspectRatio: true,
plugins: { plugins: {
legend: { legend: {
display: false display: false,
} },
}, },
scales: { scales: {
@ -63,7 +60,7 @@ ChartJS.register(
max: 15, max: 15,
ticks: { ticks: {
display: false, display: false,
} },
}, },
y: { y: {
display: false, display: false,
@ -71,7 +68,7 @@ ChartJS.register(
max: 10, max: 10,
ticks: { ticks: {
display: false, display: false,
} },
}, },
}, },
}; };
@ -82,58 +79,30 @@ ChartJS.register(
//console.log(dataArray1) //console.log(dataArray1)
//[-3, 10, 8, 5, 3, 0, -5] //[-3, 10, 8, 5, 3, 0, -5]
try { try {
chat.beaconLabelArray = Object.values(
chat.beaconLabelArray = Object.values(chat.sorted_beacon_list['DJ2LS-0'].timestamp) chat.sorted_beacon_list["DJ2LS-0"].timestamp,
chat.beaconDataArray = Object.values(chat.sorted_beacon_list['DJ2LS-0'].snr) );
chat.beaconDataArray = Object.values(chat.sorted_beacon_list["DJ2LS-0"].snr);
} catch (e) { } catch (e) {
console.log(e);
console.log(e) var beaconLabels = [];
var beaconData = [];
var beaconLabels = []
var beaconData = []
} }
const beaconHistogramData = computed(() => ({ const beaconHistogramData = computed(() => ({
labels: chat.beaconLabelArray, labels: chat.beaconLabelArray,
datasets: [ datasets: [
{ data: chat.beaconDataArray, tension: 0.1, borderColor: 'rgb(0, 255, 0)' } { data: chat.beaconDataArray, tension: 0.1, borderColor: "rgb(0, 255, 0)" },
] ],
} }));
));
function newChat(obj) { function newChat(obj) {
let callsign = document.getElementById("chatModuleNewDxCall").value;
let callsign = document.getElementById("chatModuleNewDxCall").value callsign = callsign.toUpperCase();
callsign = callsign.toUpperCase() chat.callsign_list.add(callsign);
chat.callsign_list.add(callsign)
} }
</script> </script>
<template> <template>
@ -157,23 +126,19 @@ function newChat(obj){
@click="newChat()" @click="newChat()"
> >
new chat new chat
<i <i class="bi bi-pencil-square" style="font-size: 1.2rem"></i>
class="bi bi-pencil-square"
style="font-size: 1.2rem"
></i>
</button> </button>
</div> </div>
</div> </div>
<div class="col-7 ms-2 p-0"> <div class="col-7 ms-2 p-0">
<!-- right side of chat nav bar--> <!-- right side of chat nav bar-->
{{ beaconData }} {{ beaconData }}
<Bar :data="beaconHistogramData" :options="beaconHistogramOptions" width="300" style="height:100%" /> <Bar
:data="beaconHistogramData"
:options="beaconHistogramOptions"
width="300"
style="height: 100%"
/>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,46 +1,34 @@
<script setup lang="ts"> <script setup lang="ts">
import { saveSettingsToFile } from "../js/settingsHandler";
import {saveSettingsToFile} from '../js/settingsHandler' import { setActivePinia } from "pinia";
import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useStateStore } from '../store/stateStore.js'; import { useStateStore } from "../store/stateStore.js";
const state = useStateStore(pinia); const state = useStateStore(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
import main_modals from './main_modals.vue' import main_modals from "./main_modals.vue";
import main_top_navbar from './main_top_navbar.vue' import main_top_navbar from "./main_top_navbar.vue";
import main_audio from './main_audio.vue' import main_audio from "./main_audio.vue";
import main_rig_control from './main_rig_control.vue' import main_rig_control from "./main_rig_control.vue";
import main_my_station from './main_my_station.vue' import main_my_station from "./main_my_station.vue";
import main_updater from './main_updater.vue' import main_updater from "./main_updater.vue";
import settings_view from './settings.vue' import settings_view from "./settings.vue";
import main_active_rig_control from './main_active_rig_control.vue' import main_active_rig_control from "./main_active_rig_control.vue";
import main_footer_navbar from './main_footer_navbar.vue' import main_footer_navbar from "./main_footer_navbar.vue";
import main_active_stats from './main_active_stats.vue'
import main_active_broadcasts from './main_active_broadcasts.vue'
import main_active_heard_stations from './main_active_heard_stations.vue'
import main_active_audio_level from './main_active_audio_level.vue'
import chat from './chat.vue'
import {stopTransmission} from '../js/sock.js'
import main_active_stats from "./main_active_stats.vue";
import main_active_broadcasts from "./main_active_broadcasts.vue";
import main_active_heard_stations from "./main_active_heard_stations.vue";
import main_active_audio_level from "./main_active_audio_level.vue";
import chat from "./chat.vue";
import { stopTransmission } from "../js/sock.js";
function changeGuiDesign(design) { function changeGuiDesign(design) {
if ( if (
@ -105,16 +93,10 @@ function changeGuiDesign(design) {
document.getElementById("bootstrap_theme").href = escape(theme_path); document.getElementById("bootstrap_theme").href = escape(theme_path);
} }
function stopAllTransmissions() { function stopAllTransmissions() {
console.log("stopping transmissions") console.log("stopping transmissions");
stopTransmission() stopTransmission();
} }
</script> </script>
<template> <template>
@ -164,7 +146,6 @@ function stopAllTransmissions(){
><i class="bi bi-chat-text h3"></i ><i class="bi bi-chat-text h3"></i
></a> ></a>
<a <a
class="list-group-item list-group-item-action d-none" class="list-group-item list-group-item-action d-none"
id="list-mesh-list" id="list-mesh-list"
@ -185,7 +166,6 @@ function stopAllTransmissions(){
><i class="bi bi-info h3"></i ><i class="bi bi-info h3"></i
></a> ></a>
<a <a
class="list-group-item list-group-item-action d-none" class="list-group-item list-group-item-action d-none"
id="list-logger-list" id="list-logger-list"
@ -402,7 +382,6 @@ function stopAllTransmissions(){
</div> </div>
</div> </div>
<div <div
class="tab-pane fade" class="tab-pane fade"
id="nav-actions" id="nav-actions"
@ -538,9 +517,6 @@ function stopAllTransmissions(){
aria-labelledby="list-chat-list" aria-labelledby="list-chat-list"
> >
<chat /> <chat />
</div> </div>
<div <div
class="tab-pane fade" class="tab-pane fade"

View file

@ -1,32 +1,26 @@
<script setup lang="ts"> <script setup lang="ts">
import { saveSettingsToFile } from "../js/settingsHandler";
import {saveSettingsToFile} from '../js/settingsHandler' import { setActivePinia } from "pinia";
import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
import { useStateStore } from '../store/stateStore.js'; import { useStateStore } from "../store/stateStore.js";
const state = useStateStore(pinia); const state = useStateStore(pinia);
import {record_audio, sendTestFrame} from '../js/sock.js' import { record_audio, sendTestFrame } from "../js/sock.js";
function startStopRecordAudio() { function startStopRecordAudio() {
record_audio() record_audio();
} }
</script> </script>
<template> <template>
<div class="card mb-1"> <div class="card mb-1">
<div class="card-header p-1"> <div class="card-header p-1">
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-1"> <div class="col-1">
<i class="bi bi-volume-up" style="font-size: 1.2rem"></i> <i class="bi bi-volume-up" style="font-size: 1.2rem"></i>
@ -49,8 +43,10 @@ function startStopRecordAudio(){
id="startStopRecording" id="startStopRecording"
class="btn btn-sm" class="btn btn-sm"
@click="startStopRecordAudio()" @click="startStopRecordAudio()"
v-bind:class="{ 'btn-outline-secondary' : state.audio_recording === 'False', v-bind:class="{
'btn-secondary' : state.audio_recording === 'True'}" 'btn-outline-secondary': state.audio_recording === 'False',
'btn-secondary': state.audio_recording === 'True',
}"
> >
Record Record
</button> </button>
@ -63,10 +59,7 @@ function startStopRecordAudio(){
data-bs-target="#audioLevelHelpModal" data-bs-target="#audioLevelHelpModal"
class="btn m-0 p-0 border-0" class="btn m-0 p-0 border-0"
> >
<i <i class="bi bi-question-circle" style="font-size: 1rem"></i>
class="bi bi-question-circle"
style="font-size: 1rem"
></i>
</button> </button>
</div> </div>
</div> </div>
@ -76,7 +69,10 @@ function startStopRecordAudio(){
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-sm"> <div class="col-sm">
<div class="progress mb-0 rounded-0 rounded-top" style="height: 22px"> <div
class="progress mb-0 rounded-0 rounded-top"
style="height: 22px"
>
<div <div
class="progress-bar progress-bar-striped bg-primary force-gpu" class="progress-bar progress-bar-striped bg-primary force-gpu"
id="noise_level" id="noise_level"
@ -93,7 +89,10 @@ function startStopRecordAudio(){
S-Meter(dB): {{ state.s_meter_strength_raw }} S-Meter(dB): {{ state.s_meter_strength_raw }}
</p> </p>
</div> </div>
<div class="progress mb-0 rounded-0 rounded-bottom" style="height: 8px"> <div
class="progress mb-0 rounded-0 rounded-bottom"
style="height: 8px"
>
<div <div
class="progress-bar progress-bar-striped bg-warning" class="progress-bar progress-bar-striped bg-warning"
role="progressbar" role="progressbar"
@ -129,7 +128,10 @@ function startStopRecordAudio(){
</div> </div>
</div> </div>
<div class="col-sm"> <div class="col-sm">
<div class="progress mb-0 rounded-0 rounded-top" style="height: 22px"> <div
class="progress mb-0 rounded-0 rounded-top"
style="height: 22px"
>
<div <div
class="progress-bar progress-bar-striped bg-primary force-gpu" class="progress-bar progress-bar-striped bg-primary force-gpu"
id="dbfs_level" id="dbfs_level"
@ -146,7 +148,10 @@ function startStopRecordAudio(){
{{ state.dbfs_level }} dBFS {{ state.dbfs_level }} dBFS
</p> </p>
</div> </div>
<div class="progress mb-0 rounded-0 rounded-bottom" style="height: 8px"> <div
class="progress mb-0 rounded-0 rounded-bottom"
style="height: 8px"
>
<div <div
class="progress-bar progress-bar-striped bg-warning" class="progress-bar progress-bar-striped bg-warning"
role="progressbar" role="progressbar"

View file

@ -1,46 +1,39 @@
<script setup lang="ts"> <script setup lang="ts">
import { saveSettingsToFile } from "../js/settingsHandler";
import {saveSettingsToFile} from '../js/settingsHandler' import { setActivePinia } from "pinia";
import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
import { useStateStore } from '../store/stateStore.js'; import { useStateStore } from "../store/stateStore.js";
const state = useStateStore(pinia); const state = useStateStore(pinia);
import {sendCQ, sendPing, startBeacon, stopBeacon} from '../js/sock.js' import { sendCQ, sendPing, startBeacon, stopBeacon } from "../js/sock.js";
function transmitCQ() { function transmitCQ() {
sendCQ() sendCQ();
} }
function transmitPing() { function transmitPing() {
sendPing(document.getElementById("dxCall").value) sendPing(document.getElementById("dxCall").value);
} }
function startStopBeacon() { function startStopBeacon() {
switch (state.beacon_state) { switch (state.beacon_state) {
case 'False': case "False":
startBeacon(settings.beacon_interval) startBeacon(settings.beacon_interval);
break; break;
case 'True': case "True":
stopBeacon() stopBeacon();
break; break;
default: default:
} }
} }
</script> </script>
<template> <template>
<div class="card mb-1"> <div class="card mb-1">
@ -61,10 +54,7 @@ function startStopBeacon(){
data-bs-target="#broadcastsHelpModal" data-bs-target="#broadcastsHelpModal"
class="btn m-0 p-0 border-0" class="btn m-0 p-0 border-0"
> >
<i <i class="bi bi-question-circle" style="font-size: 1rem"></i>
class="bi bi-question-circle"
style="font-size: 1rem"
></i>
</button> </button>
</div> </div>
</div> </div>
@ -99,7 +89,6 @@ function startStopBeacon(){
Ping Ping
</button> </button>
<button <button
class="btn btn-sm btn-outline-secondary ms-1" class="btn btn-sm btn-outline-secondary ms-1"
id="sendCQ" id="sendCQ"
@ -115,8 +104,10 @@ function startStopBeacon(){
id="startBeacon" id="startBeacon"
class="btn btn-sm ms-1" class="btn btn-sm ms-1"
@click="startStopBeacon()" @click="startStopBeacon()"
v-bind:class="{ 'btn-success' : state.beacon_state === 'True', v-bind:class="{
'btn-outline-secondary' : state.beacon_state === 'False'}" 'btn-success': state.beacon_state === 'True',
'btn-outline-secondary': state.beacon_state === 'False',
}"
title="Toggle beacon mode. The interval can be set in settings. While sending a beacon, you can receive ping requests and open a datachannel. If a datachannel is opened, the beacon pauses." title="Toggle beacon mode. The interval can be set in settings. While sending a beacon, you can receive ping requests and open a datachannel. If a datachannel is opened, the beacon pauses."
> >
<i class="bi bi-soundwave"></i> Toggle beacon <i class="bi bi-soundwave"></i> Toggle beacon

View file

@ -1,5 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
const { const {
locatorToLatLng, locatorToLatLng,
distance, distance,
@ -7,21 +6,18 @@ const {
latLngToLocator, latLngToLocator,
} = require("qth-locator"); } = require("qth-locator");
import { saveSettingsToFile } from "../js/settingsHandler";
import { setActivePinia } from "pinia";
import {saveSettingsToFile} from '../js/settingsHandler' import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
import { useStateStore } from '../store/stateStore.js'; import { useStateStore } from "../store/stateStore.js";
const state = useStateStore(pinia); const state = useStateStore(pinia);
function getDateTime(timestampRaw) { function getDateTime(timestampRaw) {
var datetime = new Date(timestampRaw * 1000).toLocaleString( var datetime = new Date(timestampRaw * 1000).toLocaleString(
navigator.language, navigator.language,
@ -35,7 +31,7 @@ function getDateTime(timestampRaw){
second: "2-digit", second: "2-digit",
}, },
); );
return datetime return datetime;
} }
function getMaidenheadDistance(dxGrid) { function getMaidenheadDistance(dxGrid) {
@ -44,24 +40,16 @@ try{
} catch (e) { } catch (e) {
// //
} }
} }
</script> </script>
<template> <template>
<div class="card mb-1" style="height: 240px"> <div class="card mb-1" style="height: 240px">
<!--325px--> <!--325px-->
<div class="card-header p-1"> <div class="card-header p-1">
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-auto"> <div class="col-auto">
<i <i class="bi bi-list-columns-reverse" style="font-size: 1.2rem"></i>
class="bi bi-list-columns-reverse"
style="font-size: 1.2rem"
></i>
</div> </div>
<div class="col-10"> <div class="col-10">
<strong class="fs-5">Heard stations</strong> <strong class="fs-5">Heard stations</strong>
@ -74,10 +62,7 @@ try{
data-bs-target="#heardStationsHelpModal" data-bs-target="#heardStationsHelpModal"
class="btn m-0 p-0 border-0" class="btn m-0 p-0 border-0"
> >
<i <i class="bi bi-question-circle" style="font-size: 1rem"></i>
class="bi bi-question-circle"
style="font-size: 1rem"
></i>
</button> </button>
</div> </div>
</div> </div>
@ -108,7 +93,9 @@ try{
<td>{{ getDateTime(item.timestamp) }}</td> <td>{{ getDateTime(item.timestamp) }}</td>
<td>{{ item.frequency }}</td> <td>{{ item.frequency }}</td>
<td>&nbsp;</td> <td>&nbsp;</td>
<td><span class="badge bg-secondary">{{ item.dxcallsign }}</span></td> <td>
<span class="badge bg-secondary">{{ item.dxcallsign }}</span>
</td>
<td>{{ item.dxgrid }}</td> <td>{{ item.dxgrid }}</td>
<td>{{ getMaidenheadDistance(item.dxgrid) }} km</td> <td>{{ getMaidenheadDistance(item.dxgrid) }} km</td>
<td>{{ item.datatype }}</td> <td>{{ item.datatype }}</td>
@ -121,5 +108,4 @@ try{
<!-- END OF HEARD STATIONS TABLE --> <!-- END OF HEARD STATIONS TABLE -->
</div> </div>
</div> </div>
</template> </template>

View file

@ -1,50 +1,51 @@
<script setup lang="ts"> <script setup lang="ts">
import { saveSettingsToFile } from "../js/settingsHandler";
import {saveSettingsToFile} from '../js/settingsHandler' import { setActivePinia } from "pinia";
import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
import { useStateStore } from '../store/stateStore.js'; import { useStateStore } from "../store/stateStore.js";
const state = useStateStore(pinia); const state = useStateStore(pinia);
import {set_frequency, set_mode} from '../js/sock.js' import { set_frequency, set_mode } from "../js/sock.js";
function set_hamlib_frequency() { function set_hamlib_frequency() {
set_frequency(state.new_frequency) set_frequency(state.new_frequency);
} }
function set_hamlib_mode() { function set_hamlib_mode() {
set_mode(state.mode) set_mode(state.mode);
} }
function set_hamlib_rf_level() { function set_hamlib_rf_level() {
set_rf_level(state.rf_level) set_rf_level(state.rf_level);
} }
</script> </script>
<template> <template>
<div class="mb-3"> <div class="mb-3">
<div class="card mb-1"> <div class="card mb-1">
<div class="card-header p-1"> <div class="card-header p-1">
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-1"> <div class="col-1">
<i class="bi bi-house-door" style="font-size: 1.2rem"></i> <i class="bi bi-house-door" style="font-size: 1.2rem"></i>
</div> </div>
<div class="col-10"> <div class="col-10">
<strong class="fs-5 me-2">Radio control</strong> <span class="badge" v-bind:class="{ 'text-bg-success' : state.hamlib_status === 'connected', <strong class="fs-5 me-2">Radio control</strong>
'text-bg-danger disabled' : state.hamlib_status === 'disconnected'}">{{state.hamlib_status}}</span> <span
class="badge"
v-bind:class="{
'text-bg-success': state.hamlib_status === 'connected',
'text-bg-danger disabled':
state.hamlib_status === 'disconnected',
}"
>{{ state.hamlib_status }}</span
>
</div> </div>
<div class="col-1 text-end"> <div class="col-1 text-end">
<button <button
@ -55,36 +56,30 @@ function set_hamlib_rf_level(){
class="btn m-0 p-0 border-0" class="btn m-0 p-0 border-0"
disabled disabled
> >
<i <i class="bi bi-question-circle" style="font-size: 1rem"></i>
class="bi bi-question-circle"
style="font-size: 1rem"
></i>
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="card-body p-2"> <div class="card-body p-2">
<div class="input-group bottom-0 m-0"> <div class="input-group bottom-0 m-0">
<div class="me-2"> <div class="me-2">
<div class="input-group"> <div class="input-group">
<span class="input-group-text">QRG</span> <span class="input-group-text">QRG</span>
<span class="input-group-text">{{ state.frequency }} Hz</span> <span class="input-group-text">{{ state.frequency }} Hz</span>
<span class="input-group-text">QSY</span> <span class="input-group-text">QSY</span>
<input type="text" class="form-control" v-model="state.new_frequency" style="max-width: 8rem;" <input
pattern="[0-9]*" list="frequencyDataList" v-bind:class="{ 'disabled' : state.hamlib_status === 'disconnected'}"> type="text"
class="form-control"
v-model="state.new_frequency"
style="max-width: 8rem"
pattern="[0-9]*"
list="frequencyDataList"
v-bind:class="{
disabled: state.hamlib_status === 'disconnected',
}"
/>
<datalist id="frequencyDataList"> <datalist id="frequencyDataList">
<option selected value="7053000">40m | USB | EU, US</option> <option selected value="7053000">40m | USB | EU, US</option>
@ -95,30 +90,49 @@ function set_hamlib_rf_level(){
<option value="50308000">6m | USB | US</option> <option value="50308000">6m | USB | US</option>
<option value="50616000">6m | USB | EU, US</option> <option value="50616000">6m | USB | EU, US</option>
</datalist> </datalist>
<button class="btn btn-sm btn-outline-success" type="button" @click="set_hamlib_frequency" v-bind:class="{ 'disabled' : state.hamlib_status === 'disconnected'}">Apply</button> <button
class="btn btn-sm btn-outline-success"
type="button"
@click="set_hamlib_frequency"
v-bind:class="{
disabled: state.hamlib_status === 'disconnected',
}"
>
Apply
</button>
</div> </div>
</div> </div>
<div class="me-2"> <div class="me-2">
<div class="input-group"> <div class="input-group">
<span class="input-group-text">Mode</span> <span class="input-group-text">Mode</span>
<select class="form-control" v-model="state.mode" @click="set_hamlib_mode()" v-bind:class="{ 'disabled' : state.hamlib_status === 'disconnected'}"> <select
class="form-control"
v-model="state.mode"
@click="set_hamlib_mode()"
v-bind:class="{
disabled: state.hamlib_status === 'disconnected',
}"
>
<option value="USB">USB</option> <option value="USB">USB</option>
<option value="LSB">LSB</option> <option value="LSB">LSB</option>
<option value="AM">AM</option> <option value="AM">AM</option>
<option value="FM">FM</option> <option value="FM">FM</option>
</select> </select>
</div> </div>
</div> </div>
<div class="me-2"> <div class="me-2">
<div class="input-group"> <div class="input-group">
<span class="input-group-text">Power</span> <span class="input-group-text">Power</span>
<select class="form-control" v-model="state.rf_level" @click="set_hamlib_rf_level()" v-bind:class="{ 'disabled' : state.hamlib_status === 'disconnected'}"> <select
class="form-control"
v-model="state.rf_level"
@click="set_hamlib_rf_level()"
v-bind:class="{
disabled: state.hamlib_status === 'disconnected',
}"
>
<option value="0">-</option> <option value="0">-</option>
<option value="10">10</option> <option value="10">10</option>
<option value="20">20</option> <option value="20">20</option>
@ -132,44 +146,10 @@ function set_hamlib_rf_level(){
<option value="100">100</option> <option value="100">100</option>
</select> </select>
<span class="input-group-text">%</span> <span class="input-group-text">%</span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div></div> </div>
</div>
</template> </template>

View file

@ -1,19 +1,16 @@
<script setup lang="ts"> <script setup lang="ts">
import { saveSettingsToFile } from "../js/settingsHandler";
import { setActivePinia } from "pinia";
import {saveSettingsToFile} from '../js/settingsHandler'; import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
import { useStateStore } from '../store/stateStore.js'; import { useStateStore } from "../store/stateStore.js";
const state = useStateStore(pinia); const state = useStateStore(pinia);
import { import {
Chart as ChartJS, Chart as ChartJS,
CategoryScale, CategoryScale,
@ -22,43 +19,32 @@ import {
LineElement, LineElement,
Title, Title,
Tooltip, Tooltip,
Legend Legend,
} from 'chart.js' } from "chart.js";
import { Line, Scatter } from 'vue-chartjs' import { Line, Scatter } from "vue-chartjs";
import { ref, computed } from 'vue'; import { ref, computed } from "vue";
function selectStatsControl(obj) { function selectStatsControl(obj) {
switch (obj.delegateTarget.id) { switch (obj.delegateTarget.id) {
case 'list-waterfall-list': case "list-waterfall-list":
settings.spectrum = "waterfall" settings.spectrum = "waterfall";
break; break;
case 'list-scatter-list': case "list-scatter-list":
settings.spectrum = "scatter" settings.spectrum = "scatter";
break; break;
case 'list-chart-list': case "list-chart-list":
settings.spectrum = "chart" settings.spectrum = "chart";
break; break;
default: default:
settings.spectrum = "waterfall" settings.spectrum = "waterfall";
} }
saveSettingsToFile() saveSettingsToFile();
} }
var transmissionSpeedChartOptions = { var transmissionSpeedChartOptions = {
type: "line", type: "line",
}; };
ChartJS.register( ChartJS.register(
CategoryScale, CategoryScale,
LinearScale, LinearScale,
@ -66,9 +52,8 @@ ChartJS.register(
LineElement, LineElement,
Title, Title,
Tooltip, Tooltip,
Legend Legend,
) );
// https://www.chartjs.org/docs/latest/samples/line/segments.html // https://www.chartjs.org/docs/latest/samples/line/segments.html
const skipped = (speedCtx, value) => const skipped = (speedCtx, value) =>
@ -128,19 +113,16 @@ const transmissionSpeedChartData = computed(() => ({
order: 0, order: 0,
yAxisID: "SPEED", yAxisID: "SPEED",
}, },
] ],
} }));
));
const scatterChartOptions = { const scatterChartOptions = {
responsive: true, responsive: true,
maintainAspectRatio: true, maintainAspectRatio: true,
scales: { scales: {
x: { x: {
type: 'linear', type: "linear",
position: 'bottom', position: "bottom",
grid: { grid: {
display: true, display: true,
lineWidth: 1, // Set the line width for x-axis grid lines lineWidth: 1, // Set the line width for x-axis grid lines
@ -150,8 +132,8 @@ const scatterChartOptions = {
}, },
}, },
y: { y: {
type: 'linear', type: "linear",
position: 'left', position: "left",
grid: { grid: {
display: true, display: true,
lineWidth: 1, // Set the line width for y-axis grid lines lineWidth: 1, // Set the line width for y-axis grid lines
@ -171,16 +153,21 @@ const scatterChartOptions = {
}, },
}; };
// dummy data // dummy data
//state.scatter = [{"x":"166","y":"46"},{"x":"-193","y":"-139"},{"x":"-165","y":"-291"},{"x":"311","y":"-367"},{"x":"389","y":"199"},{"x":"78","y":"372"},{"x":"242","y":"-431"},{"x":"-271","y":"-248"},{"x":"28","y":"-130"},{"x":"-20","y":"187"},{"x":"74","y":"362"},{"x":"-316","y":"-229"},{"x":"-180","y":"261"},{"x":"321","y":"360"},{"x":"438","y":"-288"},{"x":"378","y":"-94"},{"x":"462","y":"-163"},{"x":"-265","y":"248"},{"x":"210","y":"314"},{"x":"230","y":"-320"},{"x":"261","y":"-244"},{"x":"-283","y":"-373"}] //state.scatter = [{"x":"166","y":"46"},{"x":"-193","y":"-139"},{"x":"-165","y":"-291"},{"x":"311","y":"-367"},{"x":"389","y":"199"},{"x":"78","y":"372"},{"x":"242","y":"-431"},{"x":"-271","y":"-248"},{"x":"28","y":"-130"},{"x":"-20","y":"187"},{"x":"74","y":"362"},{"x":"-316","y":"-229"},{"x":"-180","y":"261"},{"x":"321","y":"360"},{"x":"438","y":"-288"},{"x":"378","y":"-94"},{"x":"462","y":"-163"},{"x":"-265","y":"248"},{"x":"210","y":"314"},{"x":"230","y":"-320"},{"x":"261","y":"-244"},{"x":"-283","y":"-373"}]
const scatterChartData = computed(() => ({ const scatterChartData = computed(() => ({
datasets: [ datasets: [
{ type: 'scatter', fill: true, data: state.scatter, label: 'Scatter' ,tension: 0.1, borderColor: 'rgb(0, 255, 0)' }, {
] type: "scatter",
} fill: true,
)); data: state.scatter,
label: "Scatter",
tension: 0.1,
borderColor: "rgb(0, 255, 0)",
},
],
}));
</script> </script>
<template> <template>
@ -202,7 +189,7 @@ const scatterChartData = computed(() => ({
href="#list-waterfall" href="#list-waterfall"
role="tab" role="tab"
aria-controls="list-waterfall" aria-controls="list-waterfall"
v-bind:class="{ 'active' : settings.spectrum === 'waterfall'}" v-bind:class="{ active: settings.spectrum === 'waterfall' }"
@click="selectStatsControl($event)" @click="selectStatsControl($event)"
><strong><i class="bi bi-water"></i></strong ><strong><i class="bi bi-water"></i></strong
></a> ></a>
@ -213,7 +200,7 @@ const scatterChartData = computed(() => ({
href="#list-scatter" href="#list-scatter"
role="tab" role="tab"
aria-controls="list-scatter" aria-controls="list-scatter"
v-bind:class="{ 'active' : settings.spectrum === 'scatter'}" v-bind:class="{ active: settings.spectrum === 'scatter' }"
@click="selectStatsControl($event)" @click="selectStatsControl($event)"
><strong><i class="bi bi-border-outer"></i></strong ><strong><i class="bi bi-border-outer"></i></strong
></a> ></a>
@ -224,7 +211,7 @@ const scatterChartData = computed(() => ({
href="#list-chart" href="#list-chart"
role="tab" role="tab"
aria-controls="list-chart" aria-controls="list-chart"
v-bind:class="{ 'active' : settings.spectrum === 'chart'}" v-bind:class="{ active: settings.spectrum === 'chart' }"
@click="selectStatsControl($event)" @click="selectStatsControl($event)"
><strong><i class="bi bi-graph-up-arrow"></i></strong ><strong><i class="bi bi-graph-up-arrow"></i></strong
></a> ></a>
@ -238,7 +225,10 @@ const scatterChartData = computed(() => ({
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-trigger="hover" data-bs-trigger="hover"
data-bs-html="true" data-bs-html="true"
v-bind:class="{ 'btn-warning' : state.channel_busy === 'True', 'btn-outline-secondary' : state.channel_busy === 'False'}" v-bind:class="{
'btn-warning': state.channel_busy === 'True',
'btn-outline-secondary': state.channel_busy === 'False',
}"
title="Channel busy state: <strong class='text-success'>not busy</strong> / <strong class='text-danger'>busy </strong>" title="Channel busy state: <strong class='text-success'>not busy</strong> / <strong class='text-danger'>busy </strong>"
> >
busy busy
@ -251,7 +241,10 @@ const scatterChartData = computed(() => ({
data-bs-trigger="hover" data-bs-trigger="hover"
data-bs-html="true" data-bs-html="true"
title="Recieving data: illuminates <strong class='text-success'>green</strong> if receiving codec2 data" title="Recieving data: illuminates <strong class='text-success'>green</strong> if receiving codec2 data"
v-bind:class="{ 'btn-success' : state.is_codec2_traffic === 'True', 'btn-outline-secondary' : state.is_codec2_traffic === 'False'}" v-bind:class="{
'btn-success': state.is_codec2_traffic === 'True',
'btn-outline-secondary': state.is_codec2_traffic === 'False',
}"
> >
signal signal
</button> </button>
@ -295,7 +288,6 @@ const scatterChartData = computed(() => ({
aria-labelledby="list-scatter-list" aria-labelledby="list-scatter-list"
> >
<Scatter :data="scatterChartData" :options="scatterChartOptions" /> <Scatter :data="scatterChartData" :options="scatterChartOptions" />
</div> </div>
<div <div
class="tab-pane fade" class="tab-pane fade"

View file

@ -1,20 +1,13 @@
<script setup> <script setup>
import { setActivePinia } from "pinia";
import { setActivePinia } from 'pinia'; import pinia from "../store/index";
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useAudioStore } from '../store/audioStore.js'; import { useAudioStore } from "../store/audioStore.js";
const audio = useAudioStore(pinia); const audio = useAudioStore(pinia);
</script> </script>
<template> <template>
<div class="card mb-0"> <div class="card mb-0">
<div class="card-header p-1"> <div class="card-header p-1">
<div class="container"> <div class="container">
@ -33,10 +26,7 @@ const audio = useAudioStore(pinia);
data-bs-target="#audioHelpModal" data-bs-target="#audioHelpModal"
class="btn m-0 p-0 border-0" class="btn m-0 p-0 border-0"
> >
<i <i class="bi bi-question-circle" style="font-size: 1rem"></i>
class="bi bi-question-circle"
style="font-size: 1rem"
></i>
</button> </button>
</div> </div>
</div> </div>
@ -53,8 +43,7 @@ const audio = useAudioStore(pinia);
id="audio_input_selectbox" id="audio_input_selectbox"
aria-label=".form-select-sm" aria-label=".form-select-sm"
v-html="audio.getInputDevices()" v-html="audio.getInputDevices()"
> ></select>
</select>
</div> </div>
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
<span class="input-group-text"> <span class="input-group-text">
@ -65,8 +54,7 @@ const audio = useAudioStore(pinia);
id="audio_output_selectbox" id="audio_output_selectbox"
aria-label=".form-select-sm" aria-label=".form-select-sm"
v-html="audio.getOutputDevices()" v-html="audio.getOutputDevices()"
> ></select>
</select>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,18 +1,15 @@
<script setup lang="ts"> <script setup lang="ts">
import { saveSettingsToFile } from "../js/settingsHandler";
import {saveSettingsToFile} from '../js/settingsHandler' import { setActivePinia } from "pinia";
import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useStateStore } from '../store/stateStore.js'; import { useStateStore } from "../store/stateStore.js";
const state = useStateStore(pinia); const state = useStateStore(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
</script> </script>
<template> <template>
@ -20,13 +17,15 @@ const settings = useSettingsStore(pinia);
class="navbar fixed-bottom navbar-expand-xl bg-body-tertiary border-top p-2" class="navbar fixed-bottom navbar-expand-xl bg-body-tertiary border-top p-2"
style="margin-left: 87px" style="margin-left: 87px"
> >
<div class="col"> <div class="col">
<div class="btn-toolbar" role="toolbar" style="margin-left: 2px"> <div class="btn-toolbar" role="toolbar" style="margin-left: 2px">
<div class="btn-group btn-group-sm me-1" role="group"> <div class="btn-group btn-group-sm me-1" role="group">
<button <button
class="btn btn-sm btn-secondary me-1" class="btn btn-sm btn-secondary me-1"
v-bind:class="{ 'bg-danger' : state.ptt_state === 'True', 'bg-success' : state.ptt_state === 'False'}" v-bind:class="{
'bg-danger': state.ptt_state === 'True',
'bg-success': state.ptt_state === 'False',
}"
id="ptt_state" id="ptt_state"
type="button" type="button"
data-bs-placement="top" data-bs-placement="top"
@ -46,7 +45,10 @@ const settings = useSettingsStore(pinia);
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-trigger="hover" data-bs-trigger="hover"
data-bs-html="true" data-bs-html="true"
v-bind:class="{ 'bg-danger' : state.busy_state === 'BUSY', 'bg-success' : state.busy_state === 'IDLE'}" v-bind:class="{
'bg-danger': state.busy_state === 'BUSY',
'bg-success': state.busy_state === 'IDLE',
}"
title="TNC busy state: <strong class='text-success'>IDLE</strong> / <strong class='text-danger'>BUSY</strong>" title="TNC busy state: <strong class='text-success'>IDLE</strong> / <strong class='text-danger'>BUSY</strong>"
> >
<i class="bi bi-cpu" style="font-size: 0.8rem"></i> <i class="bi bi-cpu" style="font-size: 0.8rem"></i>
@ -61,7 +63,10 @@ const settings = useSettingsStore(pinia);
data-bs-trigger="hover" data-bs-trigger="hover"
data-bs-html="true" data-bs-html="true"
title="ARQ SESSION state: <strong class='text-warning'>OPEN</strong>" title="ARQ SESSION state: <strong class='text-warning'>OPEN</strong>"
v-bind:class="{ 'bg-secondary' : state.arq_session_state === 'disconnected', 'bg-success' : state.arq_session_state === 'connected'}" v-bind:class="{
'bg-secondary': state.arq_session_state === 'disconnected',
'bg-success': state.arq_session_state === 'connected',
}"
> >
<i class="bi bi-arrow-left-right" style="font-size: 0.8rem"></i> <i class="bi bi-arrow-left-right" style="font-size: 0.8rem"></i>
</button> </button>
@ -75,13 +80,12 @@ const settings = useSettingsStore(pinia);
data-bs-trigger="hover" data-bs-trigger="hover"
data-bs-html="true" data-bs-html="true"
title="DATA-CHANNEL state: <strong class='text-warning'>OPEN</strong>" title="DATA-CHANNEL state: <strong class='text-warning'>OPEN</strong>"
v-bind:class="{ 'bg-secondary' : state.arq_state === 'False', 'bg-success' : state.arq_state === 'True'}" v-bind:class="{
'bg-secondary': state.arq_state === 'False',
'bg-success': state.arq_state === 'True',
}"
> >
<i <i class="bi bi-file-earmark-binary" style="font-size: 0.8rem"></i>
class="bi bi-file-earmark-binary"
style="font-size: 0.8rem"
></i>
</button> </button>
<!-- <!--
<button <button
@ -105,17 +109,16 @@ const settings = useSettingsStore(pinia);
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-trigger="hover" data-bs-trigger="hover"
data-bs-html="true" data-bs-html="true"
v-bind:class="{ 'btn-warning' : state.channel_busy === 'True', 'btn-secondary' : state.channel_busy === 'False'}" v-bind:class="{
'btn-warning': state.channel_busy === 'True',
'btn-secondary': state.channel_busy === 'False',
}"
title="Channel busy state: <strong class='text-success'>not busy</strong> / <strong class='text-danger'>busy </strong>" title="Channel busy state: <strong class='text-success'>not busy</strong> / <strong class='text-danger'>busy </strong>"
> >
<i class="bi bi-hourglass"></i> <i class="bi bi-hourglass"></i>
</button> </button>
</div> </div>
<div class="btn-group btn-group-sm me-1" role="group"> <div class="btn-group btn-group-sm me-1" role="group">
<button <button
class="btn btn-sm btn-secondary me-4 disabled" class="btn btn-sm btn-secondary me-4 disabled"
@ -127,17 +130,9 @@ const settings = useSettingsStore(pinia);
> >
{{ state.frequency }} Hz {{ state.frequency }} Hz
</button> </button>
</div> </div>
<div class="btn-group btn-group-sm me-1" role="group"> <div class="btn-group btn-group-sm me-1" role="group">
<button <button
class="btn btn-sm btn-secondary me-0" class="btn btn-sm btn-secondary me-0"
type="button" type="button"
@ -149,7 +144,6 @@ const settings = useSettingsStore(pinia);
<i class="bi bi-speedometer2" style="font-size: 1rem"></i> <i class="bi bi-speedometer2" style="font-size: 1rem"></i>
</button> </button>
<button <button
class="btn btn-sm btn-secondary me-4 disabled" class="btn btn-sm btn-secondary me-4 disabled"
type="button" type="button"
@ -158,25 +152,20 @@ const settings = useSettingsStore(pinia);
data-bs-trigger="hover" data-bs-trigger="hover"
data-bs-html="true" data-bs-html="true"
> >
<i
class="bi"
<i class="bi " style="font-size: 1rem" style="font-size: 1rem"
v-bind:class="{ 'bi-reception-0' : state.speed_level === '0', v-bind:class="{
'bi-reception-0': state.speed_level === '0',
'bi-reception-1': state.speed_level === '1', 'bi-reception-1': state.speed_level === '1',
'bi-reception-2': state.speed_level === '2', 'bi-reception-2': state.speed_level === '2',
'bi-reception-3': state.speed_level === '3', 'bi-reception-3': state.speed_level === '3',
'bi-reception-4': state.speed_level === '4', 'bi-reception-4': state.speed_level === '4',
}" }"
></i> ></i>
</button> </button>
</div> </div>
<div class="btn-group btn-group-sm me-1" role="group"> <div class="btn-group btn-group-sm me-1" role="group">
<button <button
class="btn btn-sm btn-secondary me-0" class="btn btn-sm btn-secondary me-0"
type="button" type="button"
@ -188,7 +177,6 @@ const settings = useSettingsStore(pinia);
<i class="bi bi-file-earmark-binary" style="font-size: 1rem"></i> <i class="bi bi-file-earmark-binary" style="font-size: 1rem"></i>
</button> </button>
<button <button
class="btn btn-sm btn-secondary me-4 disabled" class="btn btn-sm btn-secondary me-4 disabled"
type="button" type="button"
@ -212,7 +200,6 @@ const settings = useSettingsStore(pinia);
<i class="bi bi-file-earmark-binary" style="font-size: 1rem"></i> <i class="bi bi-file-earmark-binary" style="font-size: 1rem"></i>
</button> </button>
<button <button
class="btn btn-sm btn-secondary disabled me-1" class="btn btn-sm btn-secondary disabled me-1"
type="button" type="button"
@ -223,22 +210,15 @@ const settings = useSettingsStore(pinia);
> >
{{ state.dxcallsign }} {{ state.dxcallsign }}
</button> </button>
</div> </div>
</div> </div>
</div> </div>
<div class="col-lg-4"> <div class="col-lg-4">
<div style="margin-right: 2px"> <div style="margin-right: 2px">
<div
class="progress w-100 rounded-0 rounded-top"
style="height: 20px; min-width: 200px"
>
<div class="progress w-100 rounded-0 rounded-top" style="height: 20px; min-width: 200px">
<div <div
class="progress-bar progress-bar-striped bg-primary force-gpu" class="progress-bar progress-bar-striped bg-primary force-gpu"
id="transmission_progress" id="transmission_progress"
@ -248,16 +228,15 @@ const settings = useSettingsStore(pinia);
aria-valuemin="0" aria-valuemin="0"
aria-valuemax="100" aria-valuemax="100"
></div> ></div>
<p <p class="justify-content-center m-0 d-flex position-absolute w-100">
class="justify-content-center m-0 d-flex position-absolute w-100"
>
{{ state.arq_seconds_until_finish }}s left {{ state.arq_seconds_until_finish }}s left
</p> </p>
</div> </div>
<div
<div class="progress mb-0 rounded-0 rounded-bottom" style="height: 10px"> class="progress mb-0 rounded-0 rounded-bottom"
style="height: 10px"
>
<div <div
class="progress-bar progress-bar-striped bg-warning" class="progress-bar progress-bar-striped bg-warning"
id="transmission_timeleft" id="transmission_timeleft"
@ -267,21 +246,14 @@ const settings = useSettingsStore(pinia);
aria-valuemin="0" aria-valuemin="0"
aria-valuemax="100" aria-valuemax="100"
> >
<p <p
class="justify-content-center m-0 d-flex position-absolute w-100" class="justify-content-center m-0 d-flex position-absolute w-100"
> >
timeout in: {{ state.arq_seconds_until_timeout }}s timeout in: {{ state.arq_seconds_until_timeout }}s
</p> </p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</nav> </nav>
</template> </template>

View file

@ -1,34 +1,28 @@
<script setup lang="ts"> <script setup lang="ts">
import { saveSettingsToFile } from "../js/settingsHandler";
import {saveSettingsToFile} from '../js/settingsHandler' import { setActivePinia } from "pinia";
import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
import { useStateStore } from '../store/stateStore.js'; import { useStateStore } from "../store/stateStore.js";
const state = useStateStore(pinia); const state = useStateStore(pinia);
import {sendTestFrame, setTxAudioLevel} from '../js/sock.js' import { sendTestFrame, setTxAudioLevel } from "../js/sock.js";
function tuneAudio() { function tuneAudio() {
sendTestFrame() sendTestFrame();
} }
function set_audio_level(obj) { function set_audio_level(obj) {
setTxAudioLevel(state.audio_level);
setTxAudioLevel(state.audio_level)
} }
</script> </script>
<template> <template>
<!-- HELP MODALS AUDIO --> <!-- HELP MODALS AUDIO -->
<div <div
class="modal fade" class="modal fade"
@ -127,8 +121,8 @@ setTxAudioLevel(state.audio_level)
<div class="card-body"> <div class="card-body">
<h5 class="card-title">None/Vox</h5> <h5 class="card-title">None/Vox</h5>
<p class="card-text"> <p class="card-text">
Select "None/Vox" if you want to use Vox for triggering PTT. Select "None/Vox" if you want to use Vox for triggering PTT. No
No connection to rigctld will be established. No frequency connection to rigctld will be established. No frequency
information is availble. information is availble.
</p> </p>
</div> </div>
@ -140,8 +134,8 @@ setTxAudioLevel(state.audio_level)
<p class="card-text"> <p class="card-text">
Select "Hamlib" if you want to have more control over your Select "Hamlib" if you want to have more control over your
radio. Define your hamlib settings in settings, and click the radio. Define your hamlib settings in settings, and click the
start button to start rigctld. You may use the 'PTT test' start button to start rigctld. You may use the 'PTT test' button
button to ensure rig control is working. to ensure rig control is working.
</p> </p>
</div> </div>
</div> </div>
@ -243,8 +237,8 @@ setTxAudioLevel(state.audio_level)
</div> </div>
</h5> </h5>
<p class="card-text"> <p class="card-text">
Enter your position as a 4 or 6 digit grid square, also known Enter your position as a 4 or 6 digit grid square, also known as
as a maidenhead locator. Six digits are recommended. a maidenhead locator. Six digits are recommended.
</p> </p>
</div> </div>
</div> </div>
@ -276,8 +270,8 @@ setTxAudioLevel(state.audio_level)
<h5 class="card-title">Auto-Updater</h5> <h5 class="card-title">Auto-Updater</h5>
<p class="card-text"> <p class="card-text">
The auto updater loads the latest version from Github and The auto updater loads the latest version from Github and
installs it automatically. You can select the update channel installs it automatically. You can select the update channel in
in settings. Once an update has been downlaoded, you need to settings. Once an update has been downlaoded, you need to
confirm the auto-installation and restart. confirm the auto-installation and restart.
</p> </p>
</div> </div>
@ -297,8 +291,7 @@ setTxAudioLevel(state.audio_level)
<p class="card-text"> <p class="card-text">
Beta releases are more stable than Alpha releases. They are a Beta releases are more stable than Alpha releases. They are a
good tradeoff between latest features and stability. They will good tradeoff between latest features and stability. They will
be updated less often. A beta release has not been released be updated less often. A beta release has not been released yet.
yet.
</p> </p>
</div> </div>
</div> </div>
@ -306,8 +299,8 @@ setTxAudioLevel(state.audio_level)
<div class="card-body"> <div class="card-body">
<h5 class="card-title">Stable</h5> <h5 class="card-title">Stable</h5>
<p class="card-text"> <p class="card-text">
Stable releases are the most stable versions with no known Stable releases are the most stable versions with no known major
major issues. A stable release has not been released yet. issues. A stable release has not been released yet.
</p> </p>
</div> </div>
</div> </div>
@ -415,11 +408,7 @@ setTxAudioLevel(state.audio_level)
aria-describedby="basic-addon1" aria-describedby="basic-addon1"
disabled disabled
/> />
<button <button class="btn btn-sm btn-danger" type="button" disabled>
class="btn btn-sm btn-danger"
type="button"
disabled
>
<i class="bi bi-diagram-3" style="font-size: 1rem"></i> <i class="bi bi-diagram-3" style="font-size: 1rem"></i>
</button> </button>
</div> </div>
@ -567,8 +556,8 @@ setTxAudioLevel(state.audio_level)
</div> </div>
</h5> </h5>
<p class="card-text"> <p class="card-text">
Represents the level of audio from transceiver. Excessively Represents the level of audio from transceiver. Excessively high
high levels will affect decoding performance negatively. levels will affect decoding performance negatively.
</p> </p>
</div> </div>
</div> </div>
@ -635,17 +624,14 @@ setTxAudioLevel(state.audio_level)
<div class="card mb-3"> <div class="card mb-3">
<div class="card-body"> <div class="card-body">
<h5 class="card-title"> <h5 class="card-title">
<button <button type="button" class="btn btn-sm btn-outline-secondary">
type="button"
class="btn btn-sm btn-outline-secondary"
>
Tune Tune
</button> </button>
</h5> </h5>
<p class="card-text"> <p class="card-text">
Adjust volume level of outgoing audio to transceiver. For best Adjust volume level of outgoing audio to transceiver. For best
results lower the level so that a minimum amount of ALC is results lower the level so that a minimum amount of ALC is used.
used. Can be used in combination with rig's mic/input gain for Can be used in combination with rig's mic/input gain for
furthrer refinement. furthrer refinement.
</p> </p>
</div> </div>
@ -694,12 +680,11 @@ setTxAudioLevel(state.audio_level)
</button> </button>
<p class="card-text"> <p class="card-text">
Send a ping to a remote station by entering a callsign and Send a ping to a remote station by entering a callsign and
optional SSID (-0 will be used if not specified.) optional SSID (-0 will be used if not specified.) Alternatively
Alternatively click on a station in the heard station list to click on a station in the heard station list to populate the
populate the call sign field. If the remote station decodes call sign field. If the remote station decodes the ping it will
the ping it will transmit a reply. If able to decode the transmit a reply. If able to decode the reply, a signal report
reply, a signal report will be listed in the heard station will be listed in the heard station list.
list.
</p> </p>
</div> </div>
</div> </div>
@ -787,8 +772,8 @@ setTxAudioLevel(state.audio_level)
</button> </button>
</h5> </h5>
<p class="card-text"> <p class="card-text">
Green when channel is open and changes to red to indicate Green when channel is open and changes to red to indicate there
there is activity on the channel. is activity on the channel.
</p> </p>
</div> </div>
</div> </div>
@ -815,8 +800,8 @@ setTxAudioLevel(state.audio_level)
</label> </label>
</h5> </h5>
<p class="card-text"> <p class="card-text">
Displays a plot of last decoded message. A constellation plot Displays a plot of last decoded message. A constellation plot is
is a simple way to represent signal quality. a simple way to represent signal quality.
</p> </p>
</div> </div>
</div> </div>
@ -864,9 +849,9 @@ setTxAudioLevel(state.audio_level)
<p class="card-text"> <p class="card-text">
Stations that you've been able to decode will be listed here. Stations that you've been able to decode will be listed here.
Details such as time, frequency, message type, call sign, Details such as time, frequency, message type, call sign,
location and SNR will be listed. Existing entries are updated location and SNR will be listed. Existing entries are updated if
if they already exist and more detailed history can be viewed they already exist and more detailed history can be viewed in
in chat window for each station. chat window for each station.
</p> </p>
</div> </div>
</div> </div>
@ -896,7 +881,12 @@ setTxAudioLevel(state.audio_level)
<div class="modal-body"> <div class="modal-body">
<div class="input-group input-group-sm mb-1"> <div class="input-group input-group-sm mb-1">
<span class="input-group-text">Test-Frame</span> <span class="input-group-text">Test-Frame</span>
<button type="button" id="sendTestFrame" @click="sendTestFrame()" class="btn btn-danger"> <button
type="button"
id="sendTestFrame"
@click="sendTestFrame()"
class="btn btn-danger"
>
Transmit Transmit
</button> </button>
</div> </div>
@ -919,5 +909,4 @@ setTxAudioLevel(state.audio_level)
</div> </div>
</div> </div>
</div> </div>
</template> </template>

View file

@ -1,23 +1,19 @@
<script setup lang="ts"> <script setup lang="ts">
import { saveSettingsToFile } from "../js/settingsHandler";
import {saveSettingsToFile} from '../js/settingsHandler' import { setActivePinia } from "pinia";
import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
function saveSettings() { function saveSettings() {
saveSettingsToFile() saveSettingsToFile();
} }
</script> </script>
<template> <template>
<div class="card mb-1"> <div class="card mb-1">
<div class="card-header p-1"> <div class="card-header p-1">
<div class="container"> <div class="container">
@ -36,10 +32,7 @@ function saveSettings(){
data-bs-target="#stationHelpModal" data-bs-target="#stationHelpModal"
class="btn m-0 p-0 border-0" class="btn m-0 p-0 border-0"
> >
<i <i class="bi bi-question-circle" style="font-size: 1rem"></i>
class="bi bi-question-circle"
style="font-size: 1rem"
></i>
</button> </button>
</div> </div>
</div> </div>
@ -57,10 +50,7 @@ function saveSettings(){
title="Enter your callsign and save it" title="Enter your callsign and save it"
> >
<span class="input-group-text"> <span class="input-group-text">
<i <i class="bi bi-person-bounding-box" style="font-size: 1rem"></i>
class="bi bi-person-bounding-box"
style="font-size: 1rem"
></i>
</span> </span>
<input <input
type="text" type="text"

View file

@ -1,39 +1,32 @@
<script setup lang="ts"> <script setup lang="ts">
import { saveSettingsToFile } from "../js/settingsHandler";
import {saveSettingsToFile} from '../js/settingsHandler' import { setActivePinia } from "pinia";
import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
function selectRadioControl(obj) { function selectRadioControl(obj) {
switch (event.target.id) { switch (event.target.id) {
case 'list-rig-control-none-list': case "list-rig-control-none-list":
settings.radiocontrol = "disabled" settings.radiocontrol = "disabled";
break; break;
case 'list-rig-control-rigctld-list': case "list-rig-control-rigctld-list":
settings.radiocontrol = "rigctld" settings.radiocontrol = "rigctld";
break; break;
case 'list-rig-control-tci-list': case "list-rig-control-tci-list":
settings.radiocontrol = "tci" settings.radiocontrol = "tci";
break; break;
default: default:
console.log("default=!==") console.log("default=!==");
settings.radiocontrol = "disabled" settings.radiocontrol = "disabled";
} }
saveSettingsToFile() saveSettingsToFile();
} }
</script> </script>
<template> <template>
<div class="card mb-0"> <div class="card mb-0">
<div class="card-header p-1"> <div class="card-header p-1">
@ -46,18 +39,46 @@ switch (event.target.id) {
<strong class="fs-5">Rig control</strong> <strong class="fs-5">Rig control</strong>
</div> </div>
<div class="col-6"> <div class="col-6">
<div
class="list-group list-group-horizontal"
<div class="list-group list-group-horizontal" id="rig-control-list-tab" role="rig-control-tablist"> id="rig-control-list-tab"
<a class="py-1 list-group-item list-group-item-action" id="list-rig-control-none-list" data-bs-toggle="list" href="#list-rig-control-none" role="tab" aria-controls="list-rig-control-none" v-bind:class="{ 'active' : settings.radiocontrol === 'disabled'}" @click="selectRadioControl()">None/Vox</a> role="rig-control-tablist"
<a class="py-1 list-group-item list-group-item-action" id="list-rig-control-rigctld-list" data-bs-toggle="list" href="#list-rig-control-rigctld" role="tab" aria-controls="list-rig-control-rigctld" v-bind:class="{ 'active' : settings.radiocontrol === 'rigctld'}" @click="selectRadioControl()">Rigctld</a> >
<a class="py-1 list-group-item list-group-item-action" id="list-rig-control-tci-list" data-bs-toggle="list" href="#list-rig-control-tci" role="tab" aria-controls="list-rig-control-tci" v-bind:class="{ 'active' : settings.radiocontrol === 'tci'}" @click="selectRadioControl()">TCI</a> <a
class="py-1 list-group-item list-group-item-action"
id="list-rig-control-none-list"
data-bs-toggle="list"
href="#list-rig-control-none"
role="tab"
aria-controls="list-rig-control-none"
v-bind:class="{ active: settings.radiocontrol === 'disabled' }"
@click="selectRadioControl()"
>None/Vox</a
>
<a
class="py-1 list-group-item list-group-item-action"
id="list-rig-control-rigctld-list"
data-bs-toggle="list"
href="#list-rig-control-rigctld"
role="tab"
aria-controls="list-rig-control-rigctld"
v-bind:class="{ active: settings.radiocontrol === 'rigctld' }"
@click="selectRadioControl()"
>Rigctld</a
>
<a
class="py-1 list-group-item list-group-item-action"
id="list-rig-control-tci-list"
data-bs-toggle="list"
href="#list-rig-control-tci"
role="tab"
aria-controls="list-rig-control-tci"
v-bind:class="{ active: settings.radiocontrol === 'tci' }"
@click="selectRadioControl()"
>TCI</a
>
</div> </div>
</div> </div>
<div class="col-1 text-end"> <div class="col-1 text-end">
@ -68,25 +89,34 @@ switch (event.target.id) {
data-bs-target="#rigcontrolHelpModal" data-bs-target="#rigcontrolHelpModal"
class="btn m-0 p-0 border-0" class="btn m-0 p-0 border-0"
> >
<i <i class="bi bi-question-circle" style="font-size: 1rem"></i>
class="bi bi-question-circle"
style="font-size: 1rem"
></i>
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="card-body p-2" style="height: 100px"> <div class="card-body p-2" style="height: 100px">
<div class="tab-content" id="rig-control-nav-tabContent"> <div class="tab-content" id="rig-control-nav-tabContent">
<div class="tab-pane fade" v-bind:class="{ 'show active' : settings.radiocontrol === 'disabled'}" id="list-rig-control-none" role="tabpanel" aria-labelledby="list-rig-control-none-list"><p class="small"> <div
TNC will not utilize rig control and features will be class="tab-pane fade"
limited. While functional; it is recommended to configure v-bind:class="{ 'show active': settings.radiocontrol === 'disabled' }"
hamlib. id="list-rig-control-none"
</p></div> role="tabpanel"
<div class="tab-pane fade" id="list-rig-control-rigctld" v-bind:class="{ 'show active' : settings.radiocontrol === 'rigctld'}" role="tabpanel" aria-labelledby="list-rig-control-rigctld-list"><div class="input-group input-group-sm mb-1"> aria-labelledby="list-rig-control-none-list"
>
<p class="small">
TNC will not utilize rig control and features will be limited. While
functional; it is recommended to configure hamlib.
</p>
</div>
<div
class="tab-pane fade"
id="list-rig-control-rigctld"
v-bind:class="{ 'show active': settings.radiocontrol === 'rigctld' }"
role="tabpanel"
aria-labelledby="list-rig-control-rigctld-list"
>
<div class="input-group input-group-sm mb-1">
<div class="input-group input-group-sm mb-1"> <div class="input-group input-group-sm mb-1">
<span class="input-group-text">Rigctld</span> <span class="input-group-text">Rigctld</span>
<span class="input-group-text">Address</span> <span class="input-group-text">Address</span>
@ -148,8 +178,16 @@ switch (event.target.id) {
PTT Test PTT Test
</button> </button>
</div> </div>
</div></div> </div>
<div class="tab-pane fade" id="list-rig-control-tci" v-bind:class="{ 'show active' : settings.radiocontrol === 'tci'}" role="tabpanel" aria-labelledby="list-rig-control-tci-list"><div class="input-group input-group-sm mb-1"> </div>
<div
class="tab-pane fade"
id="list-rig-control-tci"
v-bind:class="{ 'show active': settings.radiocontrol === 'tci' }"
role="tabpanel"
aria-labelledby="list-rig-control-tci-list"
>
<div class="input-group input-group-sm mb-1">
<div class="input-group input-group-sm mb-1"> <div class="input-group input-group-sm mb-1">
<span class="input-group-text">TCI</span> <span class="input-group-text">TCI</span>
<span class="input-group-text">Address</span> <span class="input-group-text">Address</span>
@ -174,27 +212,17 @@ switch (event.target.id) {
v-model="settings.tci_port" v-model="settings.tci_port"
/> />
</div> </div>
</div></div>
</div> </div>
</div>
</div>
<!-- RADIO CONTROL DISABLED --> <!-- RADIO CONTROL DISABLED -->
<div id="radio-control-disabled"> <div id="radio-control-disabled"></div>
</div>
<!-- RADIO CONTROL RIGCTLD --> <!-- RADIO CONTROL RIGCTLD -->
<div id="radio-control-rigctld"> <div id="radio-control-rigctld"></div>
</div>
<!-- RADIO CONTROL TCI--> <!-- RADIO CONTROL TCI-->
<div id="radio-control-tci"> <div id="radio-control-tci"></div>
</div>
<!-- RADIO CONTROL HELP --> <!-- RADIO CONTROL HELP -->
<div id="radio-control-help"> <div id="radio-control-help">
<!-- <!--
@ -207,7 +235,6 @@ switch (event.target.id) {
happens automatically. happens automatically.
--> -->
</div> </div>
</div> </div>
<!--<div class="card-footer text-muted small" id="hamlib_info_field"> <!--<div class="card-footer text-muted small" id="hamlib_info_field">
Define TNC rig control mode (none/hamlib) Define TNC rig control mode (none/hamlib)

View file

@ -1,68 +1,54 @@
<script setup lang="ts"> <script setup lang="ts">
import { saveSettingsToFile } from "../js/settingsHandler";
import {saveSettingsToFile} from '../js/settingsHandler' import { setActivePinia } from "pinia";
import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useStateStore } from '../store/stateStore.js'; import { useStateStore } from "../store/stateStore.js";
const state = useStateStore(pinia); const state = useStateStore(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
import {startTNC, stopTNC} from '../js/daemon.js' import { startTNC, stopTNC } from "../js/daemon.js";
function startStopTNC() { function startStopTNC() {
switch (state.tnc_running_state) { switch (state.tnc_running_state) {
case "stopped":
case 'stopped':
// todo: is there another way of doing this, maybe more VueJS like? // todo: is there another way of doing this, maybe more VueJS like?
settings.rx_audio = document.getElementById("audio_input_selectbox").value settings.rx_audio = document.getElementById(
settings.tx_audio = document.getElementById("audio_output_selectbox").value "audio_input_selectbox",
).value;
settings.tx_audio = document.getElementById(
"audio_output_selectbox",
).value;
startTNC() startTNC();
break; break;
case 'running': case "running":
stopTNC() stopTNC();
break; break;
default: default:
} }
} }
</script> </script>
<template> <template>
<nav class="navbar bg-body-tertiary border-bottom"> <nav class="navbar bg-body-tertiary border-bottom">
<div class="mx-auto"> <div class="mx-auto">
<span class="badge bg-secondary me-4"
>TNC location | {{ settings.tnc_host }}</span
>
<div class="btn-group" role="group"> <span class="badge bg-secondary me-4"
>Service | {{ state.tnc_running_state }}</span
>
<button <div class="btn-group" role="group"></div>
type="button"
id="startTNC"
class="btn btn-sm btn-outline-secondary disabled me-4"
>TNC address: {{settings.tnc_host}}
</button>
</div>
<div class="btn-group me-4" role="group"> <div class="btn-group me-4" role="group">
<button <button
type="button" type="button"
id="startTNC" id="startTNC"
@ -72,10 +58,10 @@ switch (state.tnc_running_state) {
data-bs-html="false" data-bs-html="false"
title="Start the TNC. Please set your audio and radio settings first!" title="Start the TNC. Please set your audio and radio settings first!"
@click="startStopTNC()" @click="startStopTNC()"
v-bind:class="{ 'disabled' : state.tnc_running_state === 'running'}" v-bind:class="{ disabled: state.tnc_running_state === 'running' }"
> >
<i class="bi bi-play-fill"></i> <i class="bi bi-play-fill"></i>
<span class="ms-2">Start tnc</span> <span class="ms-2">start tnc</span>
</button> </button>
<button <button
type="button" type="button"
@ -86,27 +72,13 @@ switch (state.tnc_running_state) {
data-bs-html="false" data-bs-html="false"
title="Stop the TNC." title="Stop the TNC."
@click="startStopTNC()" @click="startStopTNC()"
v-bind:class="{ 'disabled' : state.tnc_running_state === 'stopped'}" v-bind:class="{ disabled: state.tnc_running_state === 'stopped' }"
> >
<i class="bi bi-stop-fill"></i> <i class="bi bi-stop-fill"></i>
<span class="ms-2">Stop tnc</span> <span class="ms-2">stop tnc</span>
</button> </button>
</div> </div>
<div class="btn-group me-1" role="group">
<button
type="button"
id="startTNC"
class="btn btn-sm btn-outline-secondary disabled"
>TNC state:{{state.tnc_running_state}}
</button>
</div>
<button <button
type="button" type="button"
id="openHelpModalStartStopTNC" id="openHelpModalStartStopTNC"
@ -116,11 +88,8 @@ switch (state.tnc_running_state) {
> >
<i class="bi bi-question-circle" style="font-size: 1rem"></i> <i class="bi bi-question-circle" style="font-size: 1rem"></i>
</button> </button>
</div> </div>
<!-- <!--
<div class="btn-toolbar" role="toolbar"> <div class="btn-toolbar" role="toolbar">
@ -142,6 +111,5 @@ switch (state.tnc_running_state) {
</span> </span>
</div> </div>
--> --></nav>
</nav>
</template> </template>

View file

@ -1,14 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { setActivePinia } from "pinia";
import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
</script> </script>
<template> <template>
@ -17,10 +13,7 @@ const settings = useSettingsStore(pinia);
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-1"> <div class="col-1">
<i <i class="bi bi-cloud-download" style="font-size: 1.2rem"></i>
class="bi bi-cloud-download"
style="font-size: 1.2rem"
></i>
</div> </div>
<div class="col-3"> <div class="col-3">
<strong class="fs-5">Updater</strong> <strong class="fs-5">Updater</strong>
@ -49,10 +42,7 @@ const settings = useSettingsStore(pinia);
data-bs-target="#updaterHelpModal" data-bs-target="#updaterHelpModal"
class="btn m-0 p-0 border-0" class="btn m-0 p-0 border-0"
> >
<i <i class="bi bi-question-circle" style="font-size: 1rem"></i>
class="bi bi-question-circle"
style="font-size: 1rem"
></i>
</button> </button>
</div> </div>
</div> </div>
@ -64,7 +54,6 @@ const settings = useSettingsStore(pinia);
id="updater_channel" id="updater_channel"
type="button" type="button"
disabled disabled
> >
{{ settings.update_channel }} {{ settings.update_channel }}
</button> </button>

View file

@ -1,10 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import settings_gui from './settings_gui.vue' import settings_gui from "./settings_gui.vue";
import settings_chat from './settings_chat.vue' import settings_chat from "./settings_chat.vue";
import settings_hamlib from './settings_hamlib.vue' import settings_hamlib from "./settings_hamlib.vue";
import settings_tnc from './settings_tnc.vue' import settings_tnc from "./settings_tnc.vue";
import settings_web from './settings_web.vue' import settings_web from "./settings_web.vue";
import settings_exp from './settings_exp.vue' import settings_exp from "./settings_exp.vue";
</script> </script>
<template> <template>
<div <div

View file

@ -1,21 +1,19 @@
<script setup lang="ts"> <script setup lang="ts">
import { saveSettingsToFile } from "../js/settingsHandler";
import {saveSettingsToFile} from '../js/settingsHandler' import { setActivePinia } from "pinia";
import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
function saveSettings() { function saveSettings() {
saveSettingsToFile() saveSettingsToFile();
} }
</script> </script>
<template> <template>
<div class="input-group input-group-sm mb-1"> <div class="input-group input-group-sm mb-1">
<label class="input-group-text w-50">Enable "is typing"</label> <label class="input-group-text w-50">Enable "is typing"</label>
<label class="input-group-text w-50"> <label class="input-group-text w-50">
@ -24,7 +22,10 @@ function saveSettings(){
class="form-check-input" class="form-check-input"
type="checkbox" type="checkbox"
id="enable_is_writing" id="enable_is_writing"
@change="saveSettings" v-model="settings.enable_is_writing" true-value="True" false-value="False" @change="saveSettings"
v-model="settings.enable_is_writing"
true-value="True"
false-value="False"
/> />
<label class="form-check-label" for="GraphicsSwitch" <label class="form-check-label" for="GraphicsSwitch"
>Additional broadcast burst</label >Additional broadcast burst</label
@ -34,16 +35,17 @@ function saveSettings(){
</div> </div>
<div class="input-group input-group-sm mb-1"> <div class="input-group input-group-sm mb-1">
<label class="input-group-text w-50" <label class="input-group-text w-50">Allow requesting "user profile"</label>
>Allow requesting "user profile"</label
>
<label class="input-group-text w-50"> <label class="input-group-text w-50">
<div class="form-check form-switch form-check-inline"> <div class="form-check form-switch form-check-inline">
<input <input
class="form-check-input" class="form-check-input"
type="checkbox" type="checkbox"
id="enable_request_profile" id="enable_request_profile"
@change="saveSettings" v-model="settings.enable_request_profile" true-value="True" false-value="False" @change="saveSettings"
v-model="settings.enable_request_profile"
true-value="True"
false-value="False"
/> />
</div> </div>
</label> </label>
@ -59,7 +61,10 @@ function saveSettings(){
class="form-check-input" class="form-check-input"
type="checkbox" type="checkbox"
id="enable_request_shared_folder" id="enable_request_shared_folder"
@change="saveSettings" v-model="settings.enable_request_shared_folder" true-value="True" false-value="False" @change="saveSettings"
v-model="settings.enable_request_shared_folder"
true-value="True"
false-value="False"
/> />
</div> </div>
</label> </label>
@ -67,8 +72,13 @@ function saveSettings(){
<div class="input-group input-group-sm mb-1"> <div class="input-group input-group-sm mb-1">
<label class="input-group-text w-50">Shared folder path</label> <label class="input-group-text w-50">Shared folder path</label>
<input type="text" class="form-control w-50" id="shared_folder_path" @change="saveSettings" <input
v-model="settings.shared_folder_path" /> type="text"
class="form-control w-50"
id="shared_folder_path"
@change="saveSettings"
v-model="settings.shared_folder_path"
/>
</div> </div>
<div class="input-group input-group-sm mb-1"> <div class="input-group input-group-sm mb-1">
@ -82,7 +92,10 @@ function saveSettings(){
class="form-check-input" class="form-check-input"
type="checkbox" type="checkbox"
id="enable_auto_retry" id="enable_auto_retry"
@change="saveSettings" v-model="settings.enable_auto_retry" true-value="True" false-value="False" @change="saveSettings"
v-model="settings.enable_auto_retry"
true-value="True"
false-value="False"
/> />
</div> </div>
</label> </label>
@ -90,8 +103,12 @@ function saveSettings(){
<div class="input-group input-group-sm mb-1"> <div class="input-group input-group-sm mb-1">
<span class="input-group-text w-50">message retry attempts</span> <span class="input-group-text w-50">message retry attempts</span>
<select class="form-select form-select-sm w-50" id="max_retry_attempts" @change="saveSettings" <select
v-model="settings.max_retry_attempts"> class="form-select form-select-sm w-50"
id="max_retry_attempts"
@change="saveSettings"
v-model="settings.max_retry_attempts"
>
<option value="1">1</option> <option value="1">1</option>
<option value="2">2</option> <option value="2">2</option>
<option value="3">3</option> <option value="3">3</option>

View file

@ -1,27 +1,32 @@
<script setup lang="ts"> <script setup lang="ts">
import { saveSettingsToFile } from "../js/settingsHandler";
import {saveSettingsToFile} from '../js/settingsHandler' import { setActivePinia } from "pinia";
import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
function saveSettings() { function saveSettings() {
saveSettingsToFile() saveSettingsToFile();
} }
</script> </script>
<template> <template>
<div class="input-group input-group-sm mb-1"> <div class="input-group input-group-sm mb-1">
<label class="input-group-text w-50">Enable autotune</label> <label class="input-group-text w-50">Enable autotune</label>
<label class="input-group-text w-50"> <label class="input-group-text w-50">
<div class="form-check form-switch form-check-inline ms-2"> <div class="form-check form-switch form-check-inline ms-2">
<input class="form-check-input" type="checkbox" id="autoTuneSwitch" @change="saveSettings" v-model="settings.auto_tune" true-value="True" false-value="False" /> <input
class="form-check-input"
type="checkbox"
id="autoTuneSwitch"
@change="saveSettings"
v-model="settings.auto_tune"
true-value="True"
false-value="False"
/>
<label class="form-check-label" for="autoTuneSwitch" <label class="form-check-label" for="autoTuneSwitch"
>adjust ALC on TX</label >adjust ALC on TX</label
> >
@ -32,7 +37,15 @@ function saveSettings(){
<label class="input-group-text w-50">Enable FSK mode</label> <label class="input-group-text w-50">Enable FSK mode</label>
<label class="input-group-text w-50"> <label class="input-group-text w-50">
<div class="form-check form-switch form-check-inline ms-2"> <div class="form-check form-switch form-check-inline ms-2">
<input class="form-check-input" type="checkbox" id="fskModeSwitch" @change="saveSettings" v-model="settings.enable_fsk" true-value="True" false-value="False"/> <input
class="form-check-input"
type="checkbox"
id="fskModeSwitch"
@change="saveSettings"
v-model="settings.enable_fsk"
true-value="True"
false-value="False"
/>
<label class="form-check-label" for="fskModeSwitch" <label class="form-check-label" for="fskModeSwitch"
>not available, yet</label >not available, yet</label
> >
@ -48,7 +61,9 @@ function saveSettings(){
type="checkbox" type="checkbox"
id="enableMeshSwitch" id="enableMeshSwitch"
@change="saveSettings" @change="saveSettings"
v-model="settings.enable_mesh_features" true-value="True" false-value="False" v-model="settings.enable_mesh_features"
true-value="True"
false-value="False"
/> />
<label class="form-check-label" for="enableMeshSwitch" <label class="form-check-label" for="enableMeshSwitch"
>experimental! REALLY!</label >experimental! REALLY!</label
@ -63,7 +78,6 @@ function saveSettings(){
class="btn btn-outline-secondary btn-sm w-50" class="btn btn-outline-secondary btn-sm w-50"
id="btnCleanDB" id="btnCleanDB"
type="button" type="button"
> >
Clean</button Clean</button
>&nbsp; >&nbsp;

View file

@ -1,24 +1,18 @@
<script setup lang="ts"> <script setup lang="ts">
import { saveSettingsToFile } from "../js/settingsHandler";
import {saveSettingsToFile} from '../js/settingsHandler' import { setActivePinia } from "pinia";
import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
function saveSettings() { function saveSettings() {
saveSettingsToFile() saveSettingsToFile();
} }
</script> </script>
<template> <template>
<div class="input-group input-group-sm mb-1"> <div class="input-group input-group-sm mb-1">
<span class="input-group-text w-50">GUI theme</span> <span class="input-group-text w-50">GUI theme</span>
<select <select
@ -59,8 +53,12 @@ function saveSettings(){
</div> </div>
<div class="input-group input-group-sm mb-1"> <div class="input-group input-group-sm mb-1">
<span class="input-group-text w-50">Waterfall theme</span> <span class="input-group-text w-50">Waterfall theme</span>
<select class="form-select form-select-sm w-50" id="wftheme_selector" @change="saveSettings" <select
v-model="settings.wftheme"> class="form-select form-select-sm w-50"
id="wftheme_selector"
@change="saveSettings"
v-model="settings.wftheme"
>
<option value="2">Default</option> <option value="2">Default</option>
<option value="0">Turbo</option> <option value="0">Turbo</option>
<option value="1">Fosphor</option> <option value="1">Fosphor</option>
@ -74,7 +72,15 @@ function saveSettings(){
<label class="input-group-text w-50">Enable fancy GUI</label> <label class="input-group-text w-50">Enable fancy GUI</label>
<label class="input-group-text w-50"> <label class="input-group-text w-50">
<div class="form-check form-switch form-check-inline"> <div class="form-check form-switch form-check-inline">
<input class="form-check-input" type="checkbox" id="GraphicsSwitch" @change="saveSettings" v-model="settings.high_graphics" true-value="True" false-value="False"/> <input
class="form-check-input"
type="checkbox"
id="GraphicsSwitch"
@change="saveSettings"
v-model="settings.high_graphics"
true-value="True"
false-value="False"
/>
<label class="form-check-label" for="GraphicsSwitch" <label class="form-check-label" for="GraphicsSwitch"
>Higher CPU Usage</label >Higher CPU Usage</label
> >
@ -108,7 +114,10 @@ function saveSettings(){
class="form-check-input" class="form-check-input"
type="checkbox" type="checkbox"
id="NotificationSwitch" id="NotificationSwitch"
@change="saveSettings" v-model="settings.enable_sys_notification" true-value="True" false-value="False" @change="saveSettings"
v-model="settings.enable_sys_notification"
true-value="True"
false-value="False"
/> />
<label class="form-check-label" for="NotificationSwitch" <label class="form-check-label" for="NotificationSwitch"
>Show system pop-ups</label >Show system pop-ups</label
@ -124,7 +133,10 @@ function saveSettings(){
class="form-check-input" class="form-check-input"
type="checkbox" type="checkbox"
id="AutoStartSwitch" id="AutoStartSwitch"
@change="saveSettings" v-model="settings.auto_start" true-value="True" false-value="False" @change="saveSettings"
v-model="settings.auto_start"
true-value="True"
false-value="False"
/> />
<label class="form-check-label" for="AutoStartSwitch" <label class="form-check-label" for="AutoStartSwitch"
>Start on app launch</label >Start on app launch</label
@ -132,5 +144,4 @@ function saveSettings(){
</div> </div>
</label> </label>
</div> </div>
</template> </template>

View file

@ -1,21 +1,18 @@
<script setup lang="ts"> <script setup lang="ts">
import { saveSettingsToFile } from "../js/settingsHandler";
import {saveSettingsToFile} from '../js/settingsHandler' import { setActivePinia } from "pinia";
import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
function saveSettings() { function saveSettings() {
saveSettingsToFile() saveSettingsToFile();
} }
</script> </script>
<template> <template>
<hr class="m-2" /> <hr class="m-2" />
<div class="input-group input-group-sm mb-1"> <div class="input-group input-group-sm mb-1">
<span class="input-group-text" style="width: 180px">Rigctld path</span> <span class="input-group-text" style="width: 180px">Rigctld path</span>
@ -291,9 +288,7 @@ function saveSettings(){
<option value="24001">RFT EKD-500</option> <option value="24001">RFT EKD-500</option>
<option value="25001">Elektor Elektor 3/04</option> <option value="25001">Elektor Elektor 3/04</option>
<option value="25002">SAT-Schneider DRT1</option> <option value="25002">SAT-Schneider DRT1</option>
<option value="25003"> <option value="25003">Coding Technologies Digital World Traveller</option>
Coding Technologies Digital World Traveller
</option>
<option value="25006">AmQRP DDS-60</option> <option value="25006">AmQRP DDS-60</option>
<option value="25007">Elektor Elektor SDR-USB</option> <option value="25007">Elektor Elektor SDR-USB</option>
<option value="25008">mRS miniVNA</option> <option value="25008">mRS miniVNA</option>
@ -394,9 +389,7 @@ function saveSettings(){
</select> </select>
</div> </div>
<div class="input-group input-group-sm mb-1"> <div class="input-group input-group-sm mb-1">
<span class="input-group-text" style="width: 180px" <span class="input-group-text" style="width: 180px">Serial handshake</span>
>Serial handshake</span
>
<select <select
class="form-select form-select-sm" class="form-select form-select-sm"
@ -489,7 +482,6 @@ function saveSettings(){
aria-describedby="basic-addon1" aria-describedby="basic-addon1"
disabled disabled
placeholder="auto populated from above settings" placeholder="auto populated from above settings"
/> />
<button <button
class="btn btn-outline-secondary" class="btn btn-outline-secondary"

View file

@ -1,27 +1,21 @@
<script setup lang="ts"> <script setup lang="ts">
import { saveSettingsToFile } from "../js/settingsHandler";
import {saveSettingsToFile} from '../js/settingsHandler' import { setActivePinia } from "pinia";
import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
function saveSettings() { function saveSettings() {
saveSettingsToFile() saveSettingsToFile();
} }
</script> </script>
<template> <template>
<div class="input-group input-group-sm mb-1"> <div class="input-group input-group-sm mb-1">
<span class="input-group-text" style="width: 180px" <span class="input-group-text" style="width: 180px">TNC port</span>
>TNC port</span
>
<input <input
type="text" type="text"
class="form-control" class="form-control"
@ -36,9 +30,7 @@ function saveSettings(){
</div> </div>
<div class="input-group input-group-sm mb-1"> <div class="input-group input-group-sm mb-1">
<span class="input-group-text" style="width: 180px" <span class="input-group-text" style="width: 180px">TNC host</span>
>TNC host</span
>
<input <input
type="text" type="text"
class="form-control" class="form-control"
@ -49,11 +41,14 @@ function saveSettings(){
/> />
</div> </div>
<div class="input-group input-group-sm mb-1"> <div class="input-group input-group-sm mb-1">
<label class="input-group-text w-50">TX delay in ms</label> <label class="input-group-text w-50">TX delay in ms</label>
<select class="form-select form-select-sm" id="tx_delay" @change="saveSettings" <select
v-model="settings.tx_delay"> class="form-select form-select-sm"
id="tx_delay"
@change="saveSettings"
v-model="settings.tx_delay"
>
<option value="0">0</option> <option value="0">0</option>
<option value="50">50</option> <option value="50">50</option>
<option value="100">100</option> <option value="100">100</option>
@ -81,8 +76,12 @@ function saveSettings(){
<div class="input-group input-group-sm mb-1"> <div class="input-group input-group-sm mb-1">
<label class="input-group-text w-25">Tuning range</label> <label class="input-group-text w-25">Tuning range</label>
<label class="input-group-text">fmin</label> <label class="input-group-text">fmin</label>
<select class="form-select form-select-sm" id="tuning_range_fmin" @change="saveSettings" <select
v-model="settings.tuning_range_fmin"> class="form-select form-select-sm"
id="tuning_range_fmin"
@change="saveSettings"
v-model="settings.tuning_range_fmin"
>
<option value="-50.0">-50.0</option> <option value="-50.0">-50.0</option>
<option value="-100.0">-100.0</option> <option value="-100.0">-100.0</option>
<option value="-150.0">-150.0</option> <option value="-150.0">-150.0</option>
@ -90,8 +89,12 @@ function saveSettings(){
<option value="-250.0">-250.0</option> <option value="-250.0">-250.0</option>
</select> </select>
<label class="input-group-text">fmax</label> <label class="input-group-text">fmax</label>
<select class="form-select form-select-sm" id="tuning_range_fmax" @change="saveSettings" <select
v-model="settings.tuning_range_fmax"> class="form-select form-select-sm"
id="tuning_range_fmax"
@change="saveSettings"
v-model="settings.tuning_range_fmax"
>
<option value="50.0">50.0</option> <option value="50.0">50.0</option>
<option value="100.0">100.0</option> <option value="100.0">100.0</option>
<option value="150.0">150.0</option> <option value="150.0">150.0</option>
@ -123,7 +126,15 @@ function saveSettings(){
<label class="input-group-text w-50">Enable waterfall data</label> <label class="input-group-text w-50">Enable waterfall data</label>
<label class="input-group-text w-50"> <label class="input-group-text w-50">
<div class="form-check form-switch form-check-inline"> <div class="form-check form-switch form-check-inline">
<input class="form-check-input" type="checkbox" id="fftSwitch" @change="saveSettings" v-model="settings.enable_fft" true-value="True" false-value="False"/> <input
class="form-check-input"
type="checkbox"
id="fftSwitch"
@change="saveSettings"
v-model="settings.enable_fft"
true-value="True"
false-value="False"
/>
<label class="form-check-label" for="fftSwitch">Waterfall</label> <label class="form-check-label" for="fftSwitch">Waterfall</label>
</div> </div>
</label> </label>
@ -132,7 +143,15 @@ function saveSettings(){
<label class="input-group-text w-50">Enable scatter diagram data</label> <label class="input-group-text w-50">Enable scatter diagram data</label>
<label class="input-group-text w-50"> <label class="input-group-text w-50">
<div class="form-check form-switch form-check-inline"> <div class="form-check form-switch form-check-inline">
<input class="form-check-input" type="checkbox" id="scatterSwitch" @change="saveSettings" v-model="settings.enable_scatter" true-value="True" false-value="False"/> <input
class="form-check-input"
type="checkbox"
id="scatterSwitch"
@change="saveSettings"
v-model="settings.enable_scatter"
true-value="True"
false-value="False"
/>
<label class="form-check-label" for="scatterSwitch">Scatter</label> <label class="form-check-label" for="scatterSwitch">Scatter</label>
</div> </div>
</label> </label>
@ -145,7 +164,10 @@ function saveSettings(){
class="form-check-input" class="form-check-input"
type="checkbox" type="checkbox"
id="250HzModeSwitch" id="250HzModeSwitch"
v-model="settings.low_bandwidth_mode" true-value="True" false-value="False" @change="saveSettings" v-model="settings.low_bandwidth_mode"
true-value="True"
false-value="False"
@change="saveSettings"
/> />
<label class="form-check-label" for="250HzModeSwitch">250Hz</label> <label class="form-check-label" for="250HzModeSwitch">250Hz</label>
</div> </div>
@ -159,7 +181,10 @@ function saveSettings(){
class="form-check-input" class="form-check-input"
type="checkbox" type="checkbox"
id="respondCQSwitch" id="respondCQSwitch"
v-model="settings.respond_to_cq" true-value="True" false-value="False" @change="saveSettings" v-model="settings.respond_to_cq"
true-value="True"
false-value="False"
@change="saveSettings"
/> />
<label class="form-check-label" for="respondCQSwitch">QRV</label> <label class="form-check-label" for="respondCQSwitch">QRV</label>
</div> </div>
@ -168,8 +193,12 @@ function saveSettings(){
<div class="input-group input-group-sm mb-1"> <div class="input-group input-group-sm mb-1">
<label class="input-group-text w-50">RX buffer size</label> <label class="input-group-text w-50">RX buffer size</label>
<label class="input-group-text w-50"> <label class="input-group-text w-50">
<select class="form-select form-select-sm" id="rx_buffer_size" @change="saveSettings" <select
v-model="settings.rx_buffer_size"> class="form-select form-select-sm"
id="rx_buffer_size"
@change="saveSettings"
v-model="settings.rx_buffer_size"
>
<option value="1">1</option> <option value="1">1</option>
<option value="2">2</option> <option value="2">2</option>
<option value="4">4</option> <option value="4">4</option>

View file

@ -1,26 +1,30 @@
<script setup lang="ts"> <script setup lang="ts">
import { setActivePinia } from "pinia";
import pinia from "../store/index";
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia); setActivePinia(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
function saveSettings() { function saveSettings() {
saveSettingsToFile() saveSettingsToFile();
} }
</script> </script>
<template> <template>
<div class="input-group input-group-sm mb-1"> <div class="input-group input-group-sm mb-1">
<label class="input-group-text w-50">Explorer publishing</label> <label class="input-group-text w-50">Explorer publishing</label>
<label class="input-group-text w-50"> <label class="input-group-text w-50">
<div class="form-check form-switch form-check-inline"> <div class="form-check form-switch form-check-inline">
<input class="form-check-input" type="checkbox" id="ExplorerSwitch" @change="saveSettings" v-model="settings.enable_explorer" true-value="True" false-value="False"/> <input
class="form-check-input"
type="checkbox"
id="ExplorerSwitch"
@change="saveSettings"
v-model="settings.enable_explorer"
true-value="True"
false-value="False"
/>
<label class="form-check-label" for="ExplorerSwitch">Publish</label> <label class="form-check-label" for="ExplorerSwitch">Publish</label>
</div> </div>
</label> </label>
@ -33,7 +37,10 @@ function saveSettings(){
class="form-check-input" class="form-check-input"
type="checkbox" type="checkbox"
id="ExplorerStatsSwitch" id="ExplorerStatsSwitch"
@change="saveSettings" v-model="settings.enable_stats" true-value="True" false-value="False" @change="saveSettings"
v-model="settings.enable_stats"
true-value="True"
false-value="False"
/> />
<label class="form-check-label" for="ExplorerStatsSwitch" <label class="form-check-label" for="ExplorerStatsSwitch"
>Publish stats</label >Publish stats</label

View file

@ -3,24 +3,21 @@ const fs = require("fs");
const { v4: uuidv4 } = require("uuid"); const { v4: uuidv4 } = require("uuid");
// pinia store setup // pinia store setup
import { setActivePinia } from 'pinia'; import { setActivePinia } from "pinia";
import pinia from '../store/index'; import pinia from "../store/index";
setActivePinia(pinia); setActivePinia(pinia);
import { useChatStore } from '../store/chatStore.js'; import { useChatStore } from "../store/chatStore.js";
const chat = useChatStore(pinia); const chat = useChatStore(pinia);
import { sendMessage } from './sock.js'; import { sendMessage } from "./sock.js";
const FD = require("./src/js/freedata.js"); const FD = require("./src/js/freedata.js");
// split character // split character
const split_char = "0;1;"; const split_char = "0;1;";
// ---- MessageDB // ---- MessageDB
try { try {
var PouchDB = require("pouchdb"); var PouchDB = require("pouchdb");
@ -35,13 +32,10 @@ try {
var PouchDB = require("pouchdb-browser"); var PouchDB = require("pouchdb-browser");
} }
PouchDB.plugin(require("pouchdb-find")); PouchDB.plugin(require("pouchdb-find"));
//PouchDB.plugin(require('pouchdb-replication')); //PouchDB.plugin(require('pouchdb-replication'));
PouchDB.plugin(require("pouchdb-upsert")); PouchDB.plugin(require("pouchdb-upsert"));
// https://stackoverflow.com/a/26227660 // https://stackoverflow.com/a/26227660
var appDataFolder = var appDataFolder =
process.env.APPDATA || process.env.APPDATA ||
@ -50,9 +44,6 @@ var appDataFolder =
: process.env.HOME + "/.config"); : process.env.HOME + "/.config");
var configFolder = path.join(appDataFolder, "FreeDATA"); var configFolder = path.join(appDataFolder, "FreeDATA");
var chatDB = path.join(configFolder, "chatDB"); var chatDB = path.join(configFolder, "chatDB");
var db = new PouchDB(chatDB); var db = new PouchDB(chatDB);
@ -60,29 +51,28 @@ var db = new PouchDB(chatDB);
createChatIndex(); createChatIndex();
// create callsign set for storing unique callsigns // create callsign set for storing unique callsigns
chat.callsign_list = new Set() chat.callsign_list = new Set();
// function for creating a new broadcast // function for creating a new broadcast
export function newBroadcast(broadcastChannel, chatmessage) { export function newBroadcast(broadcastChannel, chatmessage) {
var mode = "";
var mode = '' var frames = "";
var frames = '' var data = "";
var data = ''
if (typeof chatFile !== "undefined") { if (typeof chatFile !== "undefined") {
var file = chatFile; var file = chatFile;
var filetype = chatFileType var filetype = chatFileType;
var filename = chatFileName var filename = chatFileName;
} else { } else {
var file = ''; var file = "";
var filetype = 'text' var filetype = "text";
var filename = '' var filename = "";
} }
var file_checksum = ''//crc32(file).toString(16).toUpperCase(); var file_checksum = ""; //crc32(file).toString(16).toUpperCase();
var checksum = '' var checksum = "";
var message_type = 'broadcast_transmit' var message_type = "broadcast_transmit";
var command = '' var command = "";
var timestamp = Math.floor(Date.now() / 1000) var timestamp = Math.floor(Date.now() / 1000);
var uuid = uuidv4(); var uuid = uuidv4();
// TODO: Not sure what this uuid part is needed for ... // TODO: Not sure what this uuid part is needed for ...
let uuidlast = uuid.lastIndexOf("-"); let uuidlast = uuid.lastIndexOf("-");
@ -106,62 +96,62 @@ export function newBroadcast(broadcastChannel, chatmessage){
var tnc_command = "broadcast"; var tnc_command = "broadcast";
sendMessage( sendMessage(dxcallsign, data_with_attachment, checksum, uuid, tnc_command);
dxcallsign,
data_with_attachment,
checksum,
uuid,
tnc_command
)
let newChatObj = new Object(); let newChatObj = new Object();
newChatObj.command = "msg" newChatObj.command = "msg";
newChatObj.hmac_signed = false newChatObj.hmac_signed = false;
newChatObj.percent = 0 newChatObj.percent = 0;
newChatObj.bytesperminute newChatObj.bytesperminute;
newChatObj.is_new = false newChatObj.is_new = false;
newChatObj._id = uuid newChatObj._id = uuid;
newChatObj.timestamp = timestamp newChatObj.timestamp = timestamp;
newChatObj.dxcallsign = dxcallsign newChatObj.dxcallsign = dxcallsign;
newChatObj.dxgrid = "null" newChatObj.dxgrid = "null";
newChatObj.msg = chatmessage newChatObj.msg = chatmessage;
newChatObj.checksum = file_checksum newChatObj.checksum = file_checksum;
newChatObj.type = message_type newChatObj.type = message_type;
newChatObj.status = "transmitting" newChatObj.status = "transmitting";
newChatObj.attempt = 1 newChatObj.attempt = 1;
newChatObj.uuid = uuid newChatObj.uuid = uuid;
newChatObj._attachments = { newChatObj._attachments = {
[filename]: { [filename]: {
content_type: filetype, content_type: filetype,
data: FD.btoa_FD(file), data: FD.btoa_FD(file),
}, },
} };
addObjToDatabase(newChatObj)
addObjToDatabase(newChatObj);
} }
// function for creating a new message // function for creating a new message
export function newMessage(dxcallsign, chatmessage, chatFile, chatFileName, chatFileSize, chatFileType){ export function newMessage(
var mode = '' dxcallsign,
var frames = '' chatmessage,
var data = '' chatFile,
chatFileName,
chatFileSize,
chatFileType,
) {
var mode = "";
var frames = "";
var data = "";
if (typeof chatFile !== "undefined") { if (typeof chatFile !== "undefined") {
var file = chatFile; var file = chatFile;
var filetype = chatFileType var filetype = chatFileType;
var filename = chatFileName var filename = chatFileName;
} else { } else {
var file = ''; var file = "";
var filetype = 'text' var filetype = "text";
var filename = '' var filename = "";
} }
var file_checksum = ''//crc32(file).toString(16).toUpperCase(); var file_checksum = ""; //crc32(file).toString(16).toUpperCase();
var checksum = '' var checksum = "";
var message_type = 'transmit' var message_type = "transmit";
var command = '' var command = "";
var timestamp = Math.floor(Date.now() / 1000) var timestamp = Math.floor(Date.now() / 1000);
var uuid = uuidv4(); var uuid = uuidv4();
// TODO: Not sure what this uuid part is needed for ... // TODO: Not sure what this uuid part is needed for ...
let uuidlast = uuid.lastIndexOf("-"); let uuidlast = uuid.lastIndexOf("-");
@ -172,9 +162,6 @@ export function newMessage(dxcallsign, chatmessage, chatFile, chatFileName, chat
// slice uuid for reducing overhead // slice uuid for reducing overhead
uuid = uuid.slice(-8); uuid = uuid.slice(-8);
var data_with_attachment = var data_with_attachment =
timestamp + timestamp +
split_char + split_char +
@ -188,52 +175,42 @@ export function newMessage(dxcallsign, chatmessage, chatFile, chatFileName, chat
var tnc_command = "msg"; var tnc_command = "msg";
sendMessage( sendMessage(dxcallsign, data_with_attachment, checksum, uuid, tnc_command);
dxcallsign,
data_with_attachment,
checksum,
uuid,
tnc_command
)
let newChatObj = new Object(); let newChatObj = new Object();
newChatObj.command = "msg" newChatObj.command = "msg";
newChatObj.hmac_signed = false newChatObj.hmac_signed = false;
newChatObj.percent = 0 newChatObj.percent = 0;
newChatObj.bytesperminute newChatObj.bytesperminute;
newChatObj.is_new = false newChatObj.is_new = false;
newChatObj._id = uuid newChatObj._id = uuid;
newChatObj.timestamp = timestamp newChatObj.timestamp = timestamp;
newChatObj.dxcallsign = dxcallsign newChatObj.dxcallsign = dxcallsign;
newChatObj.dxgrid = "null" newChatObj.dxgrid = "null";
newChatObj.msg = chatmessage newChatObj.msg = chatmessage;
newChatObj.checksum = file_checksum newChatObj.checksum = file_checksum;
newChatObj.type = message_type newChatObj.type = message_type;
newChatObj.status = "transmitting" newChatObj.status = "transmitting";
newChatObj.attempt = 1 newChatObj.attempt = 1;
newChatObj.uuid = uuid newChatObj.uuid = uuid;
newChatObj._attachments = { newChatObj._attachments = {
[filename]: { [filename]: {
content_type: filetype, content_type: filetype,
data: FD.btoa_FD(file), data: FD.btoa_FD(file),
}, },
};
addObjToDatabase(newChatObj);
} }
addObjToDatabase(newChatObj)
}
// function for creating a list, accessible by callsign // function for creating a list, accessible by callsign
function sortChatList() { function sortChatList() {
// Create an empty object to store the reordered data dynamically // Create an empty object to store the reordered data dynamically
var reorderedData = {}; var reorderedData = {};
var jsonObjects = chat.unsorted_chat_list var jsonObjects = chat.unsorted_chat_list;
// Iterate through the list of JSON objects and reorder them dynamically // Iterate through the list of JSON objects and reorder them dynamically
jsonObjects.forEach(obj => { jsonObjects.forEach((obj) => {
var dxcallsign = obj.dxcallsign; var dxcallsign = obj.dxcallsign;
if (dxcallsign) { if (dxcallsign) {
if (!reorderedData[dxcallsign]) { if (!reorderedData[dxcallsign]) {
@ -243,87 +220,78 @@ function sortChatList(){
} }
}); });
//console.log(reorderedData["DJ2LS-0"]) //console.log(reorderedData["DJ2LS-0"])
return reorderedData return reorderedData;
} }
//repeat a message //repeat a message
export function repeatMessageTransmission(id) { export function repeatMessageTransmission(id) {
console.log(id) console.log(id);
} }
// delete a message from databse and gui // delete a message from databse and gui
export function deleteMessageFromDB(id) { export function deleteMessageFromDB(id) {
console.log("deleting: " + id) console.log("deleting: " + id);
db.get(id).then(function (doc) { db.get(id).then(function (doc) {
db.remove(doc) db.remove(doc);
}) });
// overwrote unsorted chat list by filtering if not ID // overwrote unsorted chat list by filtering if not ID
chat.unsorted_chat_list = chat.unsorted_chat_list.filter(entry => entry.uuid !== id); chat.unsorted_chat_list = chat.unsorted_chat_list.filter(
(entry) => entry.uuid !== id,
);
// and finally generate our sorted chat list, which is the key store for chat gui rendering // and finally generate our sorted chat list, which is the key store for chat gui rendering
// the removed entry should be removed now from gui // the removed entry should be removed now from gui
chat.sorted_chat_list = sortChatList() chat.sorted_chat_list = sortChatList();
} }
// function to update transmission status // function to update transmission status
export function updateTransmissionStatus(obj) { export function updateTransmissionStatus(obj) {
// update database entries // update database entries
databaseUpsert(obj.uuid, "percent", obj.percent) databaseUpsert(obj.uuid, "percent", obj.percent);
databaseUpsert(obj.uuid, "bytesperminute", obj.bytesperminute) databaseUpsert(obj.uuid, "bytesperminute", obj.bytesperminute);
databaseUpsert(obj.uuid, "status", obj.status) databaseUpsert(obj.uuid, "status", obj.status);
// update screen rendering / messages // update screen rendering / messages
updateUnsortedChatListEntry(obj.uuid, "percent", obj.percent) updateUnsortedChatListEntry(obj.uuid, "percent", obj.percent);
updateUnsortedChatListEntry(obj.uuid, "bytesperminute", obj.bytesperminute) updateUnsortedChatListEntry(obj.uuid, "bytesperminute", obj.bytesperminute);
updateUnsortedChatListEntry(obj.uuid, "status", obj.status) updateUnsortedChatListEntry(obj.uuid, "status", obj.status);
} }
export function updateUnsortedChatListEntry(uuid, object, value) { export function updateUnsortedChatListEntry(uuid, object, value) {
for (const entry of chat.unsorted_chat_list) { for (const entry of chat.unsorted_chat_list) {
if (entry.uuid === uuid) { if (entry.uuid === uuid) {
entry[object] = value entry[object] = value;
console.log("Entry updated:", entry[object]) console.log("Entry updated:", entry[object]);
chat.sorted_chat_list = sortChatList() chat.sorted_chat_list = sortChatList();
return entry return entry;
} }
} }
console.log("Entry not updated:", object) console.log("Entry not updated:", object);
return null; // Return null if not found return null; // Return null if not found
} }
export function databaseUpsert(id, object, value) { export function databaseUpsert(id, object, value) {
db.upsert(id, function (doc) { db.upsert(id, function (doc) {
if (!doc[object]) { if (!doc[object]) {
doc[object] = value; doc[object] = value;
} }
doc[object] = value; doc[object] = value;
return doc; return doc;
}).then(function (res) { })
.then(function (res) {
// success, res is {rev: '1-xxx', updated: true, id: 'myDocId'} // success, res is {rev: '1-xxx', updated: true, id: 'myDocId'}
console.log(res) console.log(res);
}).catch(function (err) { })
.catch(function (err) {
// error // error
console.log(err) console.log(err);
}); });
} }
// function for fetching all messages from chat / updating chat // function for fetching all messages from chat / updating chat
export async function updateAllChat() { export async function updateAllChat() {
//Ensure we create an index before running db.find //Ensure we create an index before running db.find
//We can't rely on the default index existing before we get here...... :'( //We can't rely on the default index existing before we get here...... :'(
await db await db
@ -348,15 +316,14 @@ export async function updateAllChat() {
}) })
.then(async function (result) { .then(async function (result) {
for (var item of result.docs) { for (var item of result.docs) {
if(item.type === 'beacon'){ if (item.type === "beacon") {
console.log(item);
console.log(item)
// TODO: sort beacon list .... maybe a part for a separate function // TODO: sort beacon list .... maybe a part for a separate function
const jsonData = [item] const jsonData = [item];
const dxcallsign = obj.dxcallsign const dxcallsign = obj.dxcallsign;
// Process each JSON item step by step // Process each JSON item step by step
jsonData.forEach(jsonitem => { jsonData.forEach((jsonitem) => {
const { snr, timestamp } = item; const { snr, timestamp } = item;
// Check if dxcallsign already exists as a property in the result object // Check if dxcallsign already exists as a property in the result object
@ -372,25 +339,14 @@ export async function updateAllChat() {
// Push the snr value to the corresponding dxcallsign's snr array // Push the snr value to the corresponding dxcallsign's snr array
chat.sorted_beacon_list[dxcallsign].snr.push(snr); chat.sorted_beacon_list[dxcallsign].snr.push(snr);
chat.sorted_beacon_list[dxcallsign].timestamp.push(timestamp); chat.sorted_beacon_list[dxcallsign].timestamp.push(timestamp);
}); });
} else { } else {
chat.callsign_list.add(item.dxcallsign) chat.callsign_list.add(item.dxcallsign);
chat.unsorted_chat_list.push(item) chat.unsorted_chat_list.push(item);
} }
} }
chat.sorted_chat_list = sortChatList() chat.sorted_chat_list = sortChatList();
/* /*
if (typeof result !== "undefined") { if (typeof result !== "undefined") {
@ -406,8 +362,6 @@ export async function updateAllChat() {
} }
} }
*/ */
}) })
.catch(function (err) { .catch(function (err) {
console.log(err); console.log(err);
@ -416,11 +370,10 @@ export async function updateAllChat() {
.catch(function (err) { .catch(function (err) {
console.log(err); console.log(err);
}); });
} }
function addObjToDatabase(newobj) { function addObjToDatabase(newobj) {
console.log(newobj) console.log(newobj);
/* /*
db.upsert(newobj._id, function (doc) { db.upsert(newobj._id, function (doc) {
if (!doc._id) { if (!doc._id) {
@ -440,11 +393,10 @@ function addObjToDatabase(newobj){
console.log(err); console.log(err);
}); });
console.log(newobj);
console.log(newobj) if (newobj.command === "msg") {
if(newobj.command === 'msg'){ chat.unsorted_chat_list.push(newobj);
chat.unsorted_chat_list.push(newobj) chat.sorted_chat_list = sortChatList();
chat.sorted_chat_list = sortChatList()
} }
/* /*
@ -456,8 +408,6 @@ function addObjToDatabase(newobj){
*/ */
} }
function createChatIndex() { function createChatIndex() {
db.createIndex({ db.createIndex({
index: { index: {
@ -489,15 +439,12 @@ function createChatIndex() {
}); });
} }
export function deleteChatByCallsign(callsign) { export function deleteChatByCallsign(callsign) {
chat.callsign_list.delete(callsign) chat.callsign_list.delete(callsign);
delete chat.unsorted_chat_list.callsign delete chat.unsorted_chat_list.callsign;
delete chat.sorted_chat_list.callsign delete chat.sorted_chat_list.callsign;
deleteFromDatabaseByCallsign(callsign)
deleteFromDatabaseByCallsign(callsign);
} }
function deleteFromDatabaseByCallsign(callsign) { function deleteFromDatabaseByCallsign(callsign) {
@ -533,7 +480,6 @@ db.find({
}); });
} }
// function for handling a received beacon // function for handling a received beacon
export function newBeaconReceived(obj) { export function newBeaconReceived(obj) {
/* /*
@ -550,25 +496,24 @@ export function newBeaconReceived(obj){
*/ */
let newChatObj = new Object(); let newChatObj = new Object();
newChatObj.command = "beacon" newChatObj.command = "beacon";
newChatObj._id = obj['uuid'] newChatObj._id = obj["uuid"];
newChatObj.uuid = obj['uuid'] newChatObj.uuid = obj["uuid"];
newChatObj.timestamp = obj['timestamp'] newChatObj.timestamp = obj["timestamp"];
newChatObj.dxcallsign = obj["dxcallsign"] newChatObj.dxcallsign = obj["dxcallsign"];
newChatObj.dxgrid = obj["dxgrid"] newChatObj.dxgrid = obj["dxgrid"];
newChatObj.type = 'beacon' newChatObj.type = "beacon";
newChatObj.status = obj["beacon"] newChatObj.status = obj["beacon"];
newChatObj.snr = obj["snr"] newChatObj.snr = obj["snr"];
addObjToDatabase(newChatObj);
addObjToDatabase(newChatObj) console.log(obj);
console.log(obj) const jsonData = [obj];
const dxcallsign = obj.dxcallsign;
const jsonData = [obj]
const dxcallsign = obj.dxcallsign
// Process each JSON item step by step // Process each JSON item step by step
jsonData.forEach(item => { jsonData.forEach((item) => {
const { snr, timestamp } = obj; const { snr, timestamp } = obj;
// Check if dxcallsign already exists as a property in the result object // Check if dxcallsign already exists as a property in the result object
@ -584,11 +529,7 @@ jsonData.forEach(item => {
// Push the snr value to the corresponding dxcallsign's snr array // Push the snr value to the corresponding dxcallsign's snr array
chat.sorted_beacon_list[dxcallsign].snr.push(snr); chat.sorted_beacon_list[dxcallsign].snr.push(snr);
chat.sorted_beacon_list[dxcallsign].timestamp.push(timestamp); chat.sorted_beacon_list[dxcallsign].timestamp.push(timestamp);
}); });
} }
// function for handling a received message // function for handling a received message
@ -629,56 +570,53 @@ export function newMessageReceived(message, protocol){
*/ */
console.log(protocol) console.log(protocol);
let newChatObj = new Object(); let newChatObj = new Object();
newChatObj.command = "msg" newChatObj.command = "msg";
newChatObj.hmac_signed = protocol["hmac_signed"] newChatObj.hmac_signed = protocol["hmac_signed"];
newChatObj.percent = 100 newChatObj.percent = 100;
newChatObj.bytesperminute = protocol["bytesperminute"] newChatObj.bytesperminute = protocol["bytesperminute"];
newChatObj.is_new = true newChatObj.is_new = true;
newChatObj._id = message[3] newChatObj._id = message[3];
newChatObj.timestamp = message[4] newChatObj.timestamp = message[4];
newChatObj.dxcallsign = protocol["dxcallsign"] newChatObj.dxcallsign = protocol["dxcallsign"];
newChatObj.dxgrid = protocol["dxgrid"] newChatObj.dxgrid = protocol["dxgrid"];
newChatObj.msg = message[5] newChatObj.msg = message[5];
newChatObj.checksum = message[2] newChatObj.checksum = message[2];
newChatObj.type = message[1] newChatObj.type = message[1];
newChatObj.status = protocol["status"] newChatObj.status = protocol["status"];
newChatObj.attempt = 1 newChatObj.attempt = 1;
newChatObj.uuid = message[3] newChatObj.uuid = message[3];
newChatObj._attachments = { newChatObj._attachments = {
[message[6]]: { [message[6]]: {
content_type: message[7], content_type: message[7],
data: FD.btoa_FD(message[8]), data: FD.btoa_FD(message[8]),
}, },
} };
// some tweaks for broadcasts // some tweaks for broadcasts
if (protocol.fec == "broadcast") { if (protocol.fec == "broadcast") {
newChatObj.broadcast_sender = protocol["dxcallsign"] newChatObj.broadcast_sender = protocol["dxcallsign"];
newChatObj.type = 'broadcast_received' newChatObj.type = "broadcast_received";
} }
addObjToDatabase(newChatObj) addObjToDatabase(newChatObj);
} }
export function setStateFailed() { export function setStateFailed() {
state.arq_seconds_until_finish = 0 state.arq_seconds_until_finish = 0;
state.arq_seconds_until_timeout = 180 state.arq_seconds_until_timeout = 180;
state.arq_seconds_until_timeout_percent = 100 state.arq_seconds_until_timeout_percent = 100;
} }
export function setStateSuccess() { export function setStateSuccess() {
state.arq_seconds_until_finish = 0 state.arq_seconds_until_finish = 0;
state.arq_seconds_until_timeout = 180 state.arq_seconds_until_timeout = 180;
state.arq_seconds_until_timeout_percent = 100 state.arq_seconds_until_timeout_percent = 100;
} }
// CRC CHECKSUMS // CRC CHECKSUMS
// https://stackoverflow.com/a/50579690 // https://stackoverflow.com/a/50579690
// crc32 calculation // crc32 calculation
@ -709,7 +647,3 @@ var crc32 = function (str) {
return (crc ^ -1) >>> 0; return (crc ^ -1) >>> 0;
}; };

View file

@ -1,19 +1,19 @@
//var net = require("net"); //var net = require("net");
var net = require('node:net'); var net = require("node:net");
const path = require("path"); const path = require("path");
const { ipcRenderer } = require("electron"); const { ipcRenderer } = require("electron");
// ----------------- init pinia stores ------------- // ----------------- init pinia stores -------------
import { setActivePinia } from 'pinia'; import { setActivePinia } from "pinia";
import pinia from '../store/index'; import pinia from "../store/index";
setActivePinia(pinia); setActivePinia(pinia);
import { useAudioStore } from '../store/audioStore.js'; import { useAudioStore } from "../store/audioStore.js";
const audioStore = useAudioStore(pinia); const audioStore = useAudioStore(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
import { useStateStore } from '../store/stateStore.js'; import { useStateStore } from "../store/stateStore.js";
const state = useStateStore(pinia); const state = useStateStore(pinia);
var daemon = new net.Socket(); var daemon = new net.Socket();
@ -22,7 +22,6 @@ var socketchunk = ""; // Current message, per connection.
// global to keep track of daemon connection error emissions // global to keep track of daemon connection error emissions
var daemonShowConnectStateError = 1; var daemonShowConnectStateError = 1;
setTimeout(connectDAEMON, 500); setTimeout(connectDAEMON, 500);
function connectDAEMON() { function connectDAEMON() {
@ -33,7 +32,6 @@ function connectDAEMON() {
//clear message buffer after reconnecting or initial connection //clear message buffer after reconnecting or initial connection
socketchunk = ""; socketchunk = "";
daemon.connect(settings.daemon_port, settings.daemon_host); daemon.connect(settings.daemon_port, settings.daemon_host);
//client.setTimeout(5000); //client.setTimeout(5000);
@ -89,7 +87,6 @@ daemon.on("end", function (data) {
//exports.writeDaemonCommand = function(command){ //exports.writeDaemonCommand = function(command){
//writeDaemonCommand = function (command) { //writeDaemonCommand = function (command) {
function writeDaemonCommand(command) { function writeDaemonCommand(command) {
// we use the writingCommand function to update our TCPIP state because we are calling this function a lot // we use the writingCommand function to update our TCPIP state because we are calling this function a lot
// if socket opened, we are able to run commands // if socket opened, we are able to run commands
if (daemon.readyState == "open") { if (daemon.readyState == "open") {
@ -109,7 +106,7 @@ function writeDaemonCommand(command) {
daemon_connection: daemon.readyState, daemon_connection: daemon.readyState,
}; };
ipcRenderer.send("request-update-daemon-connection", Data); ipcRenderer.send("request-update-daemon-connection", Data);
}; }
// "https://stackoverflow.com/questions/9070700/nodejs-net-createserver-large-amount-of-data-coming-in" // "https://stackoverflow.com/questions/9070700/nodejs-net-createserver-large-amount-of-data-coming-in"
@ -168,8 +165,6 @@ daemon.on("data", function (socketdata) {
audioStore.inputDevices = data["input_devices"]; audioStore.inputDevices = data["input_devices"];
audioStore.outputDevices = data["output_devices"]; audioStore.outputDevices = data["output_devices"];
state.tnc_running_state = data["daemon_state"][0]["status"]; state.tnc_running_state = data["daemon_state"][0]["status"];
} }
if (data["command"] == "test_hamlib") { if (data["command"] == "test_hamlib") {
@ -193,11 +188,10 @@ function hexToBytes(hex) {
//exports.getDaemonState = function () { //exports.getDaemonState = function () {
function getDaemonState() { function getDaemonState() {
//function getDaemonState(){ //function getDaemonState(){
command = '{"type" : "get", "command" : "daemon_state"}'; command = '{"type" : "get", "command" : "daemon_state"}';
writeDaemonCommand(command); writeDaemonCommand(command);
}; }
// START TNC // START TNC
// ` `== multi line string // ` `== multi line string
@ -244,19 +238,17 @@ export function startTNC() {
console.log(json_command); console.log(json_command);
writeDaemonCommand(json_command); writeDaemonCommand(json_command);
}; }
// STOP TNC // STOP TNC
//exports.stopTNC = function () { //exports.stopTNC = function () {
export function stopTNC() { export function stopTNC() {
var command = '{"type" : "set", "command": "stop_tnc" , "parameter": "---" }'; var command = '{"type" : "set", "command": "stop_tnc" , "parameter": "---" }';
writeDaemonCommand(command); writeDaemonCommand(command);
}; }
// TEST HAMLIB // TEST HAMLIB
function testHamlib( function testHamlib(
//exports.testHamlib = function ( //exports.testHamlib = function (
radiocontrol, radiocontrol,
devicename, devicename,
@ -291,7 +283,7 @@ function testHamlib(
}); });
console.log(json_command); console.log(json_command);
writeDaemonCommand(json_command); writeDaemonCommand(json_command);
}; }
//Save myCall //Save myCall
function saveMyCall(callsign) { function saveMyCall(callsign) {
@ -301,16 +293,15 @@ function saveMyCall(callsign){
callsign + callsign +
'"}'; '"}';
writeDaemonCommand(command); writeDaemonCommand(command);
}; }
// Save myGrid // Save myGrid
//exports.saveMyGrid = function (grid) { //exports.saveMyGrid = function (grid) {
function saveMyGrid(grid) { function saveMyGrid(grid) {
command = command =
'{"type" : "set", "command": "mygrid" , "parameter": "' + grid + '"}'; '{"type" : "set", "command": "mygrid" , "parameter": "' + grid + '"}';
writeDaemonCommand(command); writeDaemonCommand(command);
}; }
ipcRenderer.on("action-update-daemon-ip", (event, arg) => { ipcRenderer.on("action-update-daemon-ip", (event, arg) => {
daemon.destroy(); daemon.destroy();

View file

@ -1,6 +1,5 @@
const fs = require("fs"); const fs = require("fs");
/** /**
* Binary to ASCII replacement * Binary to ASCII replacement
* @param {string} data in normal/usual utf-8 format * @param {string} data in normal/usual utf-8 format
@ -25,5 +24,3 @@ exports.atob_FD = function (data) {
exports.atob = function (data) { exports.atob = function (data) {
return window.btoa(Buffer.from(data, "base64").toString("utf8")); return window.btoa(Buffer.from(data, "base64").toString("utf8"));
}; };

View file

@ -1,14 +1,7 @@
const { v4: uuidv4 } = require("uuid"); const { v4: uuidv4 } = require("uuid");
import * as bootstrap from 'bootstrap' import * as bootstrap from "bootstrap";
export function displayToast(type, icon, content, duration) {
export function displayToast(
type,
icon,
content,
duration,
) {
let mainToastContainer = document.getElementById("mainToastContainer"); let mainToastContainer = document.getElementById("mainToastContainer");
let randomID = uuidv4(); let randomID = uuidv4();

View file

@ -2,17 +2,16 @@
//const fs = require("fs"); //const fs = require("fs");
//const os = require("os"); //const os = require("os");
import path from 'node:path' import path from "node:path";
import fs from 'fs' import fs from "fs";
import os from 'os' import os from "os";
// pinia store setup // pinia store setup
import { setActivePinia } from 'pinia'; import { setActivePinia } from "pinia";
import pinia from '../store/index'; import pinia from "../store/index";
setActivePinia(pinia); setActivePinia(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
// --------------------------------- // ---------------------------------
@ -94,7 +93,6 @@ if (!fs.existsSync(configPath)) {
fs.writeFileSync(configPath, configDefaultSettings); fs.writeFileSync(configPath, configDefaultSettings);
} }
export function loadSettings() { export function loadSettings() {
// load settings // load settings
var config = require(configPath); var config = require(configPath);
@ -115,27 +113,20 @@ for (var key in parsedConfig) {
} }
try { try {
if (key == "mycall") { if (key == "mycall") {
settings.mycall = config[key].split("-")[0] settings.mycall = config[key].split("-")[0];
settings.myssid = config[key].split("-")[1] settings.myssid = config[key].split("-")[1];
} else { } else {
settings[key] = config[key]; settings[key] = config[key];
} }
} catch (e) { } catch (e) {
console.log(e) console.log(e);
} }
} }
} }
export function saveSettingsToFile() { export function saveSettingsToFile() {
console.log("save settings to file...") console.log("save settings to file...");
let config = settings.getJSON() let config = settings.getJSON();
console.log(config) console.log(config);
fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
} }

View file

@ -2,32 +2,32 @@ var net = require("net");
const path = require("path"); const path = require("path");
const FD = require("./src/js/freedata.js"); const FD = require("./src/js/freedata.js");
//import FD from './freedata.js'; //import FD from './freedata.js';
import { newMessageReceived, newBeaconReceived, updateTransmissionStatus, setStateSuccess, setStateFailed } from './chatHandler.js'; import {
import {displayToast} from './popupHandler.js' newMessageReceived,
newBeaconReceived,
updateTransmissionStatus,
setStateSuccess,
setStateFailed,
} from "./chatHandler.js";
import { displayToast } from "./popupHandler.js";
// ----------------- init pinia stores ------------- // ----------------- init pinia stores -------------
import { setActivePinia } from 'pinia'; import { setActivePinia } from "pinia";
import pinia from '../store/index'; import pinia from "../store/index";
setActivePinia(pinia); setActivePinia(pinia);
import { useStateStore } from '../store/stateStore.js'; import { useStateStore } from "../store/stateStore.js";
const stateStore = useStateStore(pinia); const stateStore = useStateStore(pinia);
import { useSettingsStore } from '../store/settingsStore.js'; import { useSettingsStore } from "../store/settingsStore.js";
const settings = useSettingsStore(pinia); const settings = useSettingsStore(pinia);
var client = new net.Socket(); var client = new net.Socket();
var socketchunk = ""; // Current message, per connection. var socketchunk = ""; // Current message, per connection.
// split character // split character
//const split_char = "\0;\1;"; //const split_char = "\0;\1;";
const split_char = "0;1;"; const split_char = "0;1;";
// globals for getting new data only if available so we are saving bandwidth // globals for getting new data only if available so we are saving bandwidth
var rxBufferLengthTnc = 0; var rxBufferLengthTnc = 0;
var rxBufferLengthGui = 0; var rxBufferLengthGui = 0;
@ -37,7 +37,6 @@ var rxBufferLengthGui = 0;
// global to keep track of TNC connection error emissions // global to keep track of TNC connection error emissions
var tncShowConnectStateError = 1; var tncShowConnectStateError = 1;
// network connection Timeout // network connection Timeout
setTimeout(connectTNC, 2000); setTimeout(connectTNC, 2000);
@ -48,9 +47,7 @@ function connectTNC() {
//clear message buffer after reconnecting or initial connection //clear message buffer after reconnecting or initial connection
socketchunk = ""; socketchunk = "";
client.connect(settings.tnc_port, settings.tnc_host); client.connect(settings.tnc_port, settings.tnc_host);
} }
client.on("connect", function (data) { client.on("connect", function (data) {
@ -62,7 +59,7 @@ client.on("connect", function (data) {
stateStore.mode = "-"; stateStore.mode = "-";
stateStore.bandwidth = "-"; stateStore.bandwidth = "-";
stateStore.dbfs_level = 0; stateStore.dbfs_level = 0;
stateStore.updateTncState(client.readyState) stateStore.updateTncState(client.readyState);
tncShowConnectStateError = 1; tncShowConnectStateError = 1;
}); });
@ -80,8 +77,7 @@ client.on("error", function (data) {
stateStore.mode = "-"; stateStore.mode = "-";
stateStore.bandwidth = "-"; stateStore.bandwidth = "-";
stateStore.dbfs_level = 0; stateStore.dbfs_level = 0;
stateStore.updateTncState(client.readyState) stateStore.updateTncState(client.readyState);
}); });
/* /*
@ -99,14 +95,14 @@ client.on("end", function (data) {
stateStore.mode = "-"; stateStore.mode = "-";
stateStore.bandwidth = "-"; stateStore.bandwidth = "-";
stateStore.dbfs_level = 0; stateStore.dbfs_level = 0;
stateStore.updateTncState(client.readyState) stateStore.updateTncState(client.readyState);
client.destroy(); client.destroy();
setTimeout(connectTNC, 500); setTimeout(connectTNC, 500);
}); });
function writeTncCommand(command) { function writeTncCommand(command) {
console.log(command) console.log(command);
// we use the writingCommand function to update our TCPIP state because we are calling this function a lot // we use the writingCommand function to update our TCPIP state because we are calling this function a lot
// if socket opened, we are able to run commands // if socket opened, we are able to run commands
@ -121,11 +117,10 @@ function writeTncCommand(command) {
if (client.readyState == "opening") { if (client.readyState == "opening") {
console.log("connecting to TNC..."); console.log("connecting to TNC...");
} }
}; }
client.on("data", function (socketdata) { client.on("data", function (socketdata) {
stateStore.updateTncState(client.readyState) stateStore.updateTncState(client.readyState);
/* /*
inspired by: inspired by:
@ -174,60 +169,64 @@ client.on("data", function (socketdata) {
rxBufferLengthTnc = data["rx_buffer_length"]; rxBufferLengthTnc = data["rx_buffer_length"];
//rxMsgBufferLengthTnc = data["rx_msg_buffer_length"]; //rxMsgBufferLengthTnc = data["rx_msg_buffer_length"];
stateStore.frequency = data["frequency"] stateStore.frequency = data["frequency"];
stateStore.busy_state = data["tnc_state"] stateStore.busy_state = data["tnc_state"];
stateStore.arq_state = data["arq_state"] stateStore.arq_state = data["arq_state"];
stateStore.mode = data["mode"] stateStore.mode = data["mode"];
stateStore.bandwidth = data["bandwidth"] stateStore.bandwidth = data["bandwidth"];
stateStore.dbfs_level = data["audio_dbfs"] stateStore.dbfs_level = data["audio_dbfs"];
stateStore.ptt_state = data["ptt_state"] stateStore.ptt_state = data["ptt_state"];
stateStore.speed_level = data["speed_level"] stateStore.speed_level = data["speed_level"];
stateStore.fft = data["fft"] stateStore.fft = data["fft"];
stateStore.channel_busy = data["channel_busy"] stateStore.channel_busy = data["channel_busy"];
stateStore.channel_busy_slot = data["channel_busy_slot"] stateStore.channel_busy_slot = data["channel_busy_slot"];
if (data["scatter"].length > 0) { if (data["scatter"].length > 0) {
stateStore.scatter = data["scatter"] stateStore.scatter = data["scatter"];
} }
// s meter strength // s meter strength
stateStore.s_meter_strength_raw = data["strength"] stateStore.s_meter_strength_raw = data["strength"];
if (stateStore.s_meter_strength_raw == "") { if (stateStore.s_meter_strength_raw == "") {
stateStore.s_meter_strength_raw = "Unsupported" stateStore.s_meter_strength_raw = "Unsupported";
stateStore.s_meter_strength_percent = 0 stateStore.s_meter_strength_percent = 0;
} else { } else {
// https://www.moellerstudios.org/converting-amplitude-representations/ // https://www.moellerstudios.org/converting-amplitude-representations/
stateStore.s_meter_strength_percent = Math.round(Math.pow(10, stateStore.s_meter_strength_raw / 20) * 100); stateStore.s_meter_strength_percent = Math.round(
Math.pow(10, stateStore.s_meter_strength_raw / 20) * 100,
);
} }
stateStore.dbfs_level_percent = Math.round(Math.pow(10, stateStore.dbfs_level / 20) * 100); stateStore.dbfs_level_percent = Math.round(
stateStore.dbfs_level = Math.round(stateStore.dbfs_level) Math.pow(10, stateStore.dbfs_level / 20) * 100,
);
stateStore.dbfs_level = Math.round(stateStore.dbfs_level);
stateStore.arq_total_bytes = data["total_bytes"];
stateStore.heard_stations = data["stations"];
stateStore.dxcallsign = data["dxcallsign"];
stateStore.arq_total_bytes = data["total_bytes"] stateStore.beacon_state = data["beacon_state"];
stateStore.heard_stations = data["stations"] stateStore.audio_recording = data["audio_recording"];
stateStore.dxcallsign = data["dxcallsign"]
stateStore.beacon_state = data["beacon_state"] stateStore.hamlib_status = data["hamlib_status"];
stateStore.audio_recording = data["audio_recording"] stateStore.alc = data["alc"];
stateStore.rf_level = data["rf_level"];
stateStore.hamlib_status = data["hamlib_status"] stateStore.is_codec2_traffic = data["is_codec2_traffic"];
stateStore.alc = data["alc"]
stateStore.rf_level = data["rf_level"]
stateStore.is_codec2_traffic = data["is_codec2_traffic"] stateStore.arq_session_state = data["arq_session"];
stateStore.arq_state = data["arq_state"];
stateStore.arq_session_state = data["arq_session"] stateStore.arq_transmission_percent = data["arq_transmission_percent"];
stateStore.arq_state = data["arq_state"] stateStore.arq_seconds_until_finish = data["arq_seconds_until_finish"];
stateStore.arq_transmission_percent = data["arq_transmission_percent"] stateStore.arq_seconds_until_timeout =
stateStore.arq_seconds_until_finish = data["arq_seconds_until_finish"] data["arq_seconds_until_timeout"];
stateStore.arq_seconds_until_timeout = data["arq_seconds_until_timeout"] stateStore.arq_seconds_until_timeout_percent =
stateStore.arq_seconds_until_timeout_percent = (stateStore.arq_seconds_until_timeout / 180) * 100 (stateStore.arq_seconds_until_timeout / 180) * 100;
if (data["speed_list"].length > 0) { if (data["speed_list"].length > 0) {
prepareStatsDataForStore(data["speed_list"]) prepareStatsDataForStore(data["speed_list"]);
} }
// TODO: Remove ported objects // TODO: Remove ported objects
let Data = { let Data = {
mycallsign: data["mycallsign"], mycallsign: data["mycallsign"],
@ -260,19 +259,16 @@ client.on("data", function (socketdata) {
// ----------- catch tnc messages START ----------- // ----------- catch tnc messages START -----------
//init message variable //init message variable
var message = '' var message = "";
if (data["freedata"] == "tnc-message") { if (data["freedata"] == "tnc-message") {
// break early if we received a dummy callsign // break early if we received a dummy callsign
// thats a kind of hotfix, as long as the tnc isnt handling this better // thats a kind of hotfix, as long as the tnc isnt handling this better
if (data["dxcallsign"] == "AA0AA-0") { if (data["dxcallsign"] == "AA0AA-0") {
break break;
} }
console.log(data); console.log(data);
switch (data["fec"]) { switch (data["fec"]) {
case "is_writing": case "is_writing":
// RX'd FECiswriting // RX'd FECiswriting
@ -293,12 +289,17 @@ client.on("data", function (socketdata) {
switch (data["cq"]) { switch (data["cq"]) {
case "transmitting": case "transmitting":
// CQ TRANSMITTING // CQ TRANSMITTING
displayToast("success", "bi-arrow-left-right", "transmitting CQ", 5000); displayToast(
"success",
"bi-arrow-left-right",
"transmitting CQ",
5000,
);
break; break;
case "received": case "received":
// CQ RECEIVED // CQ RECEIVED
message = "CQ from " + data['dxcallsign'] message = "CQ from " + data["dxcallsign"];
displayToast("success", "bi-arrow-left-right", message, 5000); displayToast("success", "bi-arrow-left-right", message, 5000);
break; break;
} }
@ -306,12 +307,17 @@ client.on("data", function (socketdata) {
switch (data["qrv"]) { switch (data["qrv"]) {
case "transmitting": case "transmitting":
// QRV TRANSMITTING // QRV TRANSMITTING
displayToast("success", "bi-arrow-left-right", "transmitting QRV ", 5000); displayToast(
"success",
"bi-arrow-left-right",
"transmitting QRV ",
5000,
);
break; break;
case "received": case "received":
// QRV RECEIVED // QRV RECEIVED
message = "QRV from " + data['dxcallsign'] + " | " + data['dxgrid'] message = "QRV from " + data["dxcallsign"] + " | " + data["dxgrid"];
displayToast("success", "bi-arrow-left-right", message, 5000); displayToast("success", "bi-arrow-left-right", message, 5000);
break; break;
} }
@ -324,9 +330,10 @@ client.on("data", function (socketdata) {
case "received": case "received":
// BEACON RECEIVED // BEACON RECEIVED
newBeaconReceived(data) newBeaconReceived(data);
message = "BEACON from " + data['dxcallsign'] + " | " + data['dxgrid'] message =
"BEACON from " + data["dxcallsign"] + " | " + data["dxgrid"];
displayToast("success", "bi-arrow-left-right", message, 5000); displayToast("success", "bi-arrow-left-right", message, 5000);
break; break;
} }
@ -334,19 +341,21 @@ client.on("data", function (socketdata) {
switch (data["ping"]) { switch (data["ping"]) {
case "transmitting": case "transmitting":
// PING TRANSMITTING // PING TRANSMITTING
message = "PING to " + data['dxcallsign'] message = "PING to " + data["dxcallsign"];
displayToast("success", "bi-arrow-left-right", message, 5000); displayToast("success", "bi-arrow-left-right", message, 5000);
break; break;
case "received": case "received":
// PING RECEIVED // PING RECEIVED
message = "PING from " + data['dxcallsign'] + " | " + data['dxgrid'] message =
"PING from " + data["dxcallsign"] + " | " + data["dxgrid"];
displayToast("success", "bi-arrow-left-right", message, 5000); displayToast("success", "bi-arrow-left-right", message, 5000);
break; break;
case "acknowledge": case "acknowledge":
// PING ACKNOWLEDGE // PING ACKNOWLEDGE
message = "PING ACK from " + data['dxcallsign'] + " | " + data['dxgrid'] message =
"PING ACK from " + data["dxcallsign"] + " | " + data["dxgrid"];
displayToast("success", "bi-arrow-left-right", message, 5000); displayToast("success", "bi-arrow-left-right", message, 5000);
break; break;
} }
@ -380,29 +389,27 @@ client.on("data", function (socketdata) {
switch (data["status"]) { switch (data["status"]) {
case "opened": case "opened":
// ARQ Open // ARQ Open
message = "ARQ session opened:" + data['dxcallsign'] message = "ARQ session opened:" + data["dxcallsign"];
displayToast("success", "bi-arrow-left-right", message, 5000); displayToast("success", "bi-arrow-left-right", message, 5000);
break; break;
case "opening": case "opening":
// ARQ Opening IRS/ISS // ARQ Opening IRS/ISS
if (data["irs"] == "False") { if (data["irs"] == "False") {
message = "ARQ session opening:" + data['dxcallsign'] message = "ARQ session opening:" + data["dxcallsign"];
displayToast("success", "bi-arrow-left-right", message, 5000); displayToast("success", "bi-arrow-left-right", message, 5000);
break; break;
} else { } else {
message = data["dxcallsign"] + "is requesting an ARQ session";
message = data['dxcallsign'] + "is requesting an ARQ session"
displayToast("success", "bi-arrow-left-right", message, 5000); displayToast("success", "bi-arrow-left-right", message, 5000);
break; break;
} }
break; break;
case "waiting": case "waiting":
// ARQ waiting // ARQ waiting
message = "busy channel | ARQ protocol is waiting" message = "busy channel | ARQ protocol is waiting";
displayToast("success", "bi-arrow-left-right", message, 5000); displayToast("success", "bi-arrow-left-right", message, 5000);
break; break;
@ -413,26 +420,25 @@ client.on("data", function (socketdata) {
case "failed": case "failed":
// ARQ TX Failed // ARQ TX Failed
if (data["reason"] == "protocol version missmatch") { if (data["reason"] == "protocol version missmatch") {
message = "protocol version missmatch" message = "protocol version missmatch";
displayToast("success", "bi-arrow-left-right", message, 5000); displayToast("success", "bi-arrow-left-right", message, 5000);
setStateFailed() setStateFailed();
break; break;
} else { } else {
message = "transmission failed" message = "transmission failed";
displayToast("success", "bi-arrow-left-right", message, 5000); displayToast("success", "bi-arrow-left-right", message, 5000);
updateTransmissionStatus(data) updateTransmissionStatus(data);
setStateFailed() setStateFailed();
break; break;
} }
switch (data["irs"]) { switch (data["irs"]) {
case "True": case "True":
updateTransmissionStatus(data) updateTransmissionStatus(data);
break; break;
default: default:
updateTransmissionStatus(data) updateTransmissionStatus(data);
break; break;
} }
break; break;
@ -448,30 +454,29 @@ client.on("data", function (socketdata) {
// new message received // new message received
if (splitted_data[0] == "m") { if (splitted_data[0] == "m") {
console.log(splitted_data) console.log(splitted_data);
newMessageReceived(splitted_data, data) newMessageReceived(splitted_data, data);
} }
break; break;
case "transmitting": case "transmitting":
// ARQ transmitting // ARQ transmitting
updateTransmissionStatus(data) updateTransmissionStatus(data);
break; break;
case "transmitted": case "transmitted":
// ARQ transmitted // ARQ transmitted
message = "data transmitted" message = "data transmitted";
displayToast("success", "bi-arrow-left-right", message, 5000); displayToast("success", "bi-arrow-left-right", message, 5000);
updateTransmissionStatus(data) updateTransmissionStatus(data);
setStateSuccess() setStateSuccess();
break; break;
} }
} }
} }
// ----------- catch tnc info messages END ----------- // ----------- catch tnc info messages END -----------
// if we manually checking for the rx buffer we are getting an array of multiple data // if we manually checking for the rx buffer we are getting an array of multiple data
@ -488,7 +493,6 @@ client.on("data", function (socketdata) {
var encoded_data = FD.atob_FD(data["data-array"][i]["data"]); var encoded_data = FD.atob_FD(data["data-array"][i]["data"]);
var splitted_data = encoded_data.split(split_char); var splitted_data = encoded_data.split(split_char);
if (splitted_data[0] == "m") { if (splitted_data[0] == "m") {
messageArray.push(data["data-array"][i]); messageArray.push(data["data-array"][i]);
} }
@ -508,7 +512,6 @@ client.on("data", function (socketdata) {
//finally delete message buffer //finally delete message buffer
socketchunk = ""; socketchunk = "";
} }
}); });
function hexToBytes(hex) { function hexToBytes(hex) {
@ -522,14 +525,14 @@ function hexToBytes(hex) {
function getTncState() { function getTncState() {
var command = '{"type" : "get", "command" : "tnc_state"}'; var command = '{"type" : "get", "command" : "tnc_state"}';
writeTncCommand(command); writeTncCommand(command);
}; }
//Get DATA State //Get DATA State
//exports.getDataState = function () { //exports.getDataState = function () {
function getDataState() { function getDataState() {
var command = '{"type" : "get", "command" : "data_state"}'; var command = '{"type" : "get", "command" : "data_state"}';
//writeTncCommand(command) //writeTncCommand(command)
}; }
// Send Ping // Send Ping
//exports.sendPing = function (dxcallsign) { //exports.sendPing = function (dxcallsign) {
@ -539,7 +542,7 @@ export function sendPing(dxcallsign){
dxcallsign + dxcallsign +
'"}'; '"}';
writeTncCommand(command); writeTncCommand(command);
}; }
// Send Mesh Ping // Send Mesh Ping
//exports.sendMeshPing = function (dxcallsign) { //exports.sendMeshPing = function (dxcallsign) {
@ -549,22 +552,21 @@ function sendMeshPing(dxcallsign){
dxcallsign + dxcallsign +
'"}'; '"}';
writeTncCommand(command); writeTncCommand(command);
}; }
// Send CQ // Send CQ
//exports.sendCQ = function () { //exports.sendCQ = function () {
export function sendCQ() { export function sendCQ() {
var command = '{"type" : "broadcast", "command" : "cqcqcq"}'; var command = '{"type" : "broadcast", "command" : "cqcqcq"}';
writeTncCommand(command); writeTncCommand(command);
}; }
// Set AUDIO Level // Set AUDIO Level
export function setTxAudioLevel(value) { export function setTxAudioLevel(value) {
var command = var command =
'{"type" : "set", "command" : "tx_audio_level", "value" : "' + value + '"}'; '{"type" : "set", "command" : "tx_audio_level", "value" : "' + value + '"}';
writeTncCommand(command); writeTncCommand(command);
}; }
// Send File // Send File
//exports.sendFile = function ( //exports.sendFile = function (
@ -611,16 +613,10 @@ function sendFile(
data + data +
'"}]}'; '"}]}';
writeTncCommand(command); writeTncCommand(command);
}; }
// Send Message // Send Message
export function sendMessage( export function sendMessage(dxcallsign, data, checksum, uuid, command) {
dxcallsign,
data,
checksum,
uuid,
command,
) {
data = FD.btoa_FD( data = FD.btoa_FD(
"m" + "m" +
split_char + split_char +
@ -634,9 +630,8 @@ export function sendMessage(
); );
// TODO: REMOVE mode and frames from TNC! // TODO: REMOVE mode and frames from TNC!
var mode = 255 var mode = 255;
var frames = 5 var frames = 5;
command = command =
'{"type" : "arq", "command" : "send_raw", "uuid" : "' + '{"type" : "arq", "command" : "send_raw", "uuid" : "' +
@ -652,7 +647,7 @@ export function sendMessage(
'", "attempts": "10"}]}'; '", "attempts": "10"}]}';
console.log(command); console.log(command);
writeTncCommand(command); writeTncCommand(command);
}; }
// Send Request message // Send Request message
//It would be then „m + split + request + split + request-type“ //It would be then „m + split + request + split + request-type“
@ -699,17 +694,16 @@ function sendRequestInfo(dxcallsign){
//Command 1 = shared folder list //Command 1 = shared folder list
//Command 2 = shared file transfer //Command 2 = shared file transfer
sendRequest(dxcallsign, 255, 1, "0", "req"); sendRequest(dxcallsign, 255, 1, "0", "req");
}; }
//Send shared folder file list request //Send shared folder file list request
//exports.sendRequestSharedFolderList = function (dxcallsign) { //exports.sendRequestSharedFolderList = function (dxcallsign) {
function sendRequestSharedFolderList(dxcallsign) { function sendRequestSharedFolderList(dxcallsign) {
//Command 0 = user/station information //Command 0 = user/station information
//Command 1 = shared folder list //Command 1 = shared folder list
//Command 2 = shared file transfer //Command 2 = shared file transfer
sendRequest(dxcallsign, 255, 1, "1", "req"); sendRequest(dxcallsign, 255, 1, "1", "req");
}; }
//Send shared file request //Send shared file request
//exports.sendRequestSharedFile = function (dxcallsign, file) { //exports.sendRequestSharedFile = function (dxcallsign, file) {
@ -718,7 +712,7 @@ function sendRequestSharedFile(dxcallsign, file){
//Command 1 = shared folder list //Command 1 = shared folder list
//Command 2 = shared file transfer //Command 2 = shared file transfer
sendRequest(dxcallsign, 255, 1, "2" + file, "req"); sendRequest(dxcallsign, 255, 1, "2" + file, "req");
}; }
//Send station info response //Send station info response
//exports.sendResponseInfo = function (dxcallsign, userinfo) { //exports.sendResponseInfo = function (dxcallsign, userinfo) {
@ -727,7 +721,7 @@ function sendResponseInfo(dxcallsign, userinfo){
//Command 1 = shared folder list //Command 1 = shared folder list
//Command 2 = shared file transfer //Command 2 = shared file transfer
sendResponse(dxcallsign, 255, 1, userinfo, "res-0"); sendResponse(dxcallsign, 255, 1, userinfo, "res-0");
}; }
//Send shared folder response //Send shared folder response
//exports.sendResponseSharedFolderList = function (dxcallsign, sharedFolderList) { //exports.sendResponseSharedFolderList = function (dxcallsign, sharedFolderList) {
@ -736,15 +730,11 @@ function sendResponseSharedFolderList(dxcallsign, sharedFolderList){
//Command 1 = shared folder list //Command 1 = shared folder list
//Command 2 = shared file transfer //Command 2 = shared file transfer
sendResponse(dxcallsign, 255, 1, sharedFolderList, "res-1"); sendResponse(dxcallsign, 255, 1, sharedFolderList, "res-1");
}; }
//Send shared file response //Send shared file response
//exports.sendResponseSharedFile = function ( //exports.sendResponseSharedFile = function (
function sendResponseSharedFile( function sendResponseSharedFile(dxcallsign, sharedFile, sharedFileData) {
dxcallsign,
sharedFile,
sharedFileData,
) {
console.log( console.log(
"In sendResponseSharedFile", "In sendResponseSharedFile",
dxcallsign, dxcallsign,
@ -755,13 +745,13 @@ function sendResponseSharedFile(
//Command 1 = shared folder list //Command 1 = shared folder list
//Command 2 = shared file transfer //Command 2 = shared file transfer
sendResponse(dxcallsign, 255, 1, sharedFile + "/" + sharedFileData, "res-2"); sendResponse(dxcallsign, 255, 1, sharedFile + "/" + sharedFileData, "res-2");
}; }
//STOP TRANSMISSION //STOP TRANSMISSION
export function stopTransmission() { export function stopTransmission() {
var command = '{"type" : "arq", "command": "stop_transmission"}'; var command = '{"type" : "arq", "command": "stop_transmission"}';
writeTncCommand(command); writeTncCommand(command);
}; }
// Get RX BUffer // Get RX BUffer
export function getRxBuffer() { export function getRxBuffer() {
@ -771,7 +761,7 @@ export function getRxBuffer(){
if (rxBufferLengthGui != rxBufferLengthTnc) { if (rxBufferLengthGui != rxBufferLengthTnc) {
writeTncCommand(command); writeTncCommand(command);
} }
}; }
// START BEACON // START BEACON
export function startBeacon(interval) { export function startBeacon(interval) {
@ -780,13 +770,13 @@ export function startBeacon(interval){
interval + interval +
'"}'; '"}';
writeTncCommand(command); writeTncCommand(command);
}; }
// STOP BEACON // STOP BEACON
export function stopBeacon() { export function stopBeacon() {
var command = '{"type" : "broadcast", "command" : "stop_beacon"}'; var command = '{"type" : "broadcast", "command" : "stop_beacon"}';
writeTncCommand(command); writeTncCommand(command);
}; }
// OPEN ARQ SESSION // OPEN ARQ SESSION
export function connectARQ(dxcallsign) { export function connectARQ(dxcallsign) {
@ -795,19 +785,19 @@ export function connectARQ(dxcallsign){
dxcallsign + dxcallsign +
'", "attempts": "10"}'; '", "attempts": "10"}';
writeTncCommand(command); writeTncCommand(command);
}; }
// CLOSE ARQ SESSION // CLOSE ARQ SESSION
export function disconnectARQ() { export function disconnectARQ() {
var command = '{"type" : "arq", "command" : "disconnect"}'; var command = '{"type" : "arq", "command" : "disconnect"}';
writeTncCommand(command); writeTncCommand(command);
}; }
// SEND TEST FRAME // SEND TEST FRAME
export function sendTestFrame() { export function sendTestFrame() {
var command = '{"type" : "set", "command" : "send_test_frame"}'; var command = '{"type" : "set", "command" : "send_test_frame"}';
writeTncCommand(command); writeTncCommand(command);
}; }
// SEND FEC // SEND FEC
export function sendFEC(mode, payload) { export function sendFEC(mode, payload) {
@ -818,7 +808,7 @@ export function sendFEC(mode, payload){
payload + payload +
'"}'; '"}';
writeTncCommand(command); writeTncCommand(command);
}; }
// SEND FEC IS WRITING // SEND FEC IS WRITING
export function sendFecIsWriting(mycallsign) { export function sendFecIsWriting(mycallsign) {
@ -827,7 +817,7 @@ export function sendFecIsWriting(mycallsign){
mycallsign + mycallsign +
'"}'; '"}';
writeTncCommand(command); writeTncCommand(command);
}; }
// SEND FEC TO BROADCASTCHANNEL // SEND FEC TO BROADCASTCHANNEL
export function sendBroadcastChannel(channel, data_out, uuid) { export function sendBroadcastChannel(channel, data_out, uuid) {
@ -851,33 +841,33 @@ export function sendBroadcastChannel(channel, data_out, uuid){
payload + payload +
'"}'; '"}';
writeTncCommand(command); writeTncCommand(command);
}; }
// RECORD AUDIO // RECORD AUDIO
export function record_audio() { export function record_audio() {
var command = '{"type" : "set", "command" : "record_audio"}'; var command = '{"type" : "set", "command" : "record_audio"}';
writeTncCommand(command); writeTncCommand(command);
}; }
// SET FREQUENCY // SET FREQUENCY
export function set_frequency(frequency) { export function set_frequency(frequency) {
var command = var command =
'{"type" : "set", "command" : "frequency", "frequency": ' + frequency + "}"; '{"type" : "set", "command" : "frequency", "frequency": ' + frequency + "}";
writeTncCommand(command); writeTncCommand(command);
}; }
// SET MODE // SET MODE
export function set_mode(mode) { export function set_mode(mode) {
var command = '{"type" : "set", "command" : "mode", "mode": "' + mode + '"}'; var command = '{"type" : "set", "command" : "mode", "mode": "' + mode + '"}';
writeTncCommand(command); writeTncCommand(command);
}; }
// SET rf_level // SET rf_level
export function set_rf_level(rf_level) { export function set_rf_level(rf_level) {
var command = '{"type" : "set", "command" : "rf_level", "rf_level": "' + rf_level + '"}'; var command =
'{"type" : "set", "command" : "rf_level", "rf_level": "' + rf_level + '"}';
writeTncCommand(command); writeTncCommand(command);
}; }
// https://stackoverflow.com/a/50579690 // https://stackoverflow.com/a/50579690
// crc32 calculation // crc32 calculation
@ -895,10 +885,8 @@ var crc32 = function (r) {
return (-1 ^ n) >>> 0; return (-1 ^ n) >>> 0;
}; };
// TODO: Maybe moving this to another module // TODO: Maybe moving this to another module
function prepareStatsDataForStore(data) { function prepareStatsDataForStore(data) {
// dummy data // dummy data
//state.arq_speed_list = [{"snr":0.0,"bpm":104,"timestamp":1696189769},{"snr":0.0,"bpm":80,"timestamp":1696189778},{"snr":0.0,"bpm":70,"timestamp":1696189783},{"snr":0.0,"bpm":58,"timestamp":1696189792},{"snr":0.0,"bpm":52,"timestamp":1696189797},{"snr":"NaN","bpm":42,"timestamp":1696189811},{"snr":0.0,"bpm":22,"timestamp":1696189875},{"snr":0.0,"bpm":21,"timestamp":1696189881},{"snr":0.0,"bpm":17,"timestamp":1696189913},{"snr":0.0,"bpm":15,"timestamp":1696189932},{"snr":0.0,"bpm":15,"timestamp":1696189937},{"snr":0.0,"bpm":14,"timestamp":1696189946},{"snr":-6.1,"bpm":14,"timestamp":1696189954},{"snr":-6.1,"bpm":14,"timestamp":1696189955},{"snr":-5.5,"bpm":28,"timestamp":1696189963},{"snr":-5.5,"bpm":27,"timestamp":1696189963}] //state.arq_speed_list = [{"snr":0.0,"bpm":104,"timestamp":1696189769},{"snr":0.0,"bpm":80,"timestamp":1696189778},{"snr":0.0,"bpm":70,"timestamp":1696189783},{"snr":0.0,"bpm":58,"timestamp":1696189792},{"snr":0.0,"bpm":52,"timestamp":1696189797},{"snr":"NaN","bpm":42,"timestamp":1696189811},{"snr":0.0,"bpm":22,"timestamp":1696189875},{"snr":0.0,"bpm":21,"timestamp":1696189881},{"snr":0.0,"bpm":17,"timestamp":1696189913},{"snr":0.0,"bpm":15,"timestamp":1696189932},{"snr":0.0,"bpm":15,"timestamp":1696189937},{"snr":0.0,"bpm":14,"timestamp":1696189946},{"snr":-6.1,"bpm":14,"timestamp":1696189954},{"snr":-6.1,"bpm":14,"timestamp":1696189955},{"snr":-5.5,"bpm":28,"timestamp":1696189963},{"snr":-5.5,"bpm":27,"timestamp":1696189963}]
@ -908,14 +896,13 @@ function prepareStatsDataForStore(data){
var speed_listSize = data.length; var speed_listSize = data.length;
} }
var speed_list_bpm = [];
var speed_list_bpm = []
for (var i = 0; i < speed_listSize; i++) { for (var i = 0; i < speed_listSize; i++) {
speed_list_bpm.push(data[i].bpm); speed_list_bpm.push(data[i].bpm);
} }
var speed_list_timestamp = [] var speed_list_timestamp = [];
for (var i = 0; i < speed_listSize; i++) { for (var i = 0; i < speed_listSize; i++) {
var timestamp = data[i].timestamp * 1000; var timestamp = data[i].timestamp * 1000;
@ -926,8 +913,7 @@ function prepareStatsDataForStore(data){
speed_list_timestamp.push(time); speed_list_timestamp.push(time);
} }
var speed_list_snr = [];
var speed_list_snr = []
for (var i = 0; i < speed_listSize; i++) { for (var i = 0; i < speed_listSize; i++) {
let snr = NaN; let snr = NaN;
if (data[i].snr !== 0) { if (data[i].snr !== 0) {
@ -938,8 +924,7 @@ function prepareStatsDataForStore(data){
speed_list_snr.push(snr); speed_list_snr.push(snr);
} }
stateStore.arq_speed_list_bpm = speed_list_bpm stateStore.arq_speed_list_bpm = speed_list_bpm;
stateStore.arq_speed_list_timestamp = speed_list_timestamp stateStore.arq_speed_list_timestamp = speed_list_timestamp;
stateStore.arq_speed_list_snr = speed_list_snr stateStore.arq_speed_list_snr = speed_list_snr;
} }

View file

@ -1,16 +1,16 @@
import { defineStore } from 'pinia' import { defineStore } from "pinia";
import { ref, computed } from 'vue'; import { ref, computed } from "vue";
export const useAudioStore = defineStore('audioStore', () => { export const useAudioStore = defineStore("audioStore", () => {
var inputDevices = ref([{"id":0, "name": "no input devices"}]) var inputDevices = ref([{ id: 0, name: "no input devices" }]);
var outputDevices = ref([{"id":0, "name": "no output devices"}]) var outputDevices = ref([{ id: 0, name: "no output devices" }]);
function getInputDevices() { function getInputDevices() {
var html = ""; var html = "";
for (var key in inputDevices.value) { for (var key in inputDevices.value) {
html += `<option value=${inputDevices.value[key]["id"]}>${inputDevices.value[key]["name"]}</option>`; html += `<option value=${inputDevices.value[key]["id"]}>${inputDevices.value[key]["name"]}</option>`;
} }
return html return html;
} }
function getOutputDevices() { function getOutputDevices() {
@ -18,7 +18,7 @@ export const useAudioStore = defineStore('audioStore', () => {
for (var key in outputDevices.value) { for (var key in outputDevices.value) {
html += `<option value="${outputDevices.value[key]["id"]}">${outputDevices.value[key]["name"]}</option>`; html += `<option value="${outputDevices.value[key]["id"]}">${outputDevices.value[key]["name"]}</option>`;
} }
return html return html;
} }
return { inputDevices, outputDevices, getInputDevices, getOutputDevices }; return { inputDevices, outputDevices, getInputDevices, getOutputDevices };

View file

@ -1,7 +1,7 @@
import { defineStore } from 'pinia' import { defineStore } from "pinia";
import { ref, computed } from 'vue'; import { ref, computed } from "vue";
export const useChatStore = defineStore('chatStore', () => { export const useChatStore = defineStore("chatStore", () => {
var chat_filter = ref([ var chat_filter = ref([
{ type: "newchat" }, { type: "newchat" },
{ type: "received" }, { type: "received" },
@ -11,31 +11,48 @@ export const useChatStore = defineStore('chatStore', () => {
{ type: "broadcast_transmit" }, { type: "broadcast_transmit" },
//{ type: "request" }, //{ type: "request" },
//{ type: "response" }, //{ type: "response" },
]) ]);
var selectedCallsign = ref();
var inputText = ref();
var inputFile = ref();
var inputFileName = ref();
var inputFileType = ref();
var inputFileSize = ref();
var selectedCallsign = ref() var callsign_list = ref();
var inputText = ref() var sorted_chat_list = ref();
var inputFile = ref() var unsorted_chat_list = ref([]);
var inputFileName = ref()
var inputFileType = ref()
var inputFileSize = ref()
var callsign_list = ref() var sorted_beacon_list = ref({});
var sorted_chat_list = ref() var unsorted_beacon_list = ref({});
var unsorted_chat_list = ref([])
var sorted_beacon_list = ref({}) var chartSpeedPER0 = ref();
var unsorted_beacon_list = ref({}) var chartSpeedPER25 = ref();
var chartSpeedPER75 = ref();
var chartSpeedPER0 = ref()
var chartSpeedPER25 = ref()
var chartSpeedPER75 = ref()
// var beaconDataArray = ref([-3, 10, 8, 5, 3, 0, -5, 10, 8, 5, 3, 0, -5, 10, 8, 5, 3, 0, -5, 10, 8, 5, 3, 0, -5]) // var beaconDataArray = ref([-3, 10, 8, 5, 3, 0, -5, 10, 8, 5, 3, 0, -5, 10, 8, 5, 3, 0, -5, 10, 8, 5, 3, 0, -5])
// var beaconLabelArray = ref(['18:10', '19:00', '23:00', '01:13', '04:25', '08:15', '09:12', '18:10', '19:00', '23:00', '01:13', '04:25', '08:15', '09:12', '18:10', '19:00', '23:00', '01:13', '04:25', '08:15', '09:12', '01:13', '04:25', '08:15', '09:12']) // var beaconLabelArray = ref(['18:10', '19:00', '23:00', '01:13', '04:25', '08:15', '09:12', '18:10', '19:00', '23:00', '01:13', '04:25', '08:15', '09:12', '18:10', '19:00', '23:00', '01:13', '04:25', '08:15', '09:12', '01:13', '04:25', '08:15', '09:12'])
var beaconDataArray = ref([]) var beaconDataArray = ref([]);
var beaconLabelArray = ref([]) var beaconLabelArray = ref([]);
return {selectedCallsign, inputText, chat_filter, callsign_list, sorted_chat_list, unsorted_chat_list, inputFileName, inputFileSize, inputFileType, inputFile, chartSpeedPER0, chartSpeedPER25, chartSpeedPER75, beaconDataArray, beaconLabelArray , unsorted_beacon_list, sorted_beacon_list }; return {
selectedCallsign,
inputText,
chat_filter,
callsign_list,
sorted_chat_list,
unsorted_chat_list,
inputFileName,
inputFileSize,
inputFileType,
inputFile,
chartSpeedPER0,
chartSpeedPER25,
chartSpeedPER75,
beaconDataArray,
beaconLabelArray,
unsorted_beacon_list,
sorted_beacon_list,
};
}); });

View file

@ -1,4 +1,4 @@
import { createPinia } from 'pinia'; import { createPinia } from "pinia";
const pinia = createPinia(); const pinia = createPinia();

View file

@ -1,152 +1,142 @@
import { defineStore } from 'pinia' import { defineStore } from "pinia";
import { ref, computed } from 'vue' import { ref, computed } from "vue";
export const useSettingsStore = defineStore('settingsStore', () => {
export const useSettingsStore = defineStore("settingsStore", () => {
// network // network
var tnc_host = ref("127.0.0.1") var tnc_host = ref("127.0.0.1");
var tnc_port = ref(3000) var tnc_port = ref(3000);
var daemon_host = ref(tnc_host.value) var daemon_host = ref(tnc_host.value);
var daemon_port = ref(tnc_port.value + 1) var daemon_port = ref(tnc_port.value + 1);
// app // app
var screen_height = ref(430) var screen_height = ref(430);
var screen_width = ref(1050) var screen_width = ref(1050);
var theme = ref("default") var theme = ref("default");
var wftheme = ref(2) var wftheme = ref(2);
var high_graphics = ref("False") var high_graphics = ref("False");
var auto_start = ref(0) var auto_start = ref(0);
var enable_sys_notification = ref(1) var enable_sys_notification = ref(1);
// chat // chat
var shared_folder_path = ref(".") var shared_folder_path = ref(".");
var enable_request_profile = ref("True") var enable_request_profile = ref("True");
var enable_request_shared_folder = ref("False") var enable_request_shared_folder = ref("False");
var max_retry_attempts = ref(5) var max_retry_attempts = ref(5);
var enable_auto_retry = ref("False") var enable_auto_retry = ref("False");
// station // station
var mycall = ref("AA0AA-5") var mycall = ref("AA0AA-5");
var myssid = ref(0) var myssid = ref(0);
var mygrid = ref("JN20aa") var mygrid = ref("JN20aa");
// rigctld // rigctld
var hamlib_rigctld_port = ref(4532) var hamlib_rigctld_port = ref(4532);
var hamlib_rigctld_ip = ref("127.0.0.1") var hamlib_rigctld_ip = ref("127.0.0.1");
var radiocontrol = ref("disabled") var radiocontrol = ref("disabled");
var hamlib_deviceid = ref("RIG_MODEL_DUMMY_NOVFO") var hamlib_deviceid = ref("RIG_MODEL_DUMMY_NOVFO");
var hamlib_deviceport = ref("ignore") var hamlib_deviceport = ref("ignore");
var hamlib_stop_bits = ref("ignore") var hamlib_stop_bits = ref("ignore");
var hamlib_data_bits = ref("ignore") var hamlib_data_bits = ref("ignore");
var hamlib_handshake = ref("ignore") var hamlib_handshake = ref("ignore");
var hamlib_serialspeed = ref("ignore") var hamlib_serialspeed = ref("ignore");
var hamlib_dtrstate = ref("ignore") var hamlib_dtrstate = ref("ignore");
var hamlib_pttprotocol = ref("ignore") var hamlib_pttprotocol = ref("ignore");
var hamlib_ptt_port = ref("ignore") var hamlib_ptt_port = ref("ignore");
var hamlib_dcd = ref("ignore") var hamlib_dcd = ref("ignore");
var hamlbib_serialspeed_ptt = ref(9600) var hamlbib_serialspeed_ptt = ref(9600);
var hamlib_rigctld_port = ref(4532) var hamlib_rigctld_port = ref(4532);
var hamlib_rigctld_ip = ref("127.0.0.1") var hamlib_rigctld_ip = ref("127.0.0.1");
var hamlib_rigctld_path = ref("") var hamlib_rigctld_path = ref("");
var hamlib_rigctld_server_port = ref(4532) var hamlib_rigctld_server_port = ref(4532);
var hamlib_rigctld_custom_args = ref("") var hamlib_rigctld_custom_args = ref("");
// tci // tci
var tci_ip = ref('127.0.0.1') var tci_ip = ref("127.0.0.1");
var tci_port = ref(50001) var tci_port = ref(50001);
//tnc //tnc
var spectrum = ref("waterfall") var spectrum = ref("waterfall");
var enable_scatter = ref("False") var enable_scatter = ref("False");
var enable_fft = ref("False") var enable_fft = ref("False");
var enable_fsk = ref("False") var enable_fsk = ref("False");
var low_bandwidth_mode = ref("False") var low_bandwidth_mode = ref("False");
var update_channel = ref("latest") var update_channel = ref("latest");
var beacon_interval = ref(300) var beacon_interval = ref(300);
var received_files_folder = ref("None") var received_files_folder = ref("None");
var tuning_range_fmin = ref(-50.0) var tuning_range_fmin = ref(-50.0);
var tuning_range_fmax = ref(50.0) var tuning_range_fmax = ref(50.0);
var respond_to_cq = ref("True") var respond_to_cq = ref("True");
var rx_buffer_size = ref(16) var rx_buffer_size = ref(16);
var enable_explorer = ref("False") var enable_explorer = ref("False");
var explorer_stats = ref("False") var explorer_stats = ref("False");
var auto_tune = ref("False") var auto_tune = ref("False");
var enable_is_writing = ref("True") var enable_is_writing = ref("True");
var tx_delay = ref(0) var tx_delay = ref(0);
var enable_mesh_features = ref("False") var enable_mesh_features = ref("False");
function getJSON() { function getJSON() {
var config_export = { var config_export = {
"tnc_host": tnc_host.value, tnc_host: tnc_host.value,
"tnc_port": tnc_port.value, tnc_port: tnc_port.value,
"daemon_host": tnc_host.value, daemon_host: tnc_host.value,
"daemon_port": (parseInt(tnc_port.value) + 1).toString(), daemon_port: (parseInt(tnc_port.value) + 1).toString(),
"mycall": mycall.value, mycall: mycall.value,
"myssid": myssid.value, myssid: myssid.value,
"mygrid": mygrid.value, mygrid: mygrid.value,
"radiocontrol" : radiocontrol.value, radiocontrol: radiocontrol.value,
"hamlib_deviceid": hamlib_deviceid.value, hamlib_deviceid: hamlib_deviceid.value,
"hamlib_deviceport": hamlib_deviceport.value, hamlib_deviceport: hamlib_deviceport.value,
"hamlib_stop_bits": hamlib_stop_bits.value, hamlib_stop_bits: hamlib_stop_bits.value,
"hamlib_data_bits": hamlib_data_bits.value, hamlib_data_bits: hamlib_data_bits.value,
"hamlib_handshake": hamlib_handshake.value, hamlib_handshake: hamlib_handshake.value,
"hamlib_serialspeed": hamlib_serialspeed.value, hamlib_serialspeed: hamlib_serialspeed.value,
"hamlib_dtrstate": hamlib_dtrstate.value, hamlib_dtrstate: hamlib_dtrstate.value,
"hamlib_pttprotocol": hamlib_pttprotocol.value, hamlib_pttprotocol: hamlib_pttprotocol.value,
"hamlib_ptt_port": hamlib_ptt_port.value, hamlib_ptt_port: hamlib_ptt_port.value,
"hamlib_dcd": hamlib_dcd.value, hamlib_dcd: hamlib_dcd.value,
"hamlbib_serialspeed_ptt": hamlib_serialspeed.value, hamlbib_serialspeed_ptt: hamlib_serialspeed.value,
"hamlib_rigctld_port" : hamlib_rigctld_port.value, hamlib_rigctld_port: hamlib_rigctld_port.value,
"hamlib_rigctld_ip" : hamlib_rigctld_ip.value, hamlib_rigctld_ip: hamlib_rigctld_ip.value,
"hamlib_rigctld_path" : hamlib_rigctld_path.value, hamlib_rigctld_path: hamlib_rigctld_path.value,
"hamlib_rigctld_server_port" : hamlib_rigctld_server_port.value, hamlib_rigctld_server_port: hamlib_rigctld_server_port.value,
"hamlib_rigctld_custom_args": hamlib_rigctld_custom_args.value, hamlib_rigctld_custom_args: hamlib_rigctld_custom_args.value,
"tci_port" : tci_port.value, tci_port: tci_port.value,
"tci_ip" : tci_ip.value, tci_ip: tci_ip.value,
"spectrum": spectrum.value, spectrum: spectrum.value,
"enable_scatter" : enable_scatter.value, enable_scatter: enable_scatter.value,
"enable_fft" : enable_fft.value, enable_fft: enable_fft.value,
"enable_fsk" : enable_fsk.value, enable_fsk: enable_fsk.value,
"low_bandwidth_mode" : low_bandwidth_mode.value, low_bandwidth_mode: low_bandwidth_mode.value,
"theme" : theme.value, theme: theme.value,
"screen_height" : screen_height.value, screen_height: screen_height.value,
"screen_width" : screen_width.value, screen_width: screen_width.value,
"update_channel" : update_channel.value, update_channel: update_channel.value,
"beacon_interval" : beacon_interval.value, beacon_interval: beacon_interval.value,
"received_files_folder" : received_files_folder.value, received_files_folder: received_files_folder.value,
"tuning_range_fmin" : tuning_range_fmin.value, tuning_range_fmin: tuning_range_fmin.value,
"tuning_range_fmax" : tuning_range_fmax.value, tuning_range_fmax: tuning_range_fmax.value,
"respond_to_cq" : respond_to_cq.value, respond_to_cq: respond_to_cq.value,
"rx_buffer_size" : rx_buffer_size.value, rx_buffer_size: rx_buffer_size.value,
"enable_explorer" : enable_explorer.value, enable_explorer: enable_explorer.value,
"wftheme": wftheme.value, wftheme: wftheme.value,
"high_graphics" : high_graphics.value, high_graphics: high_graphics.value,
"explorer_stats" : explorer_stats.value, explorer_stats: explorer_stats.value,
"auto_tune" : auto_tune.value, auto_tune: auto_tune.value,
"enable_is_writing" : enable_is_writing.value, enable_is_writing: enable_is_writing.value,
"shared_folder_path" : shared_folder_path.value, shared_folder_path: shared_folder_path.value,
"enable_request_profile" : enable_request_profile.value, enable_request_profile: enable_request_profile.value,
"enable_request_shared_folder" : enable_request_shared_folder.value, enable_request_shared_folder: enable_request_shared_folder.value,
"max_retry_attempts" : max_retry_attempts.value, max_retry_attempts: max_retry_attempts.value,
"enable_auto_retry" : enable_auto_retry.value, enable_auto_retry: enable_auto_retry.value,
"tx_delay" : tx_delay.value, tx_delay: tx_delay.value,
"auto_start": auto_start.value, auto_start: auto_start.value,
"enable_sys_notification": enable_sys_notification.value, enable_sys_notification: enable_sys_notification.value,
"enable_mesh_features": enable_mesh_features.value enable_mesh_features: enable_mesh_features.value,
};
return config_export;
} }
return config_export
}
return { return {
tnc_host, tnc_host,
tnc_port, tnc_port,
@ -207,7 +197,5 @@ var config_export = {
tx_delay, tx_delay,
enable_mesh_features, enable_mesh_features,
getJSON, getJSON,
};
} });
})

View file

@ -1,68 +1,62 @@
import { defineStore } from 'pinia' import { defineStore } from "pinia";
import { ref, computed } from 'vue'; import { ref, computed } from "vue";
import * as bootstrap from 'bootstrap' import * as bootstrap from "bootstrap";
export const useStateStore = defineStore('stateStore', () => { export const useStateStore = defineStore("stateStore", () => {
var busy_state = ref("-") var busy_state = ref("-");
var arq_state = ref("-") var arq_state = ref("-");
var frequency = ref("-") var frequency = ref("-");
var new_frequency = ref(0) var new_frequency = ref(0);
var mode = ref("-") var mode = ref("-");
var rf_level = ref("10") var rf_level = ref("10");
var bandwidth = ref("-") var bandwidth = ref("-");
var dbfs_level_percent = ref(0) var dbfs_level_percent = ref(0);
var dbfs_level_raw = ref(0) var dbfs_level_raw = ref(0);
var ptt_state = ref("False") var ptt_state = ref("False");
var speed_level = ref(0) var speed_level = ref(0);
var fft = ref() var fft = ref();
var channel_busy = ref("") var channel_busy = ref("");
var channel_busy_slot = ref() var channel_busy_slot = ref();
var scatter = ref() var scatter = ref();
var s_meter_strength_percent = ref(0) var s_meter_strength_percent = ref(0);
var s_meter_strength_raw = ref(0) var s_meter_strength_raw = ref(0);
var tnc_connection = ref("disconnected") var tnc_connection = ref("disconnected");
var tncStartCount = ref(0) var tncStartCount = ref(0);
var tnc_running_state = ref("--------") var tnc_running_state = ref("--------");
var arq_total_bytes = ref(0) var arq_total_bytes = ref(0);
var arq_transmission_percent = ref(0) var arq_transmission_percent = ref(0);
var heard_stations = ref("") var heard_stations = ref("");
var dxcallsign = ref("") var dxcallsign = ref("");
var arq_session_state = ref("") var arq_session_state = ref("");
var arq_state = ref("") var arq_state = ref("");
var beacon_state = ref("False") var beacon_state = ref("False");
var audio_recording = ref("") var audio_recording = ref("");
var hamlib_status = ref("") var hamlib_status = ref("");
var audio_level = ref("") var audio_level = ref("");
var alc = ref("") var alc = ref("");
var is_codec2_traffic = ref("") var is_codec2_traffic = ref("");
var arq_speed_list_timestamp = ref([]);
var arq_speed_list_bpm = ref([]);
var arq_speed_list_snr = ref([]);
var arq_seconds_until_finish = ref();
var arq_speed_list_timestamp = ref([]) var arq_seconds_until_timeout = ref();
var arq_speed_list_bpm = ref([]) var arq_seconds_until_timeout_percent = ref();
var arq_speed_list_snr = ref([])
var arq_seconds_until_finish = ref()
var arq_seconds_until_timeout = ref()
var arq_seconds_until_timeout_percent = ref()
function updateTncState(state) { function updateTncState(state) {
tnc_connection.value = state; tnc_connection.value = state;
if (tnc_connection.value == "open") { if (tnc_connection.value == "open") {
// collapse settings screen // collapse settings screen
var collapseFirstRow = new bootstrap.Collapse( var collapseFirstRow = new bootstrap.Collapse(
document.getElementById("collapseFirstRow"), document.getElementById("collapseFirstRow"),
@ -89,9 +83,8 @@ export const useStateStore = defineStore('stateStore', () => {
//set_CPU_mode(); //set_CPU_mode();
//GUI will auto connect to TNC if already running, if that is the case increment start count if 0 //GUI will auto connect to TNC if already running, if that is the case increment start count if 0
if (tncStartCount.value == 0) tncStartCount++; if (tncStartCount.value == 0) tncStartCount.value++;
} else { } else {
// collapse settings screen // collapse settings screen
var collapseFirstRow = new bootstrap.Collapse( var collapseFirstRow = new bootstrap.Collapse(
document.getElementById("collapseFirstRow"), document.getElementById("collapseFirstRow"),
@ -114,13 +107,38 @@ export const useStateStore = defineStore('stateStore', () => {
); );
collapseFourthRow.hide(); collapseFourthRow.hide();
} }
}
return {
dxcallsign,
busy_state,
arq_state,
new_frequency,
frequency,
mode,
bandwidth,
dbfs_level_raw,
dbfs_level_percent,
speed_level,
fft,
channel_busy,
channel_busy_slot,
scatter,
ptt_state,
s_meter_strength_percent,
s_meter_strength_raw,
arq_total_bytes,
audio_recording,
hamlib_status,
audio_level,
alc,
updateTncState,
arq_transmission_percent,
arq_speed_list_bpm,
arq_speed_list_timestamp,
arq_speed_list_snr,
arq_seconds_until_finish,
arq_seconds_until_timeout,
arq_seconds_until_timeout_percent,
}; };
return { dxcallsign, busy_state, arq_state, new_frequency, frequency, mode, bandwidth, dbfs_level_raw, dbfs_level_percent, speed_level, fft, channel_busy, channel_busy_slot, scatter, ptt_state, s_meter_strength_percent, s_meter_strength_raw, arq_total_bytes, audio_recording, hamlib_status, audio_level, alc, updateTncState, arq_transmission_percent, arq_speed_list_bpm, arq_speed_list_timestamp, arq_speed_list_snr, arq_seconds_until_finish, arq_seconds_until_timeout, arq_seconds_until_timeout_percent };
}); });