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>

File diff suppressed because it is too large Load diff

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) {
chat.selectedCallsign = callsign.toUpperCase();
function chatSelected(callsign){
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,
} catch(e){ );
console.log("beacon data not fetched: " + e) chat.beaconDataArray = Object.values(
chat.beaconLabelArray = [] chat.sorted_beacon_list[chat.selectedCallsign].snr,
chat.beaconDataArray = [] );
} } catch (e) {
console.log("beacon data not fetched: " + e);
console.log(chat.beaconDataArray) chat.beaconLabelArray = [];
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
<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)"> class="list-group-item list-group-item-action border-0 border-bottom rounded-0"
<div class="row"> :class="{ active: key == 0 }"
<div class="col-9">{{item}}</div> :id="`list-chat-list-${item}`"
<div class="col-3"> data-bs-toggle="list"
:href="`#list-${item}-messages`"
<button class="btn btn-sm btn-outline-danger ms-2" @click="deleteChat(item)"><i class="bi bi-trash"></i></button> role="tab"
aria-controls="list-{{item}}-messages"
@click="chatSelected(item)"
>
<div class="row">
</div> <div class="col-9">{{ item }}</div>
</div> <div class="col-3">
</a> <button
</template> class="btn btn-sm btn-outline-danger ms-2"
@click="deleteChat(item)"
>
<i class="bi bi-trash"></i>
</button>
</div>
</div>
</a>
</template>
<!--<chat_conversations_entry/>--> <!--<chat_conversations_entry/>-->
</div> </div>
</template> </template>

View file

@ -1,96 +1,96 @@
<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(
navigator.language, navigator.language,
{ {
hourCycle: "h23", hourCycle: "h23",
year: "numeric", year: "numeric",
month: "2-digit", month: "2-digit",
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 v-if="item.type === 'beacon' && item.status === 'received'">
{{item}}
</div>
<div v-if="item.type === 'ping'">
{{item.snr}}
{{chat.beaconDataArray}}
</div>
<div v-if="item.type === 'ping-ack'">
{{item.snr}}
{{chat.beaconDataArray}}
</div>
<div v-if="item.type === 'transmit'">
<sent-message :message="item" />
</div>
<div v-else-if="item.type === 'received'">
<received-message :message="item" />
</div>
<div v-if="item.type === 'broadcast_transmit'">
<sent-broadcast-message :message="item" />
</div>
<div v-else-if="item.type === 'broadcast_received'">
<received-broadcast-message :message="item" />
</div>
</template>
</div> </div>
</template>
<div v-if="item.type === 'beacon' && item.status === 'received'">
{{ item }}
</div>
<div v-if="item.type === 'ping'">
{{ item.snr }}
{{ chat.beaconDataArray }}
</div>
<div v-if="item.type === 'ping-ack'">
{{ item.snr }}
{{ chat.beaconDataArray }}
</div>
<div v-if="item.type === 'transmit'">
<sent-message :message="item" />
</div>
<div v-else-if="item.type === 'received'">
<received-message :message="item" />
</div>
<div v-if="item.type === 'broadcast_transmit'">
<sent-broadcast-message :message="item" />
</div>
<div v-else-if="item.type === 'broadcast_received'">
<received-broadcast-message :message="item" />
</div>
</template>
</div>
</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,81 +15,79 @@
</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
{{message.broadcast_sender}} class="position-absolute top-0 start-100 translate-middle badge rounded-1 bg-secondary border border-white"
</span> >
{{ message.broadcast_sender }}
</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: {
message: Object, message: Object,
}, },
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,63 +52,59 @@
</div> </div>
</template> </template>
<script> <script>
import {
import {repeatMessageTransmission, deleteMessageFromDB} from '../js/chatHandler' repeatMessageTransmission,
deleteMessageFromDB,
} from "../js/chatHandler";
export default { export default {
props: { props: {
message: Object, message: Object,
}, },
computed: { computed: {
getFileContent(){ getFileContent() {
var filename = Object.keys(this.message._attachments)[0];
var filesize = this.message._attachments[filename]["length"];
var filetype = filename.split(".")[1];
var filename = Object.keys(this.message._attachments)[0] // ensure filesize is 0 for hiding message header if no data is available
var filesize = this.message._attachments[filename]["length"] if (
var filetype = filename.split(".")[1] typeof filename === "undefined" ||
filename === "" ||
filename === "-" ||
filename === "null"
) {
filesize = 0;
}
// ensure filesize is 0 for hiding message header if no data is available return { filename: filename, filesize: filesize, filetype: filetype };
if (typeof filename === 'undefined' || filename === '' || filename === '-' || filename === 'null'){
filesize = 0
}
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,67 +15,63 @@
</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: {
message: Object, message: Object,
}, },
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,63 +55,58 @@
</div> </div>
</template> </template>
<script> <script>
import {
import {repeatMessageTransmission, deleteMessageFromDB} from '../js/chatHandler' repeatMessageTransmission,
deleteMessageFromDB,
} from "../js/chatHandler";
export default { export default {
props: { props: {
message: Object, message: Object,
}, },
computed: { computed: {
getFileContent(){ getFileContent() {
var filename = Object.keys(this.message._attachments)[0];
var filesize = this.message._attachments[filename]["length"];
var filetype = filename.split(".")[1];
var filename = Object.keys(this.message._attachments)[0] // ensure filesize is 0 for hiding message header if no data is available
var filesize = this.message._attachments[filename]["length"] if (
var filetype = filename.split(".")[1] typeof filename === "undefined" ||
filename === "" ||
filename === "-"
) {
filesize = 0;
}
// ensure filesize is 0 for hiding message header if no data is available return { filename: filename, filesize: filesize, filetype: filetype };
if (typeof filename === 'undefined' || filename === '' || filename === '-'){
filesize = 0
}
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,43 +35,43 @@ 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
pointDot : false, //remove the points markers pointDot: false, //remove the points markers
scaleShowGridLines: true, //set to false to remove the grids background scaleShowGridLines: true, //set to false to remove the grids background
maintainAspectRatio:true, maintainAspectRatio: true,
plugins:{ plugins: {
legend: { legend: {
display: false display: false,
}
}, },
},
scales: { scales: {
x: { x: {
position: "bottom", position: "bottom",
display: false, display: false,
min: -10, min: -10,
max: 15, max: 15,
ticks: { ticks: {
display: false, display: false,
}
},
y: {
display: false,
min: -5,
max: 10,
ticks: {
display: false,
}
},
}, },
}; },
y: {
display: false,
min: -5,
max: 10,
ticks: {
display: false,
},
},
},
};
//let dataArray = new Array(25).fill(0) //let dataArray = new Array(25).fill(0)
//dataArray = dataArray.add([-3, 10, 8, 5, 3, 0, -5]) //dataArray = dataArray.add([-3, 10, 8, 5, 3, 0, -5])
@ -82,100 +79,68 @@ ChartJS.register(
//console.log(dataArray1) //console.log(dataArray1)
//[-3, 10, 8, 5, 3, 0, -5] //[-3, 10, 8, 5, 3, 0, -5]
try {
chat.beaconLabelArray = Object.values(
chat.sorted_beacon_list["DJ2LS-0"].timestamp,
);
chat.beaconDataArray = Object.values(chat.sorted_beacon_list["DJ2LS-0"].snr);
} catch (e) {
console.log(e);
try{ var beaconLabels = [];
var beaconData = [];
chat.beaconLabelArray = Object.values(chat.sorted_beacon_list['DJ2LS-0'].timestamp)
chat.beaconDataArray = Object.values(chat.sorted_beacon_list['DJ2LS-0'].snr)
} catch(e){
console.log(e)
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) {
let callsign = document.getElementById("chatModuleNewDxCall").value;
callsign = callsign.toUpperCase();
chat.callsign_list.add(callsign);
} }
));
function newChat(obj){
let callsign = document.getElementById("chatModuleNewDxCall").value
callsign = callsign.toUpperCase()
chat.callsign_list.add(callsign)
}
</script> </script>
<template> <template>
<nav class="navbar bg-body-tertiary border-bottom"> <nav class="navbar bg-body-tertiary border-bottom">
<div class="container"> <div class="container">
<div class="row w-100"> <div class="row w-100">
<div class="col-4 p-0 me-2"> <div class="col-4 p-0 me-2">
<div class="input-group bottom-0 m-0"> <div class="input-group bottom-0 m-0">
<input <input
class="form-control w-50" class="form-control w-50"
maxlength="9" maxlength="9"
style="text-transform: uppercase" style="text-transform: uppercase"
id="chatModuleNewDxCall" id="chatModuleNewDxCall"
placeholder="DX CALL" placeholder="DX CALL"
/> />
<button <button
class="btn btn-sm btn-success" class="btn btn-sm btn-success"
id="createNewChatButton" id="createNewChatButton"
type="button" type="button"
title="Start a new chat (enter dx call sign first)" title="Start a new chat (enter dx call sign first)"
@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" </button>
style="font-size: 1.2rem" </div>
></i> </div>
</button> <div class="col-7 ms-2 p-0">
<!-- right side of chat nav bar-->
{{ beaconData }}
</div> <Bar
</div> :data="beaconHistogramData"
<div class="col-7 ms-2 p-0"> :options="beaconHistogramOptions"
width="300"
<!-- right side of chat nav bar--> style="height: 100%"
{{beaconData}} />
<Bar :data="beaconHistogramData" :options="beaconHistogramOptions" width="300" style="height:100%" /> </div>
</div>
</div>
</nav>
</div>
</div>
</div>
</nav>
</template> </template>

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() {
console.log("stopping transmissions");
function stopAllTransmissions(){ stopTransmission();
console.log("stopping transmissions")
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"
@ -345,7 +325,7 @@ function stopAllTransmissions(){
</div> </div>
</nav> </nav>
<div class="tab-content d-none" id="nav-tabContent-Mesh"> <div class="tab-content d-none" id="nav-tabContent-Mesh">
<div <div
class="tab-pane fade show active vw-100 vh-90 overflow-auto" class="tab-pane fade show active vw-100 vh-90 overflow-auto"
id="nav-route" id="nav-route"
@ -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"
@ -537,10 +516,7 @@ function stopAllTransmissions(){
role="tabpanel" role="tabpanel"
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,188 +1,193 @@
<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() {
record_audio();
function startStopRecordAudio(){
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> </div>
</div> <div class="col-3">
<div class="col-3"> <strong class="fs-5">Audio</strong>
<strong class="fs-5">Audio</strong> </div>
</div> <div class="col-7">
<div class="col-7"> <button
<button type="button"
type="button" id="audioModalButton"
id="audioModalButton" data-bs-toggle="modal"
data-bs-toggle="modal" data-bs-target="#audioModal"
data-bs-target="#audioModal" class="btn btn-sm btn-outline-secondary me-1"
class="btn btn-sm btn-outline-secondary me-1" >
> Tune
Tune </button>
</button> <button
<button type="button"
type="button" id="startStopRecording"
id="startStopRecording" class="btn btn-sm"
class="btn btn-sm" @click="startStopRecordAudio()"
@click="startStopRecordAudio()" v-bind:class="{
v-bind:class="{ 'btn-outline-secondary' : state.audio_recording === 'False', 'btn-outline-secondary': state.audio_recording === 'False',
'btn-secondary' : state.audio_recording === 'True'}" 'btn-secondary': state.audio_recording === 'True',
> }"
Record >
</button> Record
</div> </button>
<div class="col-1 text-end"> </div>
<button <div class="col-1 text-end">
type="button" <button
id="openHelpModalAudioLevel" type="button"
data-bs-toggle="modal" id="openHelpModalAudioLevel"
data-bs-target="#audioLevelHelpModal" data-bs-toggle="modal"
class="btn m-0 p-0 border-0" data-bs-target="#audioLevelHelpModal"
> class="btn m-0 p-0 border-0"
<i >
class="bi bi-question-circle" <i class="bi bi-question-circle" style="font-size: 1rem"></i>
style="font-size: 1rem" </button>
></i> </div>
</button> </div>
</div> </div>
</div> </div>
</div> <div class="card-body p-2">
</div> <div class="container">
<div class="card-body p-2"> <div class="row">
<div class="container"> <div class="col-sm">
<div class="row"> <div
<div class="col-sm"> class="progress mb-0 rounded-0 rounded-top"
<div class="progress mb-0 rounded-0 rounded-top" style="height: 22px"> style="height: 22px"
<div >
class="progress-bar progress-bar-striped bg-primary force-gpu" <div
id="noise_level" class="progress-bar progress-bar-striped bg-primary force-gpu"
role="progressbar" id="noise_level"
:style="{ width: state.s_meter_strength_percent + '%' }" role="progressbar"
aria-valuenow="{{state.s_meter_strength_percent}}" :style="{ width: state.s_meter_strength_percent + '%' }"
aria-valuemin="0" aria-valuenow="{{state.s_meter_strength_percent}}"
aria-valuemax="100" aria-valuemin="0"
></div> aria-valuemax="100"
<p ></div>
class="justify-content-center d-flex position-absolute w-100" <p
id="noise_level_value" class="justify-content-center d-flex position-absolute w-100"
> id="noise_level_value"
S-Meter(dB): {{state.s_meter_strength_raw}} >
</p> S-Meter(dB): {{ state.s_meter_strength_raw }}
</div> </p>
<div class="progress mb-0 rounded-0 rounded-bottom" style="height: 8px">
<div
class="progress-bar progress-bar-striped bg-warning"
role="progressbar"
style="width: 1%"
aria-valuenow="1"
aria-valuemin="0"
aria-valuemax="100"
></div>
<div
class="progress-bar bg-success"
role="progressbar"
style="width: 89%"
aria-valuenow="50"
aria-valuemin="0"
aria-valuemax="100"
></div>
<div
class="progress-bar progress-bar-striped bg-warning"
role="progressbar"
style="width: 20%"
aria-valuenow="20"
aria-valuemin="0"
aria-valuemax="100"
></div>
<div
class="progress-bar progress-bar-striped bg-danger"
role="progressbar"
style="width: 29%"
aria-valuenow="29"
aria-valuemin="0"
aria-valuemax="100"
></div>
</div>
</div>
<div class="col-sm">
<div class="progress mb-0 rounded-0 rounded-top" style="height: 22px">
<div
class="progress-bar progress-bar-striped bg-primary force-gpu"
id="dbfs_level"
role="progressbar"
:style="{ width: state.dbfs_level_percent + '%' }"
aria-valuenow="0"
aria-valuemin="0"
aria-valuemax="100"
></div>
<p
class="justify-content-center d-flex position-absolute w-100"
id="dbfs_level_value"
>
{{state.dbfs_level}} dBFS
</p>
</div>
<div class="progress mb-0 rounded-0 rounded-bottom" style="height: 8px">
<div
class="progress-bar progress-bar-striped bg-warning"
role="progressbar"
style="width: 1%"
aria-valuenow="1"
aria-valuemin="0"
aria-valuemax="100"
></div>
<div
class="progress-bar bg-success"
role="progressbar"
style="width: 89%"
aria-valuenow="50"
aria-valuemin="0"
aria-valuemax="100"
></div>
<div
class="progress-bar progress-bar-striped bg-warning"
role="progressbar"
style="width: 20%"
aria-valuenow="20"
aria-valuemin="0"
aria-valuemax="100"
></div>
<div
class="progress-bar progress-bar-striped bg-danger"
role="progressbar"
style="width: 29%"
aria-valuenow="29"
aria-valuemin="0"
aria-valuemax="100"
></div>
</div>
</div>
</div>
</div>
</div>
</div> </div>
</template> <div
class="progress mb-0 rounded-0 rounded-bottom"
style="height: 8px"
>
<div
class="progress-bar progress-bar-striped bg-warning"
role="progressbar"
style="width: 1%"
aria-valuenow="1"
aria-valuemin="0"
aria-valuemax="100"
></div>
<div
class="progress-bar bg-success"
role="progressbar"
style="width: 89%"
aria-valuenow="50"
aria-valuemin="0"
aria-valuemax="100"
></div>
<div
class="progress-bar progress-bar-striped bg-warning"
role="progressbar"
style="width: 20%"
aria-valuenow="20"
aria-valuemin="0"
aria-valuemax="100"
></div>
<div
class="progress-bar progress-bar-striped bg-danger"
role="progressbar"
style="width: 29%"
aria-valuenow="29"
aria-valuemin="0"
aria-valuemax="100"
></div>
</div>
</div>
<div class="col-sm">
<div
class="progress mb-0 rounded-0 rounded-top"
style="height: 22px"
>
<div
class="progress-bar progress-bar-striped bg-primary force-gpu"
id="dbfs_level"
role="progressbar"
:style="{ width: state.dbfs_level_percent + '%' }"
aria-valuenow="0"
aria-valuemin="0"
aria-valuemax="100"
></div>
<p
class="justify-content-center d-flex position-absolute w-100"
id="dbfs_level_value"
>
{{ state.dbfs_level }} dBFS
</p>
</div>
<div
class="progress mb-0 rounded-0 rounded-bottom"
style="height: 8px"
>
<div
class="progress-bar progress-bar-striped bg-warning"
role="progressbar"
style="width: 1%"
aria-valuenow="1"
aria-valuemin="0"
aria-valuemax="100"
></div>
<div
class="progress-bar bg-success"
role="progressbar"
style="width: 89%"
aria-valuenow="50"
aria-valuemin="0"
aria-valuemax="100"
></div>
<div
class="progress-bar progress-bar-striped bg-warning"
role="progressbar"
style="width: 20%"
aria-valuenow="20"
aria-valuemin="0"
aria-valuemax="100"
></div>
<div
class="progress-bar progress-bar-striped bg-danger"
role="progressbar"
style="width: 29%"
aria-valuenow="29"
aria-valuemin="0"
aria-valuemax="100"
></div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>

View file

@ -1,130 +1,121 @@
<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;
case 'True':
stopBeacon()
break;
default:
}
break;
case "True":
stopBeacon();
break;
default:
}
} }
</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-broadcast" style="font-size: 1.2rem"></i> <i class="bi bi-broadcast" style="font-size: 1.2rem"></i>
</div> </div>
<div class="col-10"> <div class="col-10">
<strong class="fs-5">Broadcasts</strong> <strong class="fs-5">Broadcasts</strong>
</div> </div>
<div class="col-1 text-end"> <div class="col-1 text-end">
<button <button
type="button" type="button"
id="openHelpModalBroadcasts" id="openHelpModalBroadcasts"
data-bs-toggle="modal" data-bs-toggle="modal"
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" </button>
style="font-size: 1rem" </div>
></i> </div>
</button> </div>
</div> </div>
</div> <div class="card-body p-2">
</div> <div class="row">
</div> <div class="col-md-auto">
<div class="card-body p-2"> <div class="input-group input-group-sm mb-0">
<div class="row"> <input
<div class="col-md-auto"> type="text"
<div class="input-group input-group-sm mb-0"> class="form-control"
<input style="max-width: 6rem; text-transform: uppercase"
type="text" placeholder="DXcall"
class="form-control" pattern="[A-Z]*"
style="max-width: 6rem; text-transform: uppercase" id="dxCall"
placeholder="DXcall" maxlength="11"
pattern="[A-Z]*" aria-label="Input group"
id="dxCall" aria-describedby="btnGroupAddon"
maxlength="11" />
aria-label="Input group" <button
aria-describedby="btnGroupAddon" class="btn btn-sm btn-outline-secondary ms-1"
/> id="sendPing"
<button type="button"
class="btn btn-sm btn-outline-secondary ms-1" data-bs-placement="bottom"
id="sendPing" data-bs-toggle="tooltip"
type="button" data-bs-trigger="hover"
data-bs-placement="bottom" data-bs-html="false"
data-bs-toggle="tooltip" title="Send a ping request to a remote station"
data-bs-trigger="hover" @click="transmitPing()"
data-bs-html="false" >
title="Send a ping request to a remote station" Ping
@click="transmitPing()" </button>
>
Ping
</button>
<button
class="btn btn-sm btn-outline-secondary ms-1"
id="sendCQ"
type="button"
title="Send a CQ to the world"
@click="transmitCQ()"
>
Call CQ
</button>
<button <button
class="btn btn-sm btn-outline-secondary ms-1" type="button"
id="sendCQ" id="startBeacon"
type="button" class="btn btn-sm ms-1"
title="Send a CQ to the world" @click="startStopBeacon()"
@click="transmitCQ()" v-bind:class="{
> 'btn-success': state.beacon_state === 'True',
Call CQ 'btn-outline-secondary': state.beacon_state === 'False',
</button> }"
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."
<button >
type="button" <i class="bi bi-soundwave"></i> Toggle beacon
id="startBeacon" </button>
class="btn btn-sm ms-1" </div>
@click="startStopBeacon()" </div>
v-bind:class="{ 'btn-success' : state.beacon_state === 'True', </div>
'btn-outline-secondary' : state.beacon_state === 'False'}" <!-- end of row-->
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." </div>
> </div>
<i class="bi bi-soundwave"></i> Toggle beacon
</button>
</div>
</div>
</div>
<!-- end of row-->
</div>
</div>
</template> </template>

View file

@ -1,5 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
const { const {
locatorToLatLng, locatorToLatLng,
distance, distance,
@ -7,119 +6,106 @@ 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, {
{ hourCycle: "h23",
hourCycle: "h23", year: "numeric",
year: "numeric", month: "2-digit",
month: "2-digit", day: "2-digit",
day: "2-digit", hour: "2-digit",
hour: "2-digit", minute: "2-digit",
minute: "2-digit", second: "2-digit",
second: "2-digit", },
}, );
); return datetime;
return datetime
} }
function getMaidenheadDistance(dxGrid){ function getMaidenheadDistance(dxGrid) {
try{ try {
return parseInt(distance(settings.mygrid, dxGrid)); return parseInt(distance(settings.mygrid, dxGrid));
}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 class="bi bi-list-columns-reverse" style="font-size: 1.2rem"></i>
<i </div>
class="bi bi-list-columns-reverse" <div class="col-10">
style="font-size: 1.2rem" <strong class="fs-5">Heard stations</strong>
></i> </div>
</div> <div class="col-1 text-end">
<div class="col-10"> <button
<strong class="fs-5">Heard stations</strong> type="button"
</div> id="openHelpModalHeardStations"
<div class="col-1 text-end"> data-bs-toggle="modal"
<button data-bs-target="#heardStationsHelpModal"
type="button" class="btn m-0 p-0 border-0"
id="openHelpModalHeardStations" >
data-bs-toggle="modal" <i class="bi bi-question-circle" style="font-size: 1rem"></i>
data-bs-target="#heardStationsHelpModal" </button>
class="btn m-0 p-0 border-0" </div>
> </div>
<i </div>
class="bi bi-question-circle" </div>
style="font-size: 1rem" <div class="card-body p-0" style="overflow-y: overlay">
></i> <div class="table-responsive">
</button> <!-- START OF TABLE FOR HEARD STATIONS -->
</div> <table class="table table-sm" id="tblHeardStationList">
</div> <thead>
</div> <tr>
</div> <th scope="col" id="thTime">
<div class="card-body p-0" style="overflow-y: overlay"> <i id="hslSort" class="bi bi-sort-up"></i>Time
<div class="table-responsive"> </th>
<!-- START OF TABLE FOR HEARD STATIONS --> <th scope="col" id="thFreq">Frequency</th>
<table class="table table-sm" id="tblHeardStationList"> <th>&nbsp;</th>
<thead> <th scope="col" id="thDxcall">DXCall</th>
<tr> <th scope="col" id="thDxgrid">DXGrid</th>
<th scope="col" id="thTime"> <th scope="col" id="thDist">Distance</th>
<i id="hslSort" class="bi bi-sort-up"></i>Time <th scope="col" id="thType">Type</th>
</th> <th scope="col" id="thSnr">SNR (rx/dx)</th>
<th scope="col" id="thFreq">Frequency</th> <!--<th scope="col">Off</th>-->
<th>&nbsp;</th> </tr>
<th scope="col" id="thDxcall">DXCall</th> </thead>
<th scope="col" id="thDxgrid">DXGrid</th> <tbody id="heardstations">
<th scope="col" id="thDist">Distance</th> <!--https://vuejs.org/guide/essentials/list.html-->
<th scope="col" id="thType">Type</th> <tr v-for="item in state.heard_stations" :key="item.timestamp">
<th scope="col" id="thSnr">SNR (rx/dx)</th> <td>{{ getDateTime(item.timestamp) }}</td>
<!--<th scope="col">Off</th>--> <td>{{ item.frequency }}</td>
</tr> <td>&nbsp;</td>
</thead> <td>
<tbody id="heardstations"> <span class="badge bg-secondary">{{ item.dxcallsign }}</span>
<!--https://vuejs.org/guide/essentials/list.html--> </td>
<tr v-for="item in state.heard_stations" :key="item.timestamp"> <td>{{ item.dxgrid }}</td>
<td>{{ getDateTime(item.timestamp) }}</td> <td>{{ getMaidenheadDistance(item.dxgrid) }} km</td>
<td>{{ item.frequency }}</td> <td>{{ item.datatype }}</td>
<td>&nbsp;</td> <td>{{ item.snr }}</td>
<td><span class="badge bg-secondary">{{ item.dxcallsign }}</span></td> <!--<td>{{ item.offset }}</td>-->
<td>{{ item.dxgrid }}</td> </tr>
<td>{{ getMaidenheadDistance(item.dxgrid)}} km</td> </tbody>
<td>{{ item.datatype }}</td> </table>
<td>{{ item.snr }}</td> </div>
<!--<td>{{ item.offset }}</td>--> <!-- END OF HEARD STATIONS TABLE -->
</tr> </div>
</tbody> </div>
</table> </template>
</div>
<!-- END OF HEARD STATIONS TABLE -->
</div>
</div>
</template>

View file

@ -1,175 +1,155 @@
<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="row">
<div class="col-1">
<div class="container"> <i class="bi bi-house-door" style="font-size: 1.2rem"></i>
<div class="row">
<div class="col-1">
<i class="bi bi-house-door" style="font-size: 1.2rem"></i>
</div>
<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',
'text-bg-danger disabled' : state.hamlib_status === 'disconnected'}">{{state.hamlib_status}}</span>
</div>
<div class="col-1 text-end">
<button
type="button"
id="openHelpModalStation"
data-bs-toggle="modal"
data-bs-target="#stationHelpModal"
class="btn m-0 p-0 border-0"
disabled
>
<i
class="bi bi-question-circle"
style="font-size: 1rem"
></i>
</button>
</div>
</div>
</div>
</div>
<div class="card-body p-2">
<div class="input-group bottom-0 m-0">
<div class="me-2">
<div class="input-group">
<span class="input-group-text">QRG</span>
<span class="input-group-text">{{state.frequency}} Hz</span>
<span class="input-group-text">QSY</span>
<input 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">
<option selected value="7053000">40m | USB | EU, US</option>
<option value="14093000">20m | USB | EU, US</option>
<option value="21093000">15m | USB | EU, US</option>
<option value="24908000">12m | USB | EU, US</option>
<option value="28093000">10m | USB | EU, US</option>
<option value="50308000">6m | USB | US</option>
<option value="50616000">6m | USB | EU, US</option>
</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>
</div>
</div>
<div class="me-2">
<div class="input-group">
<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'}">
<option value="USB">USB</option>
<option value="LSB">LSB</option>
<option value="AM">AM</option>
<option value="FM">FM</option>
</select>
</div>
</div>
<div class="me-2">
<div class="input-group">
<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'}">
<option value="0">-</option>
<option value="10">10</option>
<option value="20">20</option>
<option value="30">30</option>
<option value="40">40</option>
<option value="50">50</option>
<option value="60">60</option>
<option value="70">70</option>
<option value="80">80</option>
<option value="90">90</option>
<option value="100">100</option>
</select>
<span class="input-group-text" >%</span>
</div>
</div>
</div> </div>
<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',
'text-bg-danger disabled':
state.hamlib_status === 'disconnected',
}"
>{{ state.hamlib_status }}</span
>
</div>
<div class="col-1 text-end">
<button
type="button"
id="openHelpModalStation"
data-bs-toggle="modal"
data-bs-target="#stationHelpModal"
class="btn m-0 p-0 border-0"
disabled
>
<i class="bi bi-question-circle" style="font-size: 1rem"></i>
</button>
</div>
</div>
</div>
</div>
<div class="card-body p-2">
<div class="input-group bottom-0 m-0">
<div class="me-2">
<div class="input-group">
<span class="input-group-text">QRG</span>
<span class="input-group-text">{{ state.frequency }} Hz</span>
<span class="input-group-text">QSY</span>
<input
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">
<option selected value="7053000">40m | USB | EU, US</option>
<option value="14093000">20m | USB | EU, US</option>
<option value="21093000">15m | USB | EU, US</option>
<option value="24908000">12m | USB | EU, US</option>
<option value="28093000">10m | USB | EU, US</option>
<option value="50308000">6m | USB | US</option>
<option value="50616000">6m | USB | EU, US</option>
</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>
</div>
</div>
<div class="me-2">
<div class="input-group">
<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',
}"
>
<option value="USB">USB</option>
<option value="LSB">LSB</option>
<option value="AM">AM</option>
<option value="FM">FM</option>
</select>
</div>
</div>
<div class="me-2">
<div class="input-group">
<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',
}"
>
<option value="0">-</option>
<option value="10">10</option>
<option value="20">20</option>
<option value="30">30</option>
<option value="40">40</option>
<option value="50">50</option>
<option value="60">60</option>
<option value="70">70</option>
<option value="80">80</option>
<option value="90">90</option>
<option value="100">100</option>
</select>
<span class="input-group-text">%</span>
</div> </div>
</div></div> </div>
</template> </div>
</div>
</div>
</div>
</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,42 +19,31 @@ 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){
switch (obj.delegateTarget.id) {
case 'list-waterfall-list':
settings.spectrum = "waterfall"
break;
case 'list-scatter-list':
settings.spectrum = "scatter"
break;
case 'list-chart-list':
settings.spectrum = "chart"
break;
default:
settings.spectrum = "waterfall"
}
saveSettingsToFile()
function selectStatsControl(obj) {
switch (obj.delegateTarget.id) {
case "list-waterfall-list":
settings.spectrum = "waterfall";
break;
case "list-scatter-list":
settings.spectrum = "scatter";
break;
case "list-chart-list":
settings.spectrum = "chart";
break;
default:
settings.spectrum = "waterfall";
}
saveSettingsToFile();
} }
var transmissionSpeedChartOptions = {
type: "line",
var transmissionSpeedChartOptions = { };
type: "line",
};
ChartJS.register( ChartJS.register(
CategoryScale, CategoryScale,
@ -66,81 +52,77 @@ 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) =>
speedCtx.p0.skip || speedCtx.p1.skip ? value : undefined; speedCtx.p0.skip || speedCtx.p1.skip ? value : undefined;
const down = (speedCtx, value) => const down = (speedCtx, value) =>
speedCtx.p0.parsed.y > speedCtx.p1.parsed.y ? value : undefined; speedCtx.p0.parsed.y > speedCtx.p1.parsed.y ? value : undefined;
var transmissionSpeedChartOptions = { var transmissionSpeedChartOptions = {
responsive: true, responsive: true,
animations: true, animations: true,
cubicInterpolationMode: "monotone", cubicInterpolationMode: "monotone",
tension: 0.4, tension: 0.4,
scales: { scales: {
SNR: { SNR: {
type: "linear", type: "linear",
ticks: { beginAtZero: false, color: "rgb(255, 99, 132)" }, ticks: { beginAtZero: false, color: "rgb(255, 99, 132)" },
position: "right", position: "right",
},
SPEED: {
type: "linear",
ticks: { beginAtZero: false, color: "rgb(120, 100, 120)" },
position: "left",
grid: {
drawOnChartArea: false, // only want the grid lines for one axis to show up
},
},
x: { ticks: { beginAtZero: true } },
}, },
}; SPEED: {
type: "linear",
ticks: { beginAtZero: false, color: "rgb(120, 100, 120)" },
position: "left",
grid: {
drawOnChartArea: false, // only want the grid lines for one axis to show up
},
},
x: { ticks: { beginAtZero: true } },
},
};
const transmissionSpeedChartData = computed(() => ({ const transmissionSpeedChartData = computed(() => ({
labels: state.arq_speed_list_timestamp, labels: state.arq_speed_list_timestamp,
datasets: [ datasets: [
{ {
type: "line", type: "line",
label: "SNR[dB]", label: "SNR[dB]",
data: state.arq_speed_list_snr, data: state.arq_speed_list_snr,
borderColor: "rgb(75, 192, 192, 1.0)", borderColor: "rgb(75, 192, 192, 1.0)",
pointRadius: 1, pointRadius: 1,
segment: { segment: {
borderColor: (speedCtx) => borderColor: (speedCtx) =>
skipped(speedCtx, "rgb(0,0,0,0.4)") || skipped(speedCtx, "rgb(0,0,0,0.4)") ||
down(speedCtx, "rgb(192,75,75)"), down(speedCtx, "rgb(192,75,75)"),
borderDash: (speedCtx) => skipped(speedCtx, [3, 3]), borderDash: (speedCtx) => skipped(speedCtx, [3, 3]),
},
spanGaps: true,
backgroundColor: "rgba(75, 192, 192, 0.2)",
order: 1,
yAxisID: "SNR",
}, },
{ spanGaps: true,
type: "bar", backgroundColor: "rgba(75, 192, 192, 0.2)",
label: "Speed[bpm]", order: 1,
data: state.arq_speed_list_bpm, yAxisID: "SNR",
borderColor: "rgb(120, 100, 120, 1.0)", },
backgroundColor: "rgba(120, 100, 120, 0.2)", {
order: 0, type: "bar",
yAxisID: "SPEED", label: "Speed[bpm]",
}, data: state.arq_speed_list_bpm,
] borderColor: "rgb(120, 100, 120, 1.0)",
} backgroundColor: "rgba(120, 100, 120, 0.2)",
)); order: 0,
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>
@ -276,7 +269,7 @@ const scatterChartData = computed(() => ({
<div class="tab-content" id="nav-stats-tabContent"> <div class="tab-content" id="nav-stats-tabContent">
<div <div
class="tab-pane fade" class="tab-pane fade"
v-bind:class="{ 'show active' : settings.spectrum === 'waterfall'}" v-bind:class="{ 'show active': settings.spectrum === 'waterfall' }"
id="list-waterfall" id="list-waterfall"
role="stats_tabpanel" role="stats_tabpanel"
aria-labelledby="list-waterfall-list" aria-labelledby="list-waterfall-list"
@ -289,17 +282,16 @@ const scatterChartData = computed(() => ({
</div> </div>
<div <div
class="tab-pane fade" class="tab-pane fade"
v-bind:class="{ 'show active' : settings.spectrum === 'scatter'}" v-bind:class="{ 'show active': settings.spectrum === 'scatter' }"
id="list-scatter" id="list-scatter"
role="tabpanel" role="tabpanel"
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"
v-bind:class="{ 'show active' : settings.spectrum === 'chart'}" v-bind:class="{ 'show active': settings.spectrum === 'chart' }"
id="list-chart" id="list-chart"
role="tabpanel" role="tabpanel"
aria-labelledby="list-chart-list" aria-labelledby="list-chart-list"

View file

@ -1,73 +1,61 @@
<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-header p-1">
<div class="container">
<div class="row">
<div class="col-1">
<i class="bi bi-volume-up" style="font-size: 1.2rem"></i>
</div>
<div class="col-10">
<strong class="fs-5">Audio devices</strong>
</div>
<div class="col-1 text-end">
<button
type="button"
id="openHelpModalAudio"
data-bs-toggle="modal"
data-bs-target="#audioHelpModal"
class="btn m-0 p-0 border-0"
>
<i class="bi bi-question-circle" style="font-size: 1rem"></i>
</button>
</div>
</div>
</div>
</div>
<div class="card-body p-2" style="height: 100px">
<div class="card mb-0"> <div class="input-group input-group-sm mb-1">
<div class="card-header p-1"> <span class="input-group-text">
<div class="container"> <i class="bi bi-mic-fill" style="font-size: 1rem"></i>
<div class="row"> </span>
<div class="col-1"> <select
<i class="bi bi-volume-up" style="font-size: 1.2rem"></i> class="form-select form-select-sm"
</div> id="audio_input_selectbox"
<div class="col-10"> aria-label=".form-select-sm"
<strong class="fs-5">Audio devices</strong> v-html="audio.getInputDevices()"
</div> ></select>
<div class="col-1 text-end"> </div>
<button <div class="input-group input-group-sm">
type="button" <span class="input-group-text">
id="openHelpModalAudio" <i class="bi bi-volume-up" style="font-size: 1rem"></i>
data-bs-toggle="modal" </span>
data-bs-target="#audioHelpModal" <select
class="btn m-0 p-0 border-0" class="form-select form-select-sm"
> id="audio_output_selectbox"
<i aria-label=".form-select-sm"
class="bi bi-question-circle" v-html="audio.getOutputDevices()"
style="font-size: 1rem" ></select>
></i> </div>
</button> </div>
</div> </div>
</div> </template>
</div>
</div>
<div class="card-body p-2" style="height: 100px">
<div class="input-group input-group-sm mb-1">
<span class="input-group-text">
<i class="bi bi-mic-fill" style="font-size: 1rem"></i>
</span>
<select
class="form-select form-select-sm"
id="audio_input_selectbox"
aria-label=".form-select-sm"
v-html="audio.getInputDevices()"
>
</select>
</div>
<div class="input-group input-group-sm">
<span class="input-group-text">
<i class="bi bi-volume-up" style="font-size: 1rem"></i>
</span>
<select
class="form-select form-select-sm"
id="audio_output_selectbox"
aria-label=".form-select-sm"
v-html="audio.getOutputDevices()"
>
</select>
</div>
</div>
</div>
</template>

View file

@ -1,89 +1,93 @@
<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>
<nav <nav
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="btn-toolbar" role="toolbar" style="margin-left: 2px">
<div class="btn-group btn-group-sm me-1" role="group">
<button
class="btn btn-sm btn-secondary me-1"
v-bind:class="{
'bg-danger': state.ptt_state === 'True',
'bg-success': state.ptt_state === 'False',
}"
id="ptt_state"
type="button"
data-bs-placement="top"
data-bs-toggle="tooltip"
data-bs-trigger="hover"
data-bs-html="true"
title="PTT state:<strong class='text-success'>RECEIVING</strong> / <strong class='text-danger'>TRANSMITTING</strong>"
>
<i class="bi bi-broadcast-pin" style="font-size: 0.8rem"></i>
</button>
<div class="col"> <button
<div class="btn-toolbar" role="toolbar" style="margin-left: 2px"> class="btn btn-sm btn-secondary me-1"
<div class="btn-group btn-group-sm me-1" role="group"> id="busy_state"
<button type="button"
class="btn btn-sm btn-secondary me-1" data-bs-placement="top"
v-bind:class="{ 'bg-danger' : state.ptt_state === 'True', 'bg-success' : state.ptt_state === 'False'}" data-bs-toggle="tooltip"
id="ptt_state" data-bs-trigger="hover"
type="button" data-bs-html="true"
data-bs-placement="top" v-bind:class="{
data-bs-toggle="tooltip" 'bg-danger': state.busy_state === 'BUSY',
data-bs-trigger="hover" 'bg-success': state.busy_state === 'IDLE',
data-bs-html="true" }"
title="PTT state:<strong class='text-success'>RECEIVING</strong> / <strong class='text-danger'>TRANSMITTING</strong>" title="TNC busy state: <strong class='text-success'>IDLE</strong> / <strong class='text-danger'>BUSY</strong>"
> >
<i class="bi bi-broadcast-pin" style="font-size: 0.8rem"></i> <i class="bi bi-cpu" style="font-size: 0.8rem"></i>
</button> </button>
<button <button
class="btn btn-sm btn-secondary me-1" class="btn btn-sm btn-secondary me-1"
id="busy_state" id="arq_session"
type="button" type="button"
data-bs-placement="top" data-bs-placement="top"
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'}" title="ARQ SESSION state: <strong class='text-warning'>OPEN</strong>"
title="TNC busy state: <strong class='text-success'>IDLE</strong> / <strong class='text-danger'>BUSY</strong>" v-bind:class="{
> 'bg-secondary': state.arq_session_state === 'disconnected',
<i class="bi bi-cpu" style="font-size: 0.8rem"></i> 'bg-success': state.arq_session_state === 'connected',
</button> }"
>
<i class="bi bi-arrow-left-right" style="font-size: 0.8rem"></i>
</button>
<button <button
class="btn btn-sm btn-secondary me-1" class="btn btn-sm btn-secondary me-1"
id="arq_session" id="arq_state"
type="button" type="button"
data-bs-placement="top" data-bs-placement="top"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
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="DATA-CHANNEL 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_state === 'False',
<i class="bi bi-arrow-left-right" style="font-size: 0.8rem"></i> 'bg-success': state.arq_state === 'True',
</button> }"
>
<button <i class="bi bi-file-earmark-binary" style="font-size: 0.8rem"></i>
class="btn btn-sm btn-secondary me-1" </button>
id="arq_state" <!--
type="button"
data-bs-placement="top"
data-bs-toggle="tooltip"
data-bs-trigger="hover"
data-bs-html="true"
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'}"
>
<i
class="bi bi-file-earmark-binary"
style="font-size: 0.8rem"
></i>
</button>
<!--
<button <button
class="btn btn-sm btn-secondary me-1" class="btn btn-sm btn-secondary me-1"
id="rigctld_state" id="rigctld_state"
@ -98,190 +102,158 @@ const settings = useSettingsStore(pinia);
</button> </button>
--> -->
<button <button
class="btn btn-sm disabled me-3" class="btn btn-sm disabled me-3"
type="button" type="button"
data-bs-placement="top" data-bs-placement="top"
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="{
title="Channel busy state: <strong class='text-success'>not busy</strong> / <strong class='text-danger'>busy </strong>" 'btn-warning': state.channel_busy === 'True',
> 'btn-secondary': state.channel_busy === 'False',
<i class="bi bi-hourglass"></i> }"
</button> title="Channel busy state: <strong class='text-success'>not busy</strong> / <strong class='text-danger'>busy </strong>"
>
<i class="bi bi-hourglass"></i>
</button>
</div>
</div> <div class="btn-group btn-group-sm me-1" role="group">
<button
class="btn btn-sm btn-secondary me-4 disabled"
type="button"
data-bs-placement="top"
data-bs-toggle="tooltip"
data-bs-trigger="hover"
data-bs-html="true"
>
{{ state.frequency }} Hz
</button>
</div>
<div class="btn-group btn-group-sm me-1" role="group">
<button
class="btn btn-sm btn-secondary me-0"
type="button"
data-bs-placement="top"
data-bs-toggle="tooltip"
data-bs-trigger="hover"
data-bs-html="true"
>
<i class="bi bi-speedometer2" style="font-size: 1rem"></i>
</button>
<button
class="btn btn-sm btn-secondary me-4 disabled"
type="button"
data-bs-placement="top"
data-bs-toggle="tooltip"
data-bs-trigger="hover"
data-bs-html="true"
>
<i
class="bi"
style="font-size: 1rem"
v-bind:class="{
'bi-reception-0': state.speed_level === '0',
'bi-reception-1': state.speed_level === '1',
'bi-reception-2': state.speed_level === '2',
'bi-reception-3': state.speed_level === '3',
'bi-reception-4': state.speed_level === '4',
}"
></i>
</button>
</div>
<div class="btn-group btn-group-sm me-1" role="group">
<button
class="btn btn-sm btn-secondary me-0"
type="button"
data-bs-placement="top"
data-bs-toggle="tooltip"
data-bs-trigger="hover"
data-bs-html="true"
>
<i class="bi bi-file-earmark-binary" style="font-size: 1rem"></i>
</button>
<button
class="btn btn-sm btn-secondary me-4 disabled"
type="button"
data-bs-placement="top"
data-bs-toggle="tooltip"
data-bs-trigger="hover"
data-bs-html="true"
>
{{ state.arq_total_bytes }}
</button>
</div>
<div class="btn-group btn-group-sm me-1" role="group">
<button
class="btn btn-sm btn-secondary me-0"
type="button"
data-bs-placement="top"
data-bs-toggle="tooltip"
data-bs-trigger="hover"
data-bs-html="true"
>
<i class="bi bi-file-earmark-binary" style="font-size: 1rem"></i>
</button>
<div class="btn-group btn-group-sm me-1" role="group"> <button
<button class="btn btn-sm btn-secondary disabled me-1"
class="btn btn-sm btn-secondary me-4 disabled" type="button"
type="button" data-bs-placement="top"
data-bs-placement="top" data-bs-toggle="tooltip"
data-bs-toggle="tooltip" data-bs-trigger="hover"
data-bs-trigger="hover" data-bs-html="true"
data-bs-html="true" >
> {{ state.dxcallsign }}
{{state.frequency}} Hz </button>
</button> </div>
</div>
</div>
<div class="col-lg-4">
<div style="margin-right: 2px">
<div
class="progress w-100 rounded-0 rounded-top"
style="height: 20px; min-width: 200px"
>
<div
class="progress-bar progress-bar-striped bg-primary force-gpu"
id="transmission_progress"
role="progressbar"
:style="{ width: state.arq_transmission_percent + '%' }"
aria-valuenow="0"
aria-valuemin="0"
aria-valuemax="100"
></div>
<p class="justify-content-center m-0 d-flex position-absolute w-100">
{{ state.arq_seconds_until_finish }}s left
</p>
</div>
<div
</div> class="progress mb-0 rounded-0 rounded-bottom"
style="height: 10px"
>
<div
class="progress-bar progress-bar-striped bg-warning"
<div class="btn-group btn-group-sm me-1" role="group"> id="transmission_timeleft"
role="progressbar"
:style="{ width: state.arq_seconds_until_timeout_percent + '%' }"
aria-valuenow="0"
<button aria-valuemin="0"
class="btn btn-sm btn-secondary me-0" aria-valuemax="100"
type="button" >
data-bs-placement="top" <p
data-bs-toggle="tooltip" class="justify-content-center m-0 d-flex position-absolute w-100"
data-bs-trigger="hover" >
data-bs-html="true" timeout in: {{ state.arq_seconds_until_timeout }}s
> </p>
<i class="bi bi-speedometer2" style="font-size: 1rem"></i>
</button>
<button
class="btn btn-sm btn-secondary me-4 disabled"
type="button"
data-bs-placement="top"
data-bs-toggle="tooltip"
data-bs-trigger="hover"
data-bs-html="true"
>
<i class="bi " style="font-size: 1rem"
v-bind:class="{ 'bi-reception-0' : state.speed_level === '0',
'bi-reception-1' : state.speed_level === '1',
'bi-reception-2' : state.speed_level === '2',
'bi-reception-3' : state.speed_level === '3',
'bi-reception-4' : state.speed_level === '4',
}"
></i>
</button>
</div>
<div class="btn-group btn-group-sm me-1" role="group">
<button
class="btn btn-sm btn-secondary me-0"
type="button"
data-bs-placement="top"
data-bs-toggle="tooltip"
data-bs-trigger="hover"
data-bs-html="true"
>
<i class="bi bi-file-earmark-binary" style="font-size: 1rem"></i>
</button>
<button
class="btn btn-sm btn-secondary me-4 disabled"
type="button"
data-bs-placement="top"
data-bs-toggle="tooltip"
data-bs-trigger="hover"
data-bs-html="true"
>
{{state.arq_total_bytes}}
</button>
</div>
<div class="btn-group btn-group-sm me-1" role="group">
<button
class="btn btn-sm btn-secondary me-0"
type="button"
data-bs-placement="top"
data-bs-toggle="tooltip"
data-bs-trigger="hover"
data-bs-html="true"
>
<i class="bi bi-file-earmark-binary" style="font-size: 1rem"></i>
</button>
<button
class="btn btn-sm btn-secondary disabled me-1"
type="button"
data-bs-placement="top"
data-bs-toggle="tooltip"
data-bs-trigger="hover"
data-bs-html="true"
>
{{state.dxcallsign}}
</button>
</div>
</div> </div>
</div> </div>
<div class="col-lg-4"> </div>
<div style="margin-right: 2px"> </div>
</nav>
</template>
<div class="progress w-100 rounded-0 rounded-top" style="height: 20px; min-width: 200px">
<div
class="progress-bar progress-bar-striped bg-primary force-gpu"
id="transmission_progress"
role="progressbar"
:style="{ width: state.arq_transmission_percent + '%' }"
aria-valuenow="0"
aria-valuemin="0"
aria-valuemax="100"
></div>
<p
class="justify-content-center m-0 d-flex position-absolute w-100"
>
{{state.arq_seconds_until_finish}}s left
</p>
</div>
<div class="progress mb-0 rounded-0 rounded-bottom" style="height: 10px">
<div
class="progress-bar progress-bar-striped bg-warning"
id="transmission_timeleft"
role="progressbar"
:style="{ width: state.arq_seconds_until_timeout_percent + '%' }"
aria-valuenow="0"
aria-valuemin="0"
aria-valuemax="100"
>
<p
class="justify-content-center m-0 d-flex position-absolute w-100"
>
timeout in: {{state.arq_seconds_until_timeout}}s
</p>
</div>
</div>
</div>
</div>
</nav>
</template>

File diff suppressed because it is too large Load diff

View file

@ -1,134 +1,124 @@
<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-header p-1">
<div class="container">
<div class="card mb-1"> <div class="row">
<div class="card-header p-1"> <div class="col-1">
<div class="container"> <i class="bi bi-house-door" style="font-size: 1.2rem"></i>
<div class="row"> </div>
<div class="col-1"> <div class="col-10">
<i class="bi bi-house-door" style="font-size: 1.2rem"></i> <strong class="fs-5">My station</strong>
</div> </div>
<div class="col-10"> <div class="col-1 text-end">
<strong class="fs-5">My station</strong> <button
</div> type="button"
<div class="col-1 text-end"> id="openHelpModalStation"
<button data-bs-toggle="modal"
type="button" data-bs-target="#stationHelpModal"
id="openHelpModalStation" class="btn m-0 p-0 border-0"
data-bs-toggle="modal" >
data-bs-target="#stationHelpModal" <i class="bi bi-question-circle" style="font-size: 1rem"></i>
class="btn m-0 p-0 border-0" </button>
> </div>
<i </div>
class="bi bi-question-circle" </div>
style="font-size: 1rem" </div>
></i> <div class="card-body p-2">
</button> <div class="row">
</div> <div class="col-md-auto">
</div> <div
</div> class="input-group input-group-sm mb-0"
</div> data-bs-placement="bottom"
<div class="card-body p-2"> data-bs-toggle="tooltip"
<div class="row"> data-bs-trigger="hover"
<div class="col-md-auto"> data-bs-html="false"
<div title="Enter your callsign and save it"
class="input-group input-group-sm mb-0" >
data-bs-placement="bottom" <span class="input-group-text">
data-bs-toggle="tooltip" <i class="bi bi-person-bounding-box" style="font-size: 1rem"></i>
data-bs-trigger="hover" </span>
data-bs-html="false" <input
title="Enter your callsign and save it" type="text"
> class="form-control"
<span class="input-group-text"> style="width: 5rem; text-transform: uppercase"
<i placeholder="callsign"
class="bi bi-person-bounding-box" pattern="[A-Z]*"
style="font-size: 1rem" id="myCall"
></i> maxlength="8"
</span> aria-label="Input group"
<input aria-describedby="btnGroupAddon"
type="text" v-model="settings.mycall"
class="form-control" @input="saveSettings"
style="width: 5rem; text-transform: uppercase" />
placeholder="callsign" <select
pattern="[A-Z]*" class="form-select form-select-sm"
id="myCall" aria-label=".form-select-sm"
maxlength="8" id="myCallSSID"
aria-label="Input group" v-model="settings.myssid"
aria-describedby="btnGroupAddon" @change="saveSettings"
v-model="settings.mycall" >
@input="saveSettings" <option selected value="0">0</option>
/> <option value="1">1</option>
<select <option value="2">2</option>
class="form-select form-select-sm" <option value="3">3</option>
aria-label=".form-select-sm" <option value="4">4</option>
id="myCallSSID" <option value="5">5</option>
v-model="settings.myssid" <option value="6">6</option>
@change="saveSettings" <option value="7">7</option>
> <option value="8">8</option>
<option selected value="0">0</option> <option value="9">9</option>
<option value="1">1</option> <option value="10">10</option>
<option value="2">2</option> <option value="11">11</option>
<option value="3">3</option> <option value="12">12</option>
<option value="4">4</option> <option value="13">13</option>
<option value="5">5</option> <option value="14">14</option>
<option value="6">6</option> <option value="15">15</option>
<option value="7">7</option> </select>
<option value="8">8</option> </div>
<option value="9">9</option> </div>
<option value="10">10</option> <div class="col-md-auto">
<option value="11">11</option> <div
<option value="12">12</option> class="input-group input-group-sm mb-0"
<option value="13">13</option> data-bs-placement="bottom"
<option value="14">14</option> data-bs-toggle="tooltip"
<option value="15">15</option> data-bs-trigger="hover"
</select> data-bs-html="false"
</div> title="Enter your gridsquare and save it"
</div> >
<div class="col-md-auto"> <span class="input-group-text">
<div <i class="bi bi-house-fill" style="font-size: 1rem"></i>
class="input-group input-group-sm mb-0" </span>
data-bs-placement="bottom" <input
data-bs-toggle="tooltip" type="text"
data-bs-trigger="hover" class="form-control mr-1"
data-bs-html="false" style="max-width: 6rem"
title="Enter your gridsquare and save it" placeholder="locator"
> id="myGrid"
<span class="input-group-text"> maxlength="6"
<i class="bi bi-house-fill" style="font-size: 1rem"></i> aria-label="Input group"
</span> aria-describedby="btnGroupAddon"
<input v-model="settings.mygrid"
type="text" @input="saveSettings"
class="form-control mr-1" />
style="max-width: 6rem" </div>
placeholder="locator" </div>
id="myGrid" </div>
maxlength="6" <!-- end of row-->
aria-label="Input group" </div>
aria-describedby="btnGroupAddon" </div>
v-model="settings.mygrid" </template>
@input="saveSettings"
/>
</div>
</div>
</div>
<!-- end of row-->
</div>
</div>
</template>

View file

@ -1,203 +1,231 @@
<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">
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-1"> <div class="col-1">
<i class="bi bi-projector" style="font-size: 1.2rem"></i> <i class="bi bi-projector" style="font-size: 1.2rem"></i>
</div> </div>
<div class="col-4"> <div class="col-4">
<strong class="fs-5">Rig control</strong> <strong class="fs-5">Rig control</strong>
</div> </div>
<div class="col-6">
<div
class="list-group list-group-horizontal"
id="rig-control-list-tab"
role="rig-control-tablist"
>
<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 class="col-6"> <div class="col-1 text-end">
<button
type="button"
<div class="list-group list-group-horizontal" id="rig-control-list-tab" role="rig-control-tablist"> id="openHelpModalRigControl"
<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> data-bs-toggle="modal"
<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> data-bs-target="#rigcontrolHelpModal"
<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> class="btn m-0 p-0 border-0"
>
<i class="bi bi-question-circle" style="font-size: 1rem"></i>
</button>
</div>
</div>
</div>
</div> </div>
<div class="card-body p-2" style="height: 100px">
<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">
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">
<span class="input-group-text">Rigctld</span>
<span class="input-group-text">Address</span>
<input
type="text"
class="form-control"
placeholder="rigctld IP"
id="hamlib_rigctld_ip"
aria-label="Device IP"
v-model="settings.hamlib_rigctld_ip"
/>
<span class="input-group-text">Port</span>
<input
type="text"
class="form-control"
placeholder="rigctld port"
id="hamlib_rigctld_port"
aria-label="Device Port"
v-model="settings.hamlib_rigctld_port"
/>
</div>
<div class="input-group input-group-sm mb-1">
<span class="input-group-text">Rigctld</span>
<button
class="btn btn-outline-success"
type="button"
id="hamlib_rigctld_start"
>
Start
</button>
<button
class="btn btn-outline-danger"
type="button"
id="hamlib_rigctld_stop"
>
Stop
</button>
<input
type="text"
class="form-control"
placeholder="Status"
id="hamlib_rigctld_status"
aria-label="State"
aria-describedby="basic-addon1"
/>
<button
type="button"
id="testHamlib"
class="btn btn-sm btn-outline-secondary ms-1"
data-bs-placement="bottom"
data-bs-toggle="tooltip"
data-bs-trigger="hover"
data-bs-html="true"
@click="testHamlib"
title="Test your hamlib settings and toggle PTT once. Button will become <strong class='text-success'>green</strong> on success and <strong class='text-danger'>red</strong> if fails."
>
PTT Test
</button>
</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 class="input-group input-group-sm mb-1">
<span class="input-group-text">TCI</span>
<span class="input-group-text">Address</span>
<input
type="text"
class="form-control"
placeholder="tci IP"
id="tci_ip"
aria-label="Device IP"
v-model="settings.tci_ip"
/>
</div>
</div> <div class="input-group input-group-sm mb-1">
<span class="input-group-text">Port</span>
<input
type="text"
class="form-control"
placeholder="tci port"
id="tci_port"
aria-label="Device Port"
v-model="settings.tci_port"
/>
</div>
</div>
</div>
</div>
<div class="col-1 text-end"> <!-- RADIO CONTROL DISABLED -->
<button <div id="radio-control-disabled"></div>
type="button"
id="openHelpModalRigControl"
data-bs-toggle="modal"
data-bs-target="#rigcontrolHelpModal"
class="btn m-0 p-0 border-0"
>
<i
class="bi bi-question-circle"
style="font-size: 1rem"
></i>
</button>
</div>
</div>
</div>
</div>
<div class="card-body p-2" style="height: 100px">
<!-- RADIO CONTROL RIGCTLD -->
<div class="tab-content" id="rig-control-nav-tabContent"> <div id="radio-control-rigctld"></div>
<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"> <!-- RADIO CONTROL TCI-->
TNC will not utilize rig control and features will be <div id="radio-control-tci"></div>
limited. While functional; it is recommended to configure <!-- RADIO CONTROL HELP -->
hamlib. <div id="radio-control-help">
</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">
<span class="input-group-text">Rigctld</span>
<span class="input-group-text">Address</span>
<input
type="text"
class="form-control"
placeholder="rigctld IP"
id="hamlib_rigctld_ip"
aria-label="Device IP"
v-model="settings.hamlib_rigctld_ip"
/>
<span class="input-group-text">Port</span>
<input
type="text"
class="form-control"
placeholder="rigctld port"
id="hamlib_rigctld_port"
aria-label="Device Port"
v-model="settings.hamlib_rigctld_port"
/>
</div>
<div class="input-group input-group-sm mb-1">
<span class="input-group-text">Rigctld</span>
<button
class="btn btn-outline-success"
type="button"
id="hamlib_rigctld_start"
>
Start
</button>
<button
class="btn btn-outline-danger"
type="button"
id="hamlib_rigctld_stop"
>
Stop
</button>
<input
type="text"
class="form-control"
placeholder="Status"
id="hamlib_rigctld_status"
aria-label="State"
aria-describedby="basic-addon1"
/>
<button
type="button"
id="testHamlib"
class="btn btn-sm btn-outline-secondary ms-1"
data-bs-placement="bottom"
data-bs-toggle="tooltip"
data-bs-trigger="hover"
data-bs-html="true"
@click="testHamlib"
title="Test your hamlib settings and toggle PTT once. Button will become <strong class='text-success'>green</strong> on success and <strong class='text-danger'>red</strong> if fails."
>
PTT Test
</button>
</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 class="input-group input-group-sm mb-1">
<span class="input-group-text">TCI</span>
<span class="input-group-text">Address</span>
<input
type="text"
class="form-control"
placeholder="tci IP"
id="tci_ip"
aria-label="Device IP"
v-model="settings.tci_ip"
/>
</div>
<div class="input-group input-group-sm mb-1">
<span class="input-group-text">Port</span>
<input
type="text"
class="form-control"
placeholder="tci port"
id="tci_port"
aria-label="Device Port"
v-model="settings.tci_port"
/>
</div>
</div></div>
</div>
<!-- RADIO CONTROL DISABLED -->
<div id="radio-control-disabled">
</div>
<!-- RADIO CONTROL RIGCTLD -->
<div id="radio-control-rigctld">
</div>
<!-- RADIO CONTROL TCI-->
<div id="radio-control-tci">
</div>
<!-- RADIO CONTROL HELP -->
<div id="radio-control-help">
<!--
<strong>VOX:</strong> Use rig control mode 'none' <strong>VOX:</strong> Use rig control mode 'none'
<br /> <br />
<strong>HAMLIB locally:</strong> configure in settings, then <strong>HAMLIB locally:</strong> configure in settings, then
@ -206,12 +234,11 @@ switch (event.target.id) {
<strong>HAMLIB remotely:</strong> Enter IP/Port, connection <strong>HAMLIB remotely:</strong> Enter IP/Port, connection
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)
</div> </div>
--> -->
</div> </div>
</template> </template>

View file

@ -1,127 +1,96 @@
<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) {
case "stopped":
// todo: is there another way of doing this, maybe more VueJS like?
settings.rx_audio = document.getElementById(
"audio_input_selectbox",
).value;
settings.tx_audio = document.getElementById(
"audio_output_selectbox",
).value;
startTNC();
switch (state.tnc_running_state) { break;
case "running":
case 'stopped': stopTNC();
// todo: is there another way of doing this, maybe more VueJS like?
settings.rx_audio = document.getElementById("audio_input_selectbox").value
settings.tx_audio = document.getElementById("audio_output_selectbox").value
startTNC()
break;
case 'running':
stopTNC()
break;
default:
break;
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">
<span class="badge bg-secondary me-4"
<div class="mx-auto"> >TNC location | {{ settings.tnc_host }}</span
>
<div class="btn-group" role="group">
<button
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">
<button
type="button"
id="startTNC"
class="btn btn-sm btn-outline-success"
data-bs-toggle="tooltip"
data-bs-trigger="hover"
data-bs-html="false"
title="Start the TNC. Please set your audio and radio settings first!"
@click="startStopTNC()"
v-bind:class="{ 'disabled' : state.tnc_running_state === 'running'}"
>
<i class="bi bi-play-fill"></i>
<span class="ms-2">Start tnc</span>
</button>
<button
type="button"
id="stopTNC"
class="btn btn-sm btn-outline-danger"
data-bs-toggle="tooltip"
data-bs-trigger="hover"
data-bs-html="false"
title="Stop the TNC."
@click="startStopTNC()"
v-bind:class="{ 'disabled' : state.tnc_running_state === 'stopped'}"
>
<i class="bi bi-stop-fill"></i>
<span class="ms-2">Stop tnc</span>
</button>
</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>
<span class="badge bg-secondary me-4"
>Service | {{ state.tnc_running_state }}</span
>
<div class="btn-group" role="group"></div>
<div class="btn-group me-4" role="group">
<button <button
type="button" type="button"
id="openHelpModalStartStopTNC" id="startTNC"
data-bs-toggle="modal" class="btn btn-sm btn-outline-success"
data-bs-target="#startStopTNCHelpModal" data-bs-toggle="tooltip"
class="btn me-4 p-0 border-0" data-bs-trigger="hover"
data-bs-html="false"
title="Start the TNC. Please set your audio and radio settings first!"
@click="startStopTNC()"
v-bind:class="{ disabled: state.tnc_running_state === 'running' }"
> >
<i class="bi bi-question-circle" style="font-size: 1rem"></i> <i class="bi bi-play-fill"></i>
<span class="ms-2">start tnc</span>
</button>
<button
type="button"
id="stopTNC"
class="btn btn-sm btn-outline-danger"
data-bs-toggle="tooltip"
data-bs-trigger="hover"
data-bs-html="false"
title="Stop the TNC."
@click="startStopTNC()"
v-bind:class="{ disabled: state.tnc_running_state === 'stopped' }"
>
<i class="bi bi-stop-fill"></i>
<span class="ms-2">stop tnc</span>
</button> </button>
</div> </div>
<button
type="button"
id="openHelpModalStartStopTNC"
data-bs-toggle="modal"
data-bs-target="#startStopTNCHelpModal"
class="btn me-4 p-0 border-0"
>
<i class="bi bi-question-circle" style="font-size: 1rem"></i>
</button>
</div>
<!--
<!--
<div class="btn-toolbar" role="toolbar"> <div class="btn-toolbar" role="toolbar">
<span data-bs-placement="bottom" data-bs-toggle="tooltip" data-bs-trigger="hover" data-bs-html="false" <span data-bs-placement="bottom" data-bs-toggle="tooltip" data-bs-trigger="hover" data-bs-html="false"
@ -142,6 +111,5 @@ switch (state.tnc_running_state) {
</span> </span>
</div> </div>
--> --></nav>
</nav> </template>
</template>

View file

@ -1,97 +1,86 @@
<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>
<div class="card mb-0"> <div class="card mb-0">
<div class="card-header p-1 d-flex"> <div class="card-header p-1 d-flex">
<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" </div>
style="font-size: 1.2rem" <div class="col-3">
></i> <strong class="fs-5">Updater</strong>
</div> </div>
<div class="col-3"> <div class="col-7">
<strong class="fs-5">Updater</strong> <div class="progress w-100 ms-1 m-1">
</div> <div
<div class="col-7"> class="progress-bar"
<div class="progress w-100 ms-1 m-1"> style="width: 0%"
<div role="progressbar"
class="progress-bar" id="UpdateProgressBar"
style="width: 0%" aria-valuenow="0"
role="progressbar" aria-valuemin="0"
id="UpdateProgressBar" aria-valuemax="100"
aria-valuenow="0" >
aria-valuemin="0" <span id="UpdateProgressInfo"></span>
aria-valuemax="100"
>
<span id="UpdateProgressInfo"></span>
</div>
</div>
</div>
<div class="col-1 text-end">
<button
type="button"
id="openHelpModalUpdater"
data-bs-toggle="modal"
data-bs-target="#updaterHelpModal"
class="btn m-0 p-0 border-0"
>
<i
class="bi bi-question-circle"
style="font-size: 1rem"
></i>
</button>
</div>
</div>
</div>
</div>
<div class="card-body p-2 mb-1">
<button
class="btn btn-secondary btn-sm"
id="updater_channel"
type="button"
disabled
>
{{settings.update_channel}}
</button>
<button
class="btn btn-secondary btn-sm"
id="updater_status"
type="button"
disabled
>
...
</button>
<button
class="btn btn-secondary btn-sm"
id="updater_changelog"
type="button"
style="display: none"
>
Changelog
</button>
<button
class="btn btn-primary btn-sm"
id="update_and_install"
type="button"
style="display: none"
>
Install & Restart
</button>
</div> </div>
</div> </div>
</template> </div>
<div class="col-1 text-end">
<button
type="button"
id="openHelpModalUpdater"
data-bs-toggle="modal"
data-bs-target="#updaterHelpModal"
class="btn m-0 p-0 border-0"
>
<i class="bi bi-question-circle" style="font-size: 1rem"></i>
</button>
</div>
</div>
</div>
</div>
<div class="card-body p-2 mb-1">
<button
class="btn btn-secondary btn-sm"
id="updater_channel"
type="button"
disabled
>
{{ settings.update_channel }}
</button>
<button
class="btn btn-secondary btn-sm"
id="updater_status"
type="button"
disabled
>
...
</button>
<button
class="btn btn-secondary btn-sm"
id="updater_changelog"
type="button"
style="display: none"
>
Changelog
</button>
<button
class="btn btn-primary btn-sm"
id="update_and_install"
type="button"
style="display: none"
>
Install & Restart
</button>
</div>
</div>
</template>

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,106 +1,123 @@
<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">
<label class="input-group-text w-50">Enable "is typing"</label>
<label class="input-group-text w-50">
<div class="form-check form-switch form-check-inline">
<input
class="form-check-input"
type="checkbox"
id="enable_is_writing"
@change="saveSettings"
v-model="settings.enable_is_writing"
true-value="True"
false-value="False"
/>
<label class="form-check-label" for="GraphicsSwitch"
>Additional broadcast burst</label
>
</div>
</label>
</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">Enable "is typing"</label> <label class="input-group-text w-50">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_is_writing" id="enable_request_profile"
@change="saveSettings" v-model="settings.enable_is_writing" true-value="True" false-value="False" @change="saveSettings"
/> v-model="settings.enable_request_profile"
<label class="form-check-label" for="GraphicsSwitch" true-value="True"
>Additional broadcast burst</label false-value="False"
> />
</div> </div>
</label> </label>
</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 "shared folder"</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_shared_folder"
@change="saveSettings" v-model="settings.enable_request_profile" true-value="True" false-value="False" @change="saveSettings"
/> v-model="settings.enable_request_shared_folder"
</div> true-value="True"
</label> false-value="False"
</div> />
</div>
</label>
</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">Shared folder path</label>
>Allow requesting "shared folder"</label <input
> type="text"
<label class="input-group-text w-50"> class="form-control w-50"
<div class="form-check form-switch form-check-inline"> id="shared_folder_path"
<input @change="saveSettings"
class="form-check-input" v-model="settings.shared_folder_path"
type="checkbox" />
id="enable_request_shared_folder" </div>
@change="saveSettings" v-model="settings.enable_request_shared_folder" true-value="True" false-value="False"
/>
</div>
</label>
</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">Shared folder path</label> <label class="input-group-text w-50"
<input type="text" class="form-control w-50" id="shared_folder_path" @change="saveSettings" >Enable auto retry on Beacon or Ping
v-model="settings.shared_folder_path" /> </label>
</div>
<div class="input-group input-group-sm mb-1"> <label class="input-group-text w-50">
<label class="input-group-text w-50" <div class="form-check form-switch form-check-inline">
>Enable auto retry on Beacon or Ping <input
</label> class="form-check-input"
type="checkbox"
id="enable_auto_retry"
@change="saveSettings"
v-model="settings.enable_auto_retry"
true-value="True"
false-value="False"
/>
</div>
</label>
</div>
<label class="input-group-text w-50"> <div class="input-group input-group-sm mb-1">
<div class="form-check form-switch form-check-inline"> <span class="input-group-text w-50">message retry attempts</span>
<input <select
class="form-check-input" class="form-select form-select-sm w-50"
type="checkbox" id="max_retry_attempts"
id="enable_auto_retry" @change="saveSettings"
@change="saveSettings" v-model="settings.enable_auto_retry" true-value="True" false-value="False" v-model="settings.max_retry_attempts"
/> >
</div> <option value="1">1</option>
</label> <option value="2">2</option>
</div> <option value="3">3</option>
<option value="4">4</option>
<div class="input-group input-group-sm mb-1"> <option value="5">5</option>
<span class="input-group-text w-50">message retry attempts</span> <option value="6">6</option>
<select class="form-select form-select-sm w-50" id="max_retry_attempts" @change="saveSettings" <option value="7">7</option>
v-model="settings.max_retry_attempts"> <option value="8">8</option>
<option value="1">1</option> <option value="9">9</option>
<option value="2">2</option> </select>
<option value="3">3</option> </div>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
</select>
</div>
</template> </template>

View file

@ -1,83 +1,97 @@
<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
<input class="form-check-input" type="checkbox" id="autoTuneSwitch" @change="saveSettings" v-model="settings.auto_tune" true-value="True" false-value="False" /> class="form-check-input"
<label class="form-check-label" for="autoTuneSwitch" type="checkbox"
>adjust ALC on TX</label id="autoTuneSwitch"
> @change="saveSettings"
</div> v-model="settings.auto_tune"
</label> true-value="True"
</div> false-value="False"
<div class="input-group input-group-sm mb-1"> />
<label class="input-group-text w-50">Enable FSK mode</label> <label class="form-check-label" for="autoTuneSwitch"
<label class="input-group-text w-50"> >adjust ALC on TX</label
<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"/>
<label class="form-check-label" for="fskModeSwitch"
>not available, yet</label
>
</div>
</label>
</div>
<div class="input-group input-group-sm mb-1">
<label class="input-group-text w-50">Enable MESH protocol</label>
<label class="input-group-text w-50">
<div class="form-check form-switch form-check-inline ms-2">
<input
class="form-check-input"
type="checkbox"
id="enableMeshSwitch"
@change="saveSettings"
v-model="settings.enable_mesh_features" true-value="True" false-value="False"
/>
<label class="form-check-label" for="enableMeshSwitch"
>experimental! REALLY!</label
>
</div>
</label>
</div>
<div class="input-group input-group-sm mb-1">
<label class="input-group-text w-50">Database maintenance</label>
<label class="input-group-text w-50">
<button
class="btn btn-outline-secondary btn-sm w-50"
id="btnCleanDB"
type="button"
> >
Clean</button
>&nbsp;
<div
class="spinner-border text-warning invisible"
role="status"
id="divCleanDBSpinner"
></div>
</label>
</div>
<div class="center">
<div class="badge text-bg-danger">
<i class="bi bi-shield-exclamation"></i> These options may not work and
are for experienced users only!
</div> </div>
</label>
</div>
<div class="input-group input-group-sm mb-1">
<label class="input-group-text w-50">Enable FSK mode</label>
<label class="input-group-text w-50">
<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"
/>
<label class="form-check-label" for="fskModeSwitch"
>not available, yet</label
>
</div>
</label>
</div>
<div class="input-group input-group-sm mb-1">
<label class="input-group-text w-50">Enable MESH protocol</label>
<label class="input-group-text w-50">
<div class="form-check form-switch form-check-inline ms-2">
<input
class="form-check-input"
type="checkbox"
id="enableMeshSwitch"
@change="saveSettings"
v-model="settings.enable_mesh_features"
true-value="True"
false-value="False"
/>
<label class="form-check-label" for="enableMeshSwitch"
>experimental! REALLY!</label
>
</div>
</label>
</div>
<div class="input-group input-group-sm mb-1">
<label class="input-group-text w-50">Database maintenance</label>
<label class="input-group-text w-50">
<button
class="btn btn-outline-secondary btn-sm w-50"
id="btnCleanDB"
type="button"
>
Clean</button
>&nbsp;
<div
class="spinner-border text-warning invisible"
role="status"
id="divCleanDBSpinner"
></div>
</label>
</div>
<div class="center">
<div class="badge text-bg-danger">
<i class="bi bi-shield-exclamation"></i> These options may not work and
are for experienced users only!
</div> </div>
</div>
</template> </template>

View file

@ -1,136 +1,147 @@
<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">
<span class="input-group-text w-50">GUI theme</span>
<div class="input-group input-group-sm mb-1"> <select
<span class="input-group-text w-50">GUI theme</span> class="form-select form-select-sm w-50"
<select id="theme_selector"
class="form-select form-select-sm w-50" @change="saveSettings"
id="theme_selector" v-model="settings.theme"
@change="saveSettings" >
v-model="settings.theme" <option value="default_light">Default (light)</option>
> <option value="default_dark">Default (dark)</option>
<option value="default_light">Default (light)</option> <option value="default_auto">Default (auto)</option>
<option value="default_dark">Default (dark)</option> <option value="cerulean">Cerulean</option>
<option value="default_auto">Default (auto)</option> <option value="cosmo">Cosmo</option>
<option value="cerulean">Cerulean</option> <option value="cyborg">Cyborg</option>
<option value="cosmo">Cosmo</option> <option value="darkly">Darkly</option>
<option value="cyborg">Cyborg</option> <option value="flatly">Flatly</option>
<option value="darkly">Darkly</option> <option value="journal">Journal</option>
<option value="flatly">Flatly</option> <option value="litera">Litera</option>
<option value="journal">Journal</option> <option value="lumen">Lumen</option>
<option value="litera">Litera</option> <option value="lux">Lux</option>
<option value="lumen">Lumen</option> <option value="materia">Materia</option>
<option value="lux">Lux</option> <option value="minty">Minty</option>
<option value="materia">Materia</option> <option value="morph">Morhp</option>
<option value="minty">Minty</option> <option value="pulse">Pulse</option>
<option value="morph">Morhp</option> <option value="quartz">Quartz</option>
<option value="pulse">Pulse</option> <option value="sandstone">Sandstone</option>
<option value="quartz">Quartz</option> <option value="simplex">Simplex</option>
<option value="sandstone">Sandstone</option> <option value="sketchy">Sketchy</option>
<option value="simplex">Simplex</option> <option value="slate">Slate</option>
<option value="sketchy">Sketchy</option> <option value="solar">Solar</option>
<option value="slate">Slate</option> <option value="spacelab">Spacelab</option>
<option value="solar">Solar</option> <option value="superhero">Superhero</option>
<option value="spacelab">Spacelab</option> <option value="united">United</option>
<option value="superhero">Superhero</option> <option value="vapor">Vapor</option>
<option value="united">United</option> <option value="yeti">Yeti</option>
<option value="vapor">Vapor</option> <option value="zephyr">Zephyr</option>
<option value="yeti">Yeti</option> </select>
<option value="zephyr">Zephyr</option> </div>
</select> <div class="input-group input-group-sm mb-1">
</div> <span class="input-group-text w-50">Waterfall theme</span>
<div class="input-group input-group-sm mb-1"> <select
<span class="input-group-text w-50">Waterfall theme</span> class="form-select form-select-sm w-50"
<select class="form-select form-select-sm w-50" id="wftheme_selector" @change="saveSettings" id="wftheme_selector"
v-model="settings.wftheme"> @change="saveSettings"
<option value="2">Default</option> v-model="settings.wftheme"
<option value="0">Turbo</option> >
<option value="1">Fosphor</option> <option value="2">Default</option>
<option value="3">Inferno</option> <option value="0">Turbo</option>
<option value="4">Magma</option> <option value="1">Fosphor</option>
<option value="5">Jet</option> <option value="3">Inferno</option>
<option value="6">Binary</option> <option value="4">Magma</option>
</select> <option value="5">Jet</option>
</div> <option value="6">Binary</option>
<div class="input-group input-group-sm mb-1"> </select>
<label class="input-group-text w-50">Enable fancy GUI</label> </div>
<label class="input-group-text w-50"> <div class="input-group input-group-sm mb-1">
<div class="form-check form-switch form-check-inline"> <label class="input-group-text w-50">Enable fancy GUI</label>
<input class="form-check-input" type="checkbox" id="GraphicsSwitch" @change="saveSettings" v-model="settings.high_graphics" true-value="True" false-value="False"/> <label class="input-group-text w-50">
<label class="form-check-label" for="GraphicsSwitch" <div class="form-check form-switch form-check-inline">
>Higher CPU Usage</label <input
> class="form-check-input"
</div> type="checkbox"
</label> id="GraphicsSwitch"
</div> @change="saveSettings"
<div class="input-group input-group-sm mb-1"> v-model="settings.high_graphics"
<label class="input-group-text w-50" for="inputGroupFile02" true-value="True"
>Received files folder</label false-value="False"
> />
<input type="text" class="form-control w-50" id="received_files_folder"/> <label class="form-check-label" for="GraphicsSwitch"
</div> >Higher CPU Usage</label
<div class="input-group input-group-sm mb-1"> >
<span class="input-group-text w-50">Update channel</span> </div>
<select </label>
class="form-select form-select-sm w-50" </div>
id="update_channel_selector" <div class="input-group input-group-sm mb-1">
@change="saveSettings" <label class="input-group-text w-50" for="inputGroupFile02"
v-model="settings.update_channel" >Received files folder</label
> >
<option value="latest">stable</option> <input type="text" class="form-control w-50" id="received_files_folder" />
<option value="beta">beta</option> </div>
<option value="alpha">alpha</option> <div class="input-group input-group-sm mb-1">
</select> <span class="input-group-text w-50">Update channel</span>
</div> <select
<div class="input-group input-group-sm mb-1"> class="form-select form-select-sm w-50"
<label class="input-group-text w-50">Enable notifications</label> id="update_channel_selector"
<label class="input-group-text w-50"> @change="saveSettings"
<div class="form-check form-switch form-check-inline"> v-model="settings.update_channel"
<input >
class="form-check-input" <option value="latest">stable</option>
type="checkbox" <option value="beta">beta</option>
id="NotificationSwitch" <option value="alpha">alpha</option>
@change="saveSettings" v-model="settings.enable_sys_notification" true-value="True" false-value="False" </select>
/> </div>
<label class="form-check-label" for="NotificationSwitch" <div class="input-group input-group-sm mb-1">
>Show system pop-ups</label <label class="input-group-text w-50">Enable notifications</label>
> <label class="input-group-text w-50">
</div> <div class="form-check form-switch form-check-inline">
</label> <input
</div> class="form-check-input"
<div class="input-group input-group-sm mb-1"> type="checkbox"
<label class="input-group-text w-50">Auto-start TNC/rigctld</label> id="NotificationSwitch"
<label class="input-group-text w-50"> @change="saveSettings"
<div class="form-check form-switch form-check-inline"> v-model="settings.enable_sys_notification"
<input true-value="True"
class="form-check-input" false-value="False"
type="checkbox" />
id="AutoStartSwitch" <label class="form-check-label" for="NotificationSwitch"
@change="saveSettings" v-model="settings.auto_start" true-value="True" false-value="False" >Show system pop-ups</label
/> >
<label class="form-check-label" for="AutoStartSwitch" </div>
>Start on app launch</label </label>
> </div>
</div> <div class="input-group input-group-sm mb-1">
</label> <label class="input-group-text w-50">Auto-start TNC/rigctld</label>
</div> <label class="input-group-text w-50">
<div class="form-check form-switch form-check-inline">
<input
class="form-check-input"
type="checkbox"
id="AutoStartSwitch"
@change="saveSettings"
v-model="settings.auto_start"
true-value="True"
false-value="False"
/>
<label class="form-check-label" for="AutoStartSwitch"
>Start on app launch</label
>
</div>
</label>
</div>
</template> </template>

File diff suppressed because it is too large Load diff

View file

@ -1,187 +1,216 @@
<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">
<span class="input-group-text" style="width: 180px">TNC port</span>
<input
type="text"
class="form-control"
placeholder="tnc port"
id="tnc_port"
maxlength="5"
max="65534"
min="1025"
@change="saveSettings"
v-model="settings.tnc_port"
/>
</div>
<div class="input-group input-group-sm mb-1">
<span class="input-group-text" style="width: 180px">TNC host</span>
<input
type="text"
class="form-control"
placeholder="tnc host"
id="tnc_port"
@change="saveSettings"
v-model="settings.tnc_host"
/>
</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" <label class="input-group-text w-50">TX delay in ms</label>
>TNC port</span <select
> class="form-select form-select-sm"
<input id="tx_delay"
type="text" @change="saveSettings"
class="form-control" v-model="settings.tx_delay"
placeholder="tnc port" >
id="tnc_port" <option value="0">0</option>
maxlength="5" <option value="50">50</option>
max="65534" <option value="100">100</option>
min="1025" <option value="150">150</option>
@change="saveSettings" <option value="200">200</option>
v-model="settings.tnc_port" <option value="250">250</option>
/> <option value="300">300</option>
</div> <option value="350">350</option>
<option value="400">400</option>
<option value="450">450</option>
<option value="500">500</option>
<option value="550">550</option>
<option value="600">600</option>
<option value="650">650</option>
<option value="700">700</option>
<option value="750">750</option>
<option value="800">800</option>
<option value="850">850</option>
<option value="900">900</option>
<option value="950">950</option>
<option value="1000">1000</option>
</select>
</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" <label class="input-group-text w-25">Tuning range</label>
>TNC host</span <label class="input-group-text">fmin</label>
> <select
<input class="form-select form-select-sm"
type="text" id="tuning_range_fmin"
class="form-control" @change="saveSettings"
placeholder="tnc host" v-model="settings.tuning_range_fmin"
id="tnc_port" >
@change="saveSettings" <option value="-50.0">-50.0</option>
v-model="settings.tnc_host" <option value="-100.0">-100.0</option>
/> <option value="-150.0">-150.0</option>
</div> <option value="-200.0">-200.0</option>
<option value="-250.0">-250.0</option>
</select>
<div class="input-group input-group-sm mb-1"> <label class="input-group-text">fmax</label>
<label class="input-group-text w-50">TX delay in ms</label> <select
<select class="form-select form-select-sm" id="tx_delay" @change="saveSettings" class="form-select form-select-sm"
v-model="settings.tx_delay"> id="tuning_range_fmax"
<option value="0">0</option> @change="saveSettings"
<option value="50">50</option> v-model="settings.tuning_range_fmax"
<option value="100">100</option> >
<option value="150">150</option> <option value="50.0">50.0</option>
<option value="200">200</option> <option value="100.0">100.0</option>
<option value="250">250</option> <option value="150.0">150.0</option>
<option value="300">300</option> <option value="200.0">200.0</option>
<option value="350">350</option> <option value="250.0">250.0</option>
<option value="400">400</option> </select>
<option value="450">450</option> </div>
<option value="500">500</option> <div class="input-group input-group-sm mb-1">
<option value="550">550</option> <span class="input-group-text w-50">Beacon interval</span>
<option value="600">600</option> <select
<option value="650">650</option> class="form-select form-select-sm"
<option value="700">700</option> aria-label=".form-select-sm"
<option value="750">750</option> id="beaconInterval"
<option value="800">800</option> style="width: 6rem"
<option value="850">850</option> @change="saveSettings"
<option value="900">900</option> v-model="settings.beacon_interval"
<option value="950">950</option> >
<option value="1000">1000</option> <option value="60">60 secs</option>
</select> <option value="90">90 secs</option>
</div> <option value="120">2 mins</option>
<option selected value="300">5 mins</option>
<div class="input-group input-group-sm mb-1"> <option value="600">10 mins</option>
<label class="input-group-text w-25">Tuning range</label> <option value="900">15 mins</option>
<label class="input-group-text">fmin</label> <option value="1800">30 mins</option>
<select class="form-select form-select-sm" id="tuning_range_fmin" @change="saveSettings" <option value="3600">60 mins</option>
v-model="settings.tuning_range_fmin"> </select>
<option value="-50.0">-50.0</option> </div>
<option value="-100.0">-100.0</option> <div class="input-group input-group-sm mb-1">
<option value="-150.0">-150.0</option> <label class="input-group-text w-50">Enable waterfall data</label>
<option value="-200.0">-200.0</option> <label class="input-group-text w-50">
<option value="-250.0">-250.0</option> <div class="form-check form-switch form-check-inline">
</select> <input
<label class="input-group-text">fmax</label> class="form-check-input"
<select class="form-select form-select-sm" id="tuning_range_fmax" @change="saveSettings" type="checkbox"
v-model="settings.tuning_range_fmax"> id="fftSwitch"
<option value="50.0">50.0</option> @change="saveSettings"
<option value="100.0">100.0</option> v-model="settings.enable_fft"
<option value="150.0">150.0</option> true-value="True"
<option value="200.0">200.0</option> false-value="False"
<option value="250.0">250.0</option> />
</select> <label class="form-check-label" for="fftSwitch">Waterfall</label>
</div> </div>
<div class="input-group input-group-sm mb-1"> </label>
<span class="input-group-text w-50">Beacon interval</span> </div>
<div class="input-group input-group-sm mb-1">
<label class="input-group-text w-50">Enable scatter diagram data</label>
<label class="input-group-text w-50">
<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"
/>
<label class="form-check-label" for="scatterSwitch">Scatter</label>
</div>
</label>
</div>
<div class="input-group input-group-sm mb-1">
<label class="input-group-text w-50">Enable 250Hz only mode</label>
<label class="input-group-text w-50">
<div class="form-check form-switch form-check-inline">
<input
class="form-check-input"
type="checkbox"
id="250HzModeSwitch"
v-model="settings.low_bandwidth_mode"
true-value="True"
false-value="False"
@change="saveSettings"
/>
<label class="form-check-label" for="250HzModeSwitch">250Hz</label>
</div>
</label>
</div>
<div class="input-group input-group-sm mb-1">
<label class="input-group-text w-50">Respond to CQ</label>
<label class="input-group-text w-50">
<div class="form-check form-switch form-check-inline">
<input
class="form-check-input"
type="checkbox"
id="respondCQSwitch"
v-model="settings.respond_to_cq"
true-value="True"
false-value="False"
@change="saveSettings"
/>
<label class="form-check-label" for="respondCQSwitch">QRV</label>
</div>
</label>
</div>
<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">
<select <select
class="form-select form-select-sm" class="form-select form-select-sm"
aria-label=".form-select-sm" id="rx_buffer_size"
id="beaconInterval" @change="saveSettings"
style="width: 6rem" v-model="settings.rx_buffer_size"
@change="saveSettings"
v-model="settings.beacon_interval"
> >
<option value="60">60 secs</option> <option value="1">1</option>
<option value="90">90 secs</option> <option value="2">2</option>
<option value="120">2 mins</option> <option value="4">4</option>
<option selected value="300">5 mins</option> <option value="8">8</option>
<option value="600">10 mins</option> <option value="16">16</option>
<option value="900">15 mins</option> <option value="32">32</option>
<option value="1800">30 mins</option> <option value="64">64</option>
<option value="3600">60 mins</option> <option value="128">128</option>
<option value="256">256</option>
<option value="512">512</option>
<option value="1024">1024</option>
</select> </select>
</div> </label>
<div class="input-group input-group-sm mb-1"> </div>
<label class="input-group-text w-50">Enable waterfall data</label>
<label class="input-group-text w-50">
<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"/>
<label class="form-check-label" for="fftSwitch">Waterfall</label>
</div>
</label>
</div>
<div class="input-group input-group-sm mb-1">
<label class="input-group-text w-50">Enable scatter diagram data</label>
<label class="input-group-text w-50">
<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"/>
<label class="form-check-label" for="scatterSwitch">Scatter</label>
</div>
</label>
</div>
<div class="input-group input-group-sm mb-1">
<label class="input-group-text w-50">Enable 250Hz only mode</label>
<label class="input-group-text w-50">
<div class="form-check form-switch form-check-inline">
<input
class="form-check-input"
type="checkbox"
id="250HzModeSwitch"
v-model="settings.low_bandwidth_mode" true-value="True" false-value="False" @change="saveSettings"
/>
<label class="form-check-label" for="250HzModeSwitch">250Hz</label>
</div>
</label>
</div>
<div class="input-group input-group-sm mb-1">
<label class="input-group-text w-50">Respond to CQ</label>
<label class="input-group-text w-50">
<div class="form-check form-switch form-check-inline">
<input
class="form-check-input"
type="checkbox"
id="respondCQSwitch"
v-model="settings.respond_to_cq" true-value="True" false-value="False" @change="saveSettings"
/>
<label class="form-check-label" for="respondCQSwitch">QRV</label>
</div>
</label>
</div>
<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">
<select 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="2">2</option>
<option value="4">4</option>
<option value="8">8</option>
<option value="16">16</option>
<option value="32">32</option>
<option value="64">64</option>
<option value="128">128</option>
<option value="256">256</option>
<option value="512">512</option>
<option value="1024">1024</option>
</select>
</label>
</div>
</template> </template>

View file

@ -1,44 +1,51 @@
<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
<input class="form-check-input" type="checkbox" id="ExplorerSwitch" @change="saveSettings" v-model="settings.enable_explorer" true-value="True" false-value="False"/> class="form-check-input"
<label class="form-check-label" for="ExplorerSwitch">Publish</label> type="checkbox"
</div> id="ExplorerSwitch"
</label> @change="saveSettings"
</div> v-model="settings.enable_explorer"
<div class="input-group input-group-sm mb-1"> true-value="True"
<label class="input-group-text w-50">Explorer stats publishing</label> false-value="False"
<label class="input-group-text w-50"> />
<div class="form-check form-switch form-check-inline"> <label class="form-check-label" for="ExplorerSwitch">Publish</label>
<input </div>
class="form-check-input" </label>
type="checkbox" </div>
id="ExplorerStatsSwitch" <div class="input-group input-group-sm mb-1">
@change="saveSettings" v-model="settings.enable_stats" true-value="True" false-value="False" <label class="input-group-text w-50">Explorer stats publishing</label>
/> <label class="input-group-text w-50">
<label class="form-check-label" for="ExplorerStatsSwitch" <div class="form-check form-switch form-check-inline">
>Publish stats</label <input
> class="form-check-input"
</div> type="checkbox"
</label> id="ExplorerStatsSwitch"
</div> @change="saveSettings"
v-model="settings.enable_stats"
true-value="True"
false-value="False"
/>
<label class="form-check-label" for="ExplorerStatsSwitch"
>Publish stats</label
>
</div>
</label>
</div>
</template> </template>

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,270 +51,247 @@ 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 frames = "";
var data = "";
if (typeof chatFile !== "undefined") {
var file = chatFile;
var filetype = chatFileType;
var filename = chatFileName;
} else {
var file = "";
var filetype = "text";
var filename = "";
}
var file_checksum = ""; //crc32(file).toString(16).toUpperCase();
var checksum = "";
var message_type = "broadcast_transmit";
var command = "";
var mode = '' var timestamp = Math.floor(Date.now() / 1000);
var frames = '' var uuid = uuidv4();
var data = '' // TODO: Not sure what this uuid part is needed for ...
if (typeof chatFile !== "undefined"){ let uuidlast = uuid.lastIndexOf("-");
var file = chatFile; uuidlast += 1;
var filetype = chatFileType if (uuidlast > 0) {
var filename = chatFileName uuid = uuid.substring(uuidlast);
} else { }
var file = ''; // slice uuid for reducing overhead
var filetype = 'text' uuid = uuid.slice(-4);
var filename = ''
}
var file_checksum = ''//crc32(file).toString(16).toUpperCase();
var checksum = ''
var message_type = 'broadcast_transmit'
var command = ''
var timestamp = Math.floor(Date.now() / 1000) var data_with_attachment =
var uuid = uuidv4(); timestamp +
// TODO: Not sure what this uuid part is needed for ... split_char +
let uuidlast = uuid.lastIndexOf("-"); chatmessage +
uuidlast += 1; split_char +
if (uuidlast > 0) { filename +
uuid = uuid.substring(uuidlast); split_char +
} filetype +
// slice uuid for reducing overhead split_char +
uuid = uuid.slice(-4); file;
var data_with_attachment = var tnc_command = "broadcast";
timestamp +
split_char +
chatmessage +
split_char +
filename +
split_char +
filetype +
split_char +
file;
var tnc_command = "broadcast"; sendMessage(dxcallsign, data_with_attachment, checksum, uuid, tnc_command);
sendMessage( let newChatObj = new Object();
dxcallsign,
data_with_attachment,
checksum,
uuid,
tnc_command
)
let newChatObj = new Object(); newChatObj.command = "msg";
newChatObj.hmac_signed = false;
newChatObj.command = "msg" newChatObj.percent = 0;
newChatObj.hmac_signed = false newChatObj.bytesperminute;
newChatObj.percent = 0 newChatObj.is_new = false;
newChatObj.bytesperminute newChatObj._id = uuid;
newChatObj.is_new = false newChatObj.timestamp = timestamp;
newChatObj._id = uuid newChatObj.dxcallsign = dxcallsign;
newChatObj.timestamp = timestamp newChatObj.dxgrid = "null";
newChatObj.dxcallsign = dxcallsign newChatObj.msg = chatmessage;
newChatObj.dxgrid = "null" newChatObj.checksum = file_checksum;
newChatObj.msg = chatmessage newChatObj.type = message_type;
newChatObj.checksum = file_checksum newChatObj.status = "transmitting";
newChatObj.type = message_type newChatObj.attempt = 1;
newChatObj.status = "transmitting" newChatObj.uuid = uuid;
newChatObj.attempt = 1 newChatObj._attachments = {
newChatObj.uuid = uuid [filename]: {
newChatObj._attachments = { content_type: filetype,
[filename]: { data: FD.btoa_FD(file),
content_type: filetype, },
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,
if (typeof chatFile !== "undefined"){ chatFileName,
var file = chatFile; chatFileSize,
var filetype = chatFileType chatFileType,
var filename = chatFileName ) {
} else { var mode = "";
var file = ''; var frames = "";
var filetype = 'text' var data = "";
var filename = '' if (typeof chatFile !== "undefined") {
} var file = chatFile;
var file_checksum = ''//crc32(file).toString(16).toUpperCase(); var filetype = chatFileType;
var checksum = '' var filename = chatFileName;
var message_type = 'transmit' } else {
var command = '' var file = "";
var filetype = "text";
var filename = "";
}
var file_checksum = ""; //crc32(file).toString(16).toUpperCase();
var checksum = "";
var message_type = "transmit";
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("-");
uuidlast += 1; uuidlast += 1;
if (uuidlast > 0) { if (uuidlast > 0) {
uuid = uuid.substring(uuidlast); uuid = uuid.substring(uuidlast);
} }
// slice uuid for reducing overhead // slice uuid for reducing overhead
uuid = uuid.slice(-8); uuid = uuid.slice(-8);
var data_with_attachment =
timestamp +
split_char +
chatmessage +
split_char +
filename +
split_char +
filetype +
split_char +
file;
var tnc_command = "msg";
sendMessage(dxcallsign, data_with_attachment, checksum, uuid, tnc_command);
var data_with_attachment = let newChatObj = new Object();
timestamp +
split_char +
chatmessage +
split_char +
filename +
split_char +
filetype +
split_char +
file;
var tnc_command = "msg"; newChatObj.command = "msg";
newChatObj.hmac_signed = false;
sendMessage( newChatObj.percent = 0;
dxcallsign, newChatObj.bytesperminute;
data_with_attachment, newChatObj.is_new = false;
checksum, newChatObj._id = uuid;
uuid, newChatObj.timestamp = timestamp;
tnc_command newChatObj.dxcallsign = dxcallsign;
) newChatObj.dxgrid = "null";
newChatObj.msg = chatmessage;
let newChatObj = new Object(); newChatObj.checksum = file_checksum;
newChatObj.type = message_type;
newChatObj.command = "msg" newChatObj.status = "transmitting";
newChatObj.hmac_signed = false newChatObj.attempt = 1;
newChatObj.percent = 0 newChatObj.uuid = uuid;
newChatObj.bytesperminute newChatObj._attachments = {
newChatObj.is_new = false [filename]: {
newChatObj._id = uuid content_type: filetype,
newChatObj.timestamp = timestamp data: FD.btoa_FD(file),
newChatObj.dxcallsign = dxcallsign },
newChatObj.dxgrid = "null" };
newChatObj.msg = chatmessage
newChatObj.checksum = file_checksum
newChatObj.type = message_type
newChatObj.status = "transmitting"
newChatObj.attempt = 1
newChatObj.uuid = uuid
newChatObj._attachments = {
[filename]: {
content_type: filetype,
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]) { reorderedData[dxcallsign] = [];
reorderedData[dxcallsign] = []; }
} reorderedData[dxcallsign].push(obj);
reorderedData[dxcallsign].push(obj); }
} });
}); //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 );
// the removed entry should be removed now from gui
chat.sorted_chat_list = sortChatList()
// 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
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
updateUnsortedChatListEntry(obj.uuid, "percent", obj.percent)
updateUnsortedChatListEntry(obj.uuid, "bytesperminute", obj.bytesperminute)
updateUnsortedChatListEntry(obj.uuid, "status", obj.status)
// update screen rendering / messages
updateUnsortedChatListEntry(obj.uuid, "percent", obj.percent);
updateUnsortedChatListEntry(obj.uuid, "bytesperminute", obj.bytesperminute);
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) {
if (!doc[object]) {
db.upsert(id, function (doc) {
if (!doc[object]) {
doc[object] = value;
}
doc[object] = value; doc[object] = value;
return doc; }
}).then(function (res) { doc[object] = value;
return doc;
})
.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,49 +316,37 @@ 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
const jsonData = [item]
const dxcallsign = obj.dxcallsign
// Process each JSON item step by step
jsonData.forEach(jsonitem => {
const { snr, timestamp } = item;
// Check if dxcallsign already exists as a property in the result object
if (!chat.sorted_beacon_list[dxcallsign]) {
// If not, initialize it with an empty array for snr values
chat.sorted_beacon_list[dxcallsign] = {
dxcallsign,
snr: [],
timestamp: [],
};
}
// Push the snr value to the corresponding dxcallsign's snr array
chat.sorted_beacon_list[dxcallsign].snr.push(snr);
chat.sorted_beacon_list[dxcallsign].timestamp.push(timestamp);
});
// TODO: sort beacon list .... maybe a part for a separate function
const jsonData = [item];
const dxcallsign = obj.dxcallsign;
// Process each JSON item step by step
jsonData.forEach((jsonitem) => {
const { snr, timestamp } = item;
// Check if dxcallsign already exists as a property in the result object
if (!chat.sorted_beacon_list[dxcallsign]) {
// If not, initialize it with an empty array for snr values
chat.sorted_beacon_list[dxcallsign] = {
dxcallsign,
snr: [],
timestamp: [],
};
}
// Push the snr value to the corresponding dxcallsign's snr array
chat.sorted_beacon_list[dxcallsign].snr.push(snr);
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,12 +370,11 @@ 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) {
console.log("upsert") console.log("upsert")
@ -430,24 +383,23 @@ function addObjToDatabase(newobj){
} else { } else {
console.log("new...") console.log("new...")
*/ */
db.post(newobj) db.post(newobj)
.then(function (response) { .then(function (response) {
// handle response // handle response
console.log("new database entry"); console.log("new database entry");
console.log(response); console.log(response);
}) })
.catch(function (err) { .catch(function (err) {
console.log(err); console.log(err);
}); });
console.log(newobj);
if (newobj.command === "msg") {
chat.unsorted_chat_list.push(newobj);
chat.sorted_chat_list = sortChatList();
}
console.log(newobj) /*
if(newobj.command === 'msg'){
chat.unsorted_chat_list.push(newobj)
chat.sorted_chat_list = sortChatList()
}
/*
// upsert footer ... // upsert footer ...
} }
@ -456,8 +408,6 @@ function addObjToDatabase(newobj){
*/ */
} }
function createChatIndex() { function createChatIndex() {
db.createIndex({ db.createIndex({
index: { index: {
@ -489,54 +439,50 @@ function createChatIndex() {
}); });
} }
export function deleteChatByCallsign(callsign) {
chat.callsign_list.delete(callsign);
delete chat.unsorted_chat_list.callsign;
delete chat.sorted_chat_list.callsign;
export function deleteChatByCallsign(callsign){ deleteFromDatabaseByCallsign(callsign);
chat.callsign_list.delete(callsign)
delete chat.unsorted_chat_list.callsign
delete chat.sorted_chat_list.callsign
deleteFromDatabaseByCallsign(callsign)
} }
function deleteFromDatabaseByCallsign(callsign){ function deleteFromDatabaseByCallsign(callsign) {
db.find({ db.find({
selector: { selector: {
dxcallsign: callsign, dxcallsign: callsign,
}, },
}) })
.then(function (result) { .then(function (result) {
// handle result // handle result
if (typeof result !== "undefined") { if (typeof result !== "undefined") {
result.docs.forEach(function (item) { result.docs.forEach(function (item) {
console.log(item); console.log(item);
db.get(item._id) db.get(item._id)
.then(function (doc) {
db.remove(doc)
.then(function (doc) { .then(function (doc) {
db.remove(doc) updateAllChat(true);
.then(function (doc) { return true;
updateAllChat(true);
return true;
})
.catch(function (err) {
console.log(err);
});
}) })
.catch(function (err) { .catch(function (err) {
console.log(err); console.log(err);
}); });
})
.catch(function (err) {
console.log(err);
}); });
}
})
.catch(function (err) {
console.log(err);
}); });
}
})
.catch(function (err) {
console.log(err);
});
} }
// function for handling a received beacon // function for handling a received beacon
export function newBeaconReceived(obj){ export function newBeaconReceived(obj) {
/* /*
{ {
"freedata": "tnc-message", "freedata": "tnc-message",
"beacon": "received", "beacon": "received",
@ -548,52 +494,47 @@ export function newBeaconReceived(obj){
"mycallsign": "DJ2LS-0" "mycallsign": "DJ2LS-0"
} }
*/ */
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
// Process each JSON item step by step
jsonData.forEach(item => {
const { snr, timestamp } = obj;
// Check if dxcallsign already exists as a property in the result object
if (!chat.sorted_beacon_list[dxcallsign]) {
// If not, initialize it with an empty array for snr values
chat.sorted_beacon_list[dxcallsign] = {
dxcallsign,
snr: [],
timestamp: [],
};
}
// Push the snr value to the corresponding dxcallsign's snr array
chat.sorted_beacon_list[dxcallsign].snr.push(snr);
chat.sorted_beacon_list[dxcallsign].timestamp.push(timestamp);
});
const jsonData = [obj];
const dxcallsign = obj.dxcallsign;
// Process each JSON item step by step
jsonData.forEach((item) => {
const { snr, timestamp } = obj;
// Check if dxcallsign already exists as a property in the result object
if (!chat.sorted_beacon_list[dxcallsign]) {
// If not, initialize it with an empty array for snr values
chat.sorted_beacon_list[dxcallsign] = {
dxcallsign,
snr: [],
timestamp: [],
};
}
// Push the snr value to the corresponding dxcallsign's snr array
chat.sorted_beacon_list[dxcallsign].snr.push(snr);
chat.sorted_beacon_list[dxcallsign].timestamp.push(timestamp);
});
} }
// function for handling a received message // function for handling a received message
export function newMessageReceived(message, protocol){ export function newMessageReceived(message, protocol) {
/* /*
PROTOCOL PROTOCOL
{ {
@ -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,20 +238,18 @@ 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,
deviceport, deviceport,
@ -291,26 +283,25 @@ 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) {
//exports.saveMyCall = function (callsign) { //exports.saveMyCall = function (callsign) {
command = command =
'{"type" : "set", "command": "mycallsign" , "parameter": "' + '{"type" : "set", "command": "mycallsign" , "parameter": "' +
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,48 +93,40 @@ if (!fs.existsSync(configPath)) {
fs.writeFileSync(configPath, configDefaultSettings); fs.writeFileSync(configPath, configDefaultSettings);
} }
export function loadSettings() {
// load settings
var config = require(configPath);
export function loadSettings(){ //config validation
// load settings // check running config against default config.
var config = require(configPath); // if parameter not exists, add it to running config to prevent errors
console.log("CONFIG VALIDATION ----------------------------- ");
//config validation
// check running config against default config.
// if parameter not exists, add it to running config to prevent errors
console.log("CONFIG VALIDATION ----------------------------- ");
var parsedConfig = JSON.parse(configDefaultSettings);
for (var key in parsedConfig) {
if (config.hasOwnProperty(key)) {
console.log("FOUND SETTTING [" + key + "]: " + config[key]);
} else {
console.log("MISSING SETTTING [" + key + "] : " + parsedConfig[key]);
config[key] = parsedConfig[key];
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
}
try{
if (key == "mycall"){
settings.mycall = config[key].split("-")[0]
settings.myssid = config[key].split("-")[1]
var parsedConfig = JSON.parse(configDefaultSettings);
for (var key in parsedConfig) {
if (config.hasOwnProperty(key)) {
console.log("FOUND SETTTING [" + key + "]: " + config[key]);
} else { } else {
settings[key] = config[key]; console.log("MISSING SETTTING [" + key + "] : " + parsedConfig[key]);
config[key] = parsedConfig[key];
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
}
try {
if (key == "mycall") {
settings.mycall = config[key].split("-")[0];
settings.myssid = config[key].split("-")[1];
} else {
settings[key] = config[key];
}
} catch (e) {
console.log(e);
} }
} catch(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;
}); });
@ -72,16 +69,15 @@ client.on("error", function (data) {
console.log("TNC connection error"); console.log("TNC connection error");
tncShowConnectStateError = 0; tncShowConnectStateError = 0;
} }
setTimeout(connectTNC, 500); setTimeout(connectTNC, 500);
client.destroy(); client.destroy();
stateStore.busy_state = "-"; stateStore.busy_state = "-";
stateStore.arq_state = "-"; stateStore.arq_state = "-";
stateStore.frequency = "-"; stateStore.frequency = "-";
stateStore.mode = "-"; stateStore.mode = "-";
stateStore.bandwidth = "-"; stateStore.bandwidth = "-";
stateStore.dbfs_level = 0; stateStore.dbfs_level = 0;
stateStore.updateTncState(client.readyState) stateStore.updateTncState(client.readyState);
}); });
/* /*
@ -92,21 +88,21 @@ client.on('close', function(data) {
*/ */
client.on("end", function (data) { client.on("end", function (data) {
console.log("TNC connection ended"); console.log("TNC connection ended");
stateStore.busy_state = "-"; stateStore.busy_state = "-";
stateStore.arq_state = "-"; stateStore.arq_state = "-";
stateStore.frequency = "-"; stateStore.frequency = "-";
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,59 +169,63 @@ 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.arq_total_bytes = data["total_bytes"];
stateStore.heard_stations = data["stations"] stateStore.heard_stations = data["stations"];
stateStore.dxcallsign = data["dxcallsign"] stateStore.dxcallsign = data["dxcallsign"];
stateStore.beacon_state = data["beacon_state"] stateStore.beacon_state = data["beacon_state"];
stateStore.audio_recording = data["audio_recording"] stateStore.audio_recording = data["audio_recording"];
stateStore.hamlib_status = data["hamlib_status"] stateStore.hamlib_status = data["hamlib_status"];
stateStore.alc = data["alc"] stateStore.alc = data["alc"];
stateStore.rf_level = data["rf_level"] stateStore.rf_level = data["rf_level"];
stateStore.is_codec2_traffic = data["is_codec2_traffic"] stateStore.is_codec2_traffic = data["is_codec2_traffic"];
stateStore.arq_session_state = data["arq_session"] stateStore.arq_session_state = data["arq_session"];
stateStore.arq_state = data["arq_state"] stateStore.arq_state = data["arq_state"];
stateStore.arq_transmission_percent = data["arq_transmission_percent"] stateStore.arq_transmission_percent = data["arq_transmission_percent"];
stateStore.arq_seconds_until_finish = data["arq_seconds_until_finish"] stateStore.arq_seconds_until_finish = data["arq_seconds_until_finish"];
stateStore.arq_seconds_until_timeout = data["arq_seconds_until_timeout"] stateStore.arq_seconds_until_timeout =
stateStore.arq_seconds_until_timeout_percent = (stateStore.arq_seconds_until_timeout / 180) * 100 data["arq_seconds_until_timeout"];
stateStore.arq_seconds_until_timeout_percent =
if(data["speed_list"].length > 0){ (stateStore.arq_seconds_until_timeout / 180) * 100;
prepareStatsDataForStore(data["speed_list"])
}
if (data["speed_list"].length > 0) {
prepareStatsDataForStore(data["speed_list"]);
}
// TODO: Remove ported objects // TODO: Remove ported objects
let Data = { let Data = {
@ -245,7 +244,7 @@ client.on("data", function (socketdata) {
arq_rx_frame_n_bursts: data["arq_rx_frame_n_bursts"], arq_rx_frame_n_bursts: data["arq_rx_frame_n_bursts"],
arq_rx_n_current_arq_frame: data["arq_rx_n_current_arq_frame"], arq_rx_n_current_arq_frame: data["arq_rx_n_current_arq_frame"],
arq_n_arq_frames_per_data_frame: arq_n_arq_frames_per_data_frame:
data["arq_n_arq_frames_per_data_frame"], data["arq_n_arq_frames_per_data_frame"],
arq_bytes_per_minute: data["arq_bytes_per_minute"], arq_bytes_per_minute: data["arq_bytes_per_minute"],
arq_compression_factor: data["arq_compression_factor"], arq_compression_factor: data["arq_compression_factor"],
routing_table: data["routing_table"], routing_table: data["routing_table"],
@ -260,18 +259,15 @@ 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":
@ -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,30 +389,28 @@ 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;
case "receiving": case "receiving":
@ -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) {
@ -519,52 +522,51 @@ function hexToBytes(hex) {
//Get TNC State //Get TNC State
//exports.getTncState = function () { //exports.getTncState = function () {
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) {
export function sendPing(dxcallsign){ export function sendPing(dxcallsign) {
var command = var command =
'{"type" : "ping", "command" : "ping", "dxcallsign" : "' + '{"type" : "ping", "command" : "ping", "dxcallsign" : "' +
dxcallsign + dxcallsign +
'"}'; '"}';
writeTncCommand(command); writeTncCommand(command);
}; }
// Send Mesh Ping // Send Mesh Ping
//exports.sendMeshPing = function (dxcallsign) { //exports.sendMeshPing = function (dxcallsign) {
function sendMeshPing(dxcallsign){ function sendMeshPing(dxcallsign) {
command = command =
'{"type" : "mesh", "command" : "ping", "dxcallsign" : "' + '{"type" : "mesh", "command" : "ping", "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“
@ -694,57 +689,52 @@ function sendResponse(dxcallsign, mode, frames, data, command) {
//Send station info request //Send station info request
//exports.sendRequestInfo = function (dxcallsign) { //exports.sendRequestInfo = function (dxcallsign) {
function sendRequestInfo(dxcallsign){ function sendRequestInfo(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, "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) {
function sendRequestSharedFile(dxcallsign, file){ function sendRequestSharedFile(dxcallsign, file) {
//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, "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) {
function sendResponseInfo(dxcallsign, userinfo){ function sendResponseInfo(dxcallsign, userinfo) {
//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
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) {
function sendResponseSharedFolderList(dxcallsign, sharedFolderList){ function sendResponseSharedFolderList(dxcallsign, sharedFolderList) {
//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
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,62 +745,62 @@ 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() {
var command = '{"type" : "get", "command" : "rx_buffer"}'; var command = '{"type" : "get", "command" : "rx_buffer"}';
// call command only if new data arrived // call command only if new data arrived
if (rxBufferLengthGui != rxBufferLengthTnc) { if (rxBufferLengthGui != rxBufferLengthTnc) {
writeTncCommand(command); writeTncCommand(command);
} }
}; }
// START BEACON // START BEACON
export function startBeacon(interval){ export function startBeacon(interval) {
var command = var command =
'{"type" : "broadcast", "command" : "start_beacon", "parameter": "' + '{"type" : "broadcast", "command" : "start_beacon", "parameter": "' +
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) {
command = command =
'{"type" : "arq", "command" : "connect", "dxcallsign": "' + '{"type" : "arq", "command" : "connect", "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) {
var command = var command =
'{"type" : "fec", "command" : "transmit", "mode" : "' + '{"type" : "fec", "command" : "transmit", "mode" : "' +
mode + mode +
@ -818,19 +808,19 @@ 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) {
var command = var command =
'{"type" : "fec", "command" : "transmit_is_writing", "mycallsign" : "' + '{"type" : "fec", "command" : "transmit_is_writing", "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) {
let checksum = ""; let checksum = "";
let command = ""; let command = "";
let data = FD.btoa_FD( let data = FD.btoa_FD(
@ -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,12 +885,10 @@ 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}]
if (typeof data == "undefined") { if (typeof data == "undefined") {
var speed_listSize = 0; var speed_listSize = 0;
@ -908,16 +896,15 @@ 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;
var h = new Date(timestamp).getHours(); var h = new Date(timestamp).getHours();
var m = new Date(timestamp).getMinutes(); var m = new Date(timestamp).getMinutes();
@ -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,25 +1,25 @@
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() {
var html = ""; var html = "";
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,41 +1,58 @@
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" },
{ type: "transmit" }, { type: "transmit" },
{ type: "ping-ack" }, { type: "ping-ack" },
{ type: "broadcast_received" }, { type: "broadcast_received" },
{ 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 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 chartSpeedPER25 = ref() // 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 chartSpeedPER75 = ref() var beaconDataArray = ref([]);
var beaconLabelArray = 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]) return {
// 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']) selectedCallsign,
var beaconDataArray = ref([]) inputText,
var beaconLabelArray = ref([]) chat_filter,
callsign_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 }; 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,151 +1,141 @@
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
var tnc_host = ref("127.0.0.1");
var tnc_port = ref(3000);
var daemon_host = ref(tnc_host.value);
var daemon_port = ref(tnc_port.value + 1);
// app
var screen_height = ref(430);
var screen_width = ref(1050);
var theme = ref("default");
var wftheme = ref(2);
var high_graphics = ref("False");
var auto_start = ref(0);
var enable_sys_notification = ref(1);
// network // chat
var tnc_host = ref("127.0.0.1") var shared_folder_path = ref(".");
var tnc_port = ref(3000) var enable_request_profile = ref("True");
var daemon_host = ref(tnc_host.value) var enable_request_shared_folder = ref("False");
var daemon_port = ref(tnc_port.value + 1) var max_retry_attempts = ref(5);
var enable_auto_retry = ref("False");
// app // station
var screen_height = ref(430) var mycall = ref("AA0AA-5");
var screen_width = ref(1050) var myssid = ref(0);
var theme = ref("default") var mygrid = ref("JN20aa");
var wftheme = ref(2)
var high_graphics = ref("False")
var auto_start = ref(0)
var enable_sys_notification = ref(1)
// chat // rigctld
var shared_folder_path = ref(".") var hamlib_rigctld_port = ref(4532);
var enable_request_profile = ref("True") var hamlib_rigctld_ip = ref("127.0.0.1");
var enable_request_shared_folder = ref("False") var radiocontrol = ref("disabled");
var max_retry_attempts = ref(5) var hamlib_deviceid = ref("RIG_MODEL_DUMMY_NOVFO");
var enable_auto_retry = ref("False") var hamlib_deviceport = ref("ignore");
var hamlib_stop_bits = ref("ignore");
var hamlib_data_bits = ref("ignore");
var hamlib_handshake = ref("ignore");
var hamlib_serialspeed = ref("ignore");
var hamlib_dtrstate = ref("ignore");
var hamlib_pttprotocol = ref("ignore");
var hamlib_ptt_port = ref("ignore");
var hamlib_dcd = ref("ignore");
var hamlbib_serialspeed_ptt = ref(9600);
var hamlib_rigctld_port = ref(4532);
var hamlib_rigctld_ip = ref("127.0.0.1");
var hamlib_rigctld_path = ref("");
var hamlib_rigctld_server_port = ref(4532);
var hamlib_rigctld_custom_args = ref("");
// station // tci
var mycall = ref("AA0AA-5") var tci_ip = ref("127.0.0.1");
var myssid = ref(0) var tci_port = ref(50001);
var mygrid = ref("JN20aa")
// rigctld
var hamlib_rigctld_port = ref(4532)
var hamlib_rigctld_ip = ref("127.0.0.1")
var radiocontrol = ref("disabled")
var hamlib_deviceid = ref("RIG_MODEL_DUMMY_NOVFO")
var hamlib_deviceport = ref("ignore")
var hamlib_stop_bits = ref("ignore")
var hamlib_data_bits = ref("ignore")
var hamlib_handshake = ref("ignore")
var hamlib_serialspeed = ref("ignore")
var hamlib_dtrstate = ref("ignore")
var hamlib_pttprotocol = ref("ignore")
var hamlib_ptt_port = ref("ignore")
var hamlib_dcd = ref("ignore")
var hamlbib_serialspeed_ptt = ref(9600)
var hamlib_rigctld_port = ref(4532)
var hamlib_rigctld_ip = ref("127.0.0.1")
var hamlib_rigctld_path = ref("")
var hamlib_rigctld_server_port = ref(4532)
var hamlib_rigctld_custom_args = ref("")
// tci
var tci_ip = ref('127.0.0.1')
var tci_port = ref(50001)
//tnc
var spectrum = ref("waterfall")
var enable_scatter = ref("False")
var enable_fft = ref("False")
var enable_fsk = ref("False")
var low_bandwidth_mode = ref("False")
var update_channel = ref("latest")
var beacon_interval = ref(300)
var received_files_folder = ref("None")
var tuning_range_fmin = ref(-50.0)
var tuning_range_fmax = ref(50.0)
var respond_to_cq = ref("True")
var rx_buffer_size = ref(16)
var enable_explorer = ref("False")
var explorer_stats = ref("False")
var auto_tune = ref("False")
var enable_is_writing = ref("True")
var tx_delay = ref(0)
var enable_mesh_features = ref("False")
function getJSON(){
var config_export = {
"tnc_host": tnc_host.value,
"tnc_port": tnc_port.value,
"daemon_host": tnc_host.value,
"daemon_port": (parseInt(tnc_port.value) + 1).toString(),
"mycall": mycall.value,
"myssid": myssid.value,
"mygrid": mygrid.value,
"radiocontrol" : radiocontrol.value,
"hamlib_deviceid": hamlib_deviceid.value,
"hamlib_deviceport": hamlib_deviceport.value,
"hamlib_stop_bits": hamlib_stop_bits.value,
"hamlib_data_bits": hamlib_data_bits.value,
"hamlib_handshake": hamlib_handshake.value,
"hamlib_serialspeed": hamlib_serialspeed.value,
"hamlib_dtrstate": hamlib_dtrstate.value,
"hamlib_pttprotocol": hamlib_pttprotocol.value,
"hamlib_ptt_port": hamlib_ptt_port.value,
"hamlib_dcd": hamlib_dcd.value,
"hamlbib_serialspeed_ptt": hamlib_serialspeed.value,
"hamlib_rigctld_port" : hamlib_rigctld_port.value,
"hamlib_rigctld_ip" : hamlib_rigctld_ip.value,
"hamlib_rigctld_path" : hamlib_rigctld_path.value,
"hamlib_rigctld_server_port" : hamlib_rigctld_server_port.value,
"hamlib_rigctld_custom_args": hamlib_rigctld_custom_args.value,
"tci_port" : tci_port.value,
"tci_ip" : tci_ip.value,
"spectrum": spectrum.value,
"enable_scatter" : enable_scatter.value,
"enable_fft" : enable_fft.value,
"enable_fsk" : enable_fsk.value,
"low_bandwidth_mode" : low_bandwidth_mode.value,
"theme" : theme.value,
"screen_height" : screen_height.value,
"screen_width" : screen_width.value,
"update_channel" : update_channel.value,
"beacon_interval" : beacon_interval.value,
"received_files_folder" : received_files_folder.value,
"tuning_range_fmin" : tuning_range_fmin.value,
"tuning_range_fmax" : tuning_range_fmax.value,
"respond_to_cq" : respond_to_cq.value,
"rx_buffer_size" : rx_buffer_size.value,
"enable_explorer" : enable_explorer.value,
"wftheme": wftheme.value,
"high_graphics" : high_graphics.value,
"explorer_stats" : explorer_stats.value,
"auto_tune" : auto_tune.value,
"enable_is_writing" : enable_is_writing.value,
"shared_folder_path" : shared_folder_path.value,
"enable_request_profile" : enable_request_profile.value,
"enable_request_shared_folder" : enable_request_shared_folder.value,
"max_retry_attempts" : max_retry_attempts.value,
"enable_auto_retry" : enable_auto_retry.value,
"tx_delay" : tx_delay.value,
"auto_start": auto_start.value,
"enable_sys_notification": enable_sys_notification.value,
"enable_mesh_features": enable_mesh_features.value
}
return config_export
}
//tnc
var spectrum = ref("waterfall");
var enable_scatter = ref("False");
var enable_fft = ref("False");
var enable_fsk = ref("False");
var low_bandwidth_mode = ref("False");
var update_channel = ref("latest");
var beacon_interval = ref(300);
var received_files_folder = ref("None");
var tuning_range_fmin = ref(-50.0);
var tuning_range_fmax = ref(50.0);
var respond_to_cq = ref("True");
var rx_buffer_size = ref(16);
var enable_explorer = ref("False");
var explorer_stats = ref("False");
var auto_tune = ref("False");
var enable_is_writing = ref("True");
var tx_delay = ref(0);
var enable_mesh_features = ref("False");
function getJSON() {
var config_export = {
tnc_host: tnc_host.value,
tnc_port: tnc_port.value,
daemon_host: tnc_host.value,
daemon_port: (parseInt(tnc_port.value) + 1).toString(),
mycall: mycall.value,
myssid: myssid.value,
mygrid: mygrid.value,
radiocontrol: radiocontrol.value,
hamlib_deviceid: hamlib_deviceid.value,
hamlib_deviceport: hamlib_deviceport.value,
hamlib_stop_bits: hamlib_stop_bits.value,
hamlib_data_bits: hamlib_data_bits.value,
hamlib_handshake: hamlib_handshake.value,
hamlib_serialspeed: hamlib_serialspeed.value,
hamlib_dtrstate: hamlib_dtrstate.value,
hamlib_pttprotocol: hamlib_pttprotocol.value,
hamlib_ptt_port: hamlib_ptt_port.value,
hamlib_dcd: hamlib_dcd.value,
hamlbib_serialspeed_ptt: hamlib_serialspeed.value,
hamlib_rigctld_port: hamlib_rigctld_port.value,
hamlib_rigctld_ip: hamlib_rigctld_ip.value,
hamlib_rigctld_path: hamlib_rigctld_path.value,
hamlib_rigctld_server_port: hamlib_rigctld_server_port.value,
hamlib_rigctld_custom_args: hamlib_rigctld_custom_args.value,
tci_port: tci_port.value,
tci_ip: tci_ip.value,
spectrum: spectrum.value,
enable_scatter: enable_scatter.value,
enable_fft: enable_fft.value,
enable_fsk: enable_fsk.value,
low_bandwidth_mode: low_bandwidth_mode.value,
theme: theme.value,
screen_height: screen_height.value,
screen_width: screen_width.value,
update_channel: update_channel.value,
beacon_interval: beacon_interval.value,
received_files_folder: received_files_folder.value,
tuning_range_fmin: tuning_range_fmin.value,
tuning_range_fmax: tuning_range_fmax.value,
respond_to_cq: respond_to_cq.value,
rx_buffer_size: rx_buffer_size.value,
enable_explorer: enable_explorer.value,
wftheme: wftheme.value,
high_graphics: high_graphics.value,
explorer_stats: explorer_stats.value,
auto_tune: auto_tune.value,
enable_is_writing: enable_is_writing.value,
shared_folder_path: shared_folder_path.value,
enable_request_profile: enable_request_profile.value,
enable_request_shared_folder: enable_request_shared_folder.value,
max_retry_attempts: max_retry_attempts.value,
enable_auto_retry: enable_auto_retry.value,
tx_delay: tx_delay.value,
auto_start: auto_start.value,
enable_sys_notification: enable_sys_notification.value,
enable_mesh_features: enable_mesh_features.value,
};
return config_export;
}
return { return {
tnc_host, tnc_host,
@ -207,7 +197,5 @@ var config_export = {
tx_delay, tx_delay,
enable_mesh_features, enable_mesh_features,
getJSON, getJSON,
};
} });
})

View file

@ -1,126 +1,144 @@
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 dxcallsign = ref("")
var arq_session_state = ref("") var heard_stations = ref("");
var arq_state = ref("") var dxcallsign = ref("");
var beacon_state = ref("False")
var audio_recording = ref("") var arq_session_state = ref("");
var arq_state = ref("");
var beacon_state = ref("False");
var hamlib_status = ref("") var audio_recording = ref("");
var audio_level = ref("")
var alc = ref("")
var is_codec2_traffic = ref("") var hamlib_status = ref("");
var audio_level = ref("");
var alc = 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_speed_list_timestamp = ref([]) var arq_seconds_until_finish = ref();
var arq_speed_list_bpm = ref([]) var arq_seconds_until_timeout = ref();
var arq_speed_list_snr = ref([]) var arq_seconds_until_timeout_percent = 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
var collapseFirstRow = new bootstrap.Collapse(
document.getElementById("collapseFirstRow"),
{ toggle: false },
);
collapseFirstRow.hide();
var collapseSecondRow = new bootstrap.Collapse(
document.getElementById("collapseSecondRow"),
{ toggle: false },
);
collapseSecondRow.hide();
var collapseThirdRow = new bootstrap.Collapse(
document.getElementById("collapseThirdRow"),
{ toggle: false },
);
collapseThirdRow.show();
var collapseFourthRow = new bootstrap.Collapse(
document.getElementById("collapseFourthRow"),
{ toggle: false },
);
collapseFourthRow.show();
// collapse settings screen //Set tuning for fancy graphics mode (high/low CPU)
var collapseFirstRow = new bootstrap.Collapse( //set_CPU_mode();
document.getElementById("collapseFirstRow"),
{ toggle: false },
);
collapseFirstRow.hide();
var collapseSecondRow = new bootstrap.Collapse(
document.getElementById("collapseSecondRow"),
{ toggle: false },
);
collapseSecondRow.hide();
var collapseThirdRow = new bootstrap.Collapse(
document.getElementById("collapseThirdRow"),
{ toggle: false },
);
collapseThirdRow.show();
var collapseFourthRow = new bootstrap.Collapse(
document.getElementById("collapseFourthRow"),
{ toggle: false },
);
collapseFourthRow.show();
//Set tuning for fancy graphics mode (high/low CPU) //GUI will auto connect to TNC if already running, if that is the case increment start count if 0
//set_CPU_mode(); if (tncStartCount.value == 0) tncStartCount.value++;
} else {
//GUI will auto connect to TNC if already running, if that is the case increment start count if 0 // collapse settings screen
if (tncStartCount.value == 0) tncStartCount++; var collapseFirstRow = new bootstrap.Collapse(
} else { document.getElementById("collapseFirstRow"),
{ toggle: false },
// collapse settings screen );
var collapseFirstRow = new bootstrap.Collapse( collapseFirstRow.show();
document.getElementById("collapseFirstRow"), var collapseSecondRow = new bootstrap.Collapse(
{ toggle: false }, document.getElementById("collapseSecondRow"),
); { toggle: false },
collapseFirstRow.show(); );
var collapseSecondRow = new bootstrap.Collapse( collapseSecondRow.show();
document.getElementById("collapseSecondRow"), var collapseThirdRow = new bootstrap.Collapse(
{ toggle: false }, document.getElementById("collapseThirdRow"),
); { toggle: false },
collapseSecondRow.show(); );
var collapseThirdRow = new bootstrap.Collapse( collapseThirdRow.hide();
document.getElementById("collapseThirdRow"), var collapseFourthRow = new bootstrap.Collapse(
{ toggle: false }, document.getElementById("collapseFourthRow"),
); { toggle: false },
collapseThirdRow.hide(); );
var collapseFourthRow = new bootstrap.Collapse( collapseFourthRow.hide();
document.getElementById("collapseFourthRow"), }
{ toggle: false },
);
collapseFourthRow.hide();
} }
};
return {
dxcallsign,
busy_state,
arq_state,
new_frequency,
frequency,
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 }; 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,
};
}); });