mirror of
https://github.com/DJ2LS/FreeDATA
synced 2024-05-14 08:04:33 +00:00
Merge branch 'develop' of github.com:DJ2LS/FreeDATA into develop
This commit is contained in:
commit
41e13770b8
|
@ -51,7 +51,8 @@ const gridWidgets = [
|
|||
{ x: 0, y: 0, w: 16, h: 40 },
|
||||
"Detailed heard stations list",
|
||||
true,
|
||||
true,"Activity"
|
||||
true,
|
||||
"Activity",
|
||||
),
|
||||
new gridWidget(
|
||||
active_stats,
|
||||
|
@ -59,7 +60,7 @@ const gridWidgets = [
|
|||
"Stats (waterfall, etc)",
|
||||
true,
|
||||
true,
|
||||
"Stats"
|
||||
"Stats",
|
||||
),
|
||||
new gridWidget(
|
||||
active_audio_level,
|
||||
|
@ -75,7 +76,7 @@ const gridWidgets = [
|
|||
"Rig control main",
|
||||
true,
|
||||
true,
|
||||
"Rig"
|
||||
"Rig",
|
||||
),
|
||||
new gridWidget(
|
||||
active_broadcats,
|
||||
|
@ -83,7 +84,7 @@ const gridWidgets = [
|
|||
"Broadcats main",
|
||||
true,
|
||||
true,
|
||||
"Broadcasts"
|
||||
"Broadcasts",
|
||||
),
|
||||
new gridWidget(
|
||||
mini_heard_stations,
|
||||
|
@ -91,16 +92,23 @@ const gridWidgets = [
|
|||
"Mini heard stations list",
|
||||
false,
|
||||
true,
|
||||
"Activity"
|
||||
"Activity",
|
||||
),
|
||||
new gridWidget(
|
||||
s_meter,
|
||||
{ x: 1, y: 1, w: 4, h: 8 },
|
||||
"S-Meter",
|
||||
false,
|
||||
true,
|
||||
"Rig",
|
||||
),
|
||||
new gridWidget(s_meter, { x: 1, y: 1, w: 4, h: 8 }, "S-Meter", false, true, "Rig"),
|
||||
new gridWidget(
|
||||
dbfs_meter,
|
||||
{ x: 1, y: 1, w: 4, h: 8 },
|
||||
"Dbfs Meter",
|
||||
false,
|
||||
true,
|
||||
"Audio"
|
||||
"Audio",
|
||||
),
|
||||
new gridWidget(
|
||||
grid_activities,
|
||||
|
@ -110,7 +118,6 @@ const gridWidgets = [
|
|||
true,
|
||||
"Activity",
|
||||
),
|
||||
|
||||
];
|
||||
onMounted(() => {
|
||||
grid = GridStack.init({
|
||||
|
@ -137,23 +144,23 @@ onMounted(() => {
|
|||
|
||||
grid.on("change", onChange);
|
||||
|
||||
gridWidgets.forEach((gw) =>{
|
||||
gridWidgets.forEach((gw) => {
|
||||
//Dynamically add widgets to widget menu
|
||||
let dom = document.getElementById("otherBod");
|
||||
switch (gw.category) {
|
||||
case "Activity":
|
||||
dom = document.getElementById("actBody");
|
||||
break;
|
||||
case "Stats":
|
||||
case "Stats":
|
||||
dom = document.getElementById("statsBody");
|
||||
break;
|
||||
case "Audio":
|
||||
case "Audio":
|
||||
dom = document.getElementById("audioBody");
|
||||
break;
|
||||
case "Rig":
|
||||
case "Rig":
|
||||
dom = document.getElementById("rigBody");
|
||||
break;
|
||||
case "Broadcasts":
|
||||
case "Broadcasts":
|
||||
dom = document.getElementById("bcBody");
|
||||
break;
|
||||
default:
|
||||
|
@ -161,7 +168,7 @@ onMounted(() => {
|
|||
break;
|
||||
}
|
||||
var index = gridWidgets.findIndex((w) => gw.text == w.text);
|
||||
dom.insertAdjacentHTML("beforeend",`<div id="gridbtn-${index}""></div>`);
|
||||
dom.insertAdjacentHTML("beforeend", `<div id="gridbtn-${index}""></div>`);
|
||||
let dom2 = document.getElementById(`gridbtn-${index}`);
|
||||
let vueComponent = h(grid_button,{btnText: gw.text,btnID:index});
|
||||
render(vueComponent,dom2);
|
||||
|
@ -274,7 +281,7 @@ function quickfill() {
|
|||
<h5 class="offcanvas-title" id="offcanvasGridItemsLabel">
|
||||
Manage grid widgets
|
||||
</h5>
|
||||
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn-close"
|
||||
|
@ -283,8 +290,10 @@ function quickfill() {
|
|||
></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<p>Grid widgets allow you to customize the display for your own usage. Here you may add additional widgets to fit your needs.
|
||||
You can move and resize the individual widgets!
|
||||
<p>
|
||||
Grid widgets allow you to customize the display for your own usage. Here
|
||||
you may add additional widgets to fit your needs. You can move and
|
||||
resize the individual widgets!
|
||||
</p>
|
||||
<div>
|
||||
<button
|
||||
|
@ -294,10 +303,8 @@ function quickfill() {
|
|||
>
|
||||
Fill grid with common widgets
|
||||
</button>
|
||||
|
||||
|
||||
</div>
|
||||
<hr>
|
||||
<hr />
|
||||
<!-- Begin widget selector -->
|
||||
<div class="accordion" id="accordionExample">
|
||||
<!-- Heard Stations -->
|
||||
|
@ -320,9 +327,7 @@ function quickfill() {
|
|||
aria-labelledby="headingHeardStations"
|
||||
data-bs-parent="#accordionExample"
|
||||
>
|
||||
<div class="accordion-body" id="actBody">
|
||||
|
||||
</div>
|
||||
<div class="accordion-body" id="actBody"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -346,9 +351,7 @@ function quickfill() {
|
|||
aria-labelledby="headingActivities"
|
||||
data-bs-parent="#accordionExample"
|
||||
>
|
||||
<div class="accordion-body" id="audioBody">
|
||||
|
||||
</div>
|
||||
<div class="accordion-body" id="audioBody"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Broadcasts -->
|
||||
|
@ -371,9 +374,7 @@ function quickfill() {
|
|||
aria-labelledby="headingBroadcasts"
|
||||
data-bs-parent="#accordionExample"
|
||||
>
|
||||
<div class="accordion-body" id="bcBody">
|
||||
|
||||
</div>
|
||||
<div class="accordion-body" id="bcBody"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Radio Control -->
|
||||
|
@ -396,9 +397,7 @@ function quickfill() {
|
|||
aria-labelledby="headingRadioControl"
|
||||
data-bs-parent="#accordionExample"
|
||||
>
|
||||
<div class="accordion-body" id="rigBody">
|
||||
|
||||
</div>
|
||||
<div class="accordion-body" id="rigBody"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -422,9 +421,7 @@ function quickfill() {
|
|||
aria-labelledby="headingAudioControl"
|
||||
data-bs-parent="#accordionExample"
|
||||
>
|
||||
<div class="accordion-body" id="statsBody">
|
||||
|
||||
</div>
|
||||
<div class="accordion-body" id="statsBody"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -448,20 +445,18 @@ function quickfill() {
|
|||
aria-labelledby="headingStatistics"
|
||||
data-bs-parent="#accordionExample"
|
||||
>
|
||||
<div class="accordion-body" id="otherBod">
|
||||
|
||||
</div>
|
||||
<div class="accordion-body" id="otherBod"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<hr />
|
||||
<button
|
||||
class="btn btn-sm btn-outline-warning"
|
||||
type="button"
|
||||
@click="clearAllItems"
|
||||
>
|
||||
Clear grid
|
||||
</button>
|
||||
class="btn btn-sm btn-outline-warning"
|
||||
type="button"
|
||||
@click="clearAllItems"
|
||||
>
|
||||
Clear grid
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
<script setup lang="ts">
|
||||
import { defineProps } from 'vue';
|
||||
const props = defineProps(['btnText','btnID']);
|
||||
import { defineProps } from "vue";
|
||||
const props = defineProps(["btnText", "btnID"]);
|
||||
|
||||
function emitClick() {
|
||||
window.dispatchEvent(new CustomEvent("add-widget", { detail: props.btnID }));
|
||||
window.dispatchEvent(new CustomEvent("add-widget", { detail: props.btnID }));
|
||||
}
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<button class="btn btn-small btn-outline-secondary" v-on:click="emitClick">{{ btnText}}</button>
|
||||
<button class="btn btn-small btn-outline-secondary" v-on:click="emitClick">
|
||||
{{ btnText }}
|
||||
</button>
|
||||
</template>
|
||||
|
|
|
@ -13,7 +13,7 @@ class ARQSessionIRS(arq_session.ARQSession):
|
|||
RETRIES_CONNECT = 3
|
||||
RETRIES_TRANSFER = 3
|
||||
|
||||
TIMEOUT_DATA = 2
|
||||
TIMEOUT_DATA = 6
|
||||
|
||||
def __init__(self, config: dict, tx_frame_queue: queue.Queue, dxcall: str, session_id: int):
|
||||
super().__init__(config, tx_frame_queue, dxcall)
|
||||
|
@ -35,7 +35,7 @@ class ARQSessionIRS(arq_session.ARQSession):
|
|||
pass
|
||||
|
||||
def set_state(self, state):
|
||||
self.log(f"ARQ Session {self.id} state {self.state}")
|
||||
self.log(f"ARQ Session IRS {self.id} state {self.state}")
|
||||
self.state = state
|
||||
|
||||
def set_modem_decode_modes(self, modes):
|
||||
|
@ -50,24 +50,25 @@ class ARQSessionIRS(arq_session.ARQSession):
|
|||
self.transmit_frame(ack_frame)
|
||||
|
||||
self.set_modem_decode_modes(None)
|
||||
|
||||
self.state = self.STATE_WAITING_DATA
|
||||
while self.state == self.STATE_WAITING_DATA:
|
||||
if not self.event_data_received.wait(self.TIMEOUT_DATA):
|
||||
self.log("Timeout waiting for data")
|
||||
self.state = self.STATE_FAILED
|
||||
return
|
||||
|
||||
|
||||
self.log("Finished ARQ IRS session")
|
||||
|
||||
def run(self):
|
||||
self.thread = threading.Thread(target=self.runner, name=f"ARQ IRS Session {self.id}", daemon=True)
|
||||
self.thread.run()
|
||||
self.thread.start()
|
||||
|
||||
|
||||
def on_data_received(self, data_frame):
|
||||
if self.state != self.STATE_WAITING_DATA:
|
||||
raise RuntimeError(f"ARQ Session: Received data while in state {self.state}")
|
||||
raise RuntimeError(f"ARQ Session: Received data while in state {self.state}, expected {self.STATE_WAITING_DATA}")
|
||||
|
||||
self.received_data = data_frame["data"]
|
||||
self.event_data_received.set()
|
||||
|
||||
|
||||
|
@ -87,3 +88,4 @@ class ARQSessionIRS(arq_session.ARQSession):
|
|||
self.event_connection_ack_received.clear()
|
||||
self.event_transfer_feedback.set()
|
||||
self.event_transfer_feedback.clear()
|
||||
self.received_data = b''
|
||||
|
|
|
@ -35,7 +35,7 @@ class ARQSessionISS(arq_session.ARQSession):
|
|||
return random.randint(1,255)
|
||||
|
||||
def set_state(self, state):
|
||||
self.logger.info(f"ARQ Session {self.id} state {self.state}")
|
||||
self.logger.info(f"ARQ Session ISS {self.id} state {self.state}")
|
||||
self.state = state
|
||||
|
||||
def runner(self):
|
||||
|
@ -49,7 +49,7 @@ class ARQSessionISS(arq_session.ARQSession):
|
|||
self.thread.run()
|
||||
|
||||
def connect(self):
|
||||
self.state = self.STATE_CONNECTING
|
||||
self.state = self.STATE_CONNECTING
|
||||
|
||||
connect_frame = self.frame_factory.build_arq_session_connect(True, self.dxcall, self.id)
|
||||
|
||||
|
@ -69,9 +69,10 @@ class ARQSessionISS(arq_session.ARQSession):
|
|||
if self.state != self.STATE_CONNECTING:
|
||||
raise RuntimeError(f"ARQ Session: Received connection ACK while in state {self.state}")
|
||||
|
||||
self.speed_level = ack['speed_level']
|
||||
self.build_arq_data_framespeed_level = ack['speed_level']
|
||||
self.event_connection_ack_received.set()
|
||||
|
||||
|
||||
# Sends the full payload in multiple frames
|
||||
def send_data(self):
|
||||
# Todo make this n frames per burst stuff part of the protocol again
|
||||
|
@ -84,6 +85,7 @@ class ARQSessionISS(arq_session.ARQSession):
|
|||
max_size = self.get_payload_size(self.speed_level)
|
||||
end_offset = min(len(self.data), max_size)
|
||||
frame_payload = self.data[offset:end_offset]
|
||||
print(self.id)
|
||||
data_frame = self.frame_factory.build_arq_data_frame(self.id, n_frames_per_burst, max_size, n_frame, frame_payload)
|
||||
self.set_state(self.STATE_SENDING)
|
||||
if not self.send_arq(data_frame):
|
||||
|
|
|
@ -127,12 +127,12 @@ class DataFrameFactory:
|
|||
|
||||
# arq data frame
|
||||
# register n frames
|
||||
for n_frame in range(0,50):
|
||||
self.template_list[FR_TYPE.BURST_01.value + n_frame] = {
|
||||
for n_frame in range(1,5):
|
||||
self.template_list[FR_TYPE.BURST_01.value + (n_frame-1)] = {
|
||||
"frame_length": "dynamic",
|
||||
"n_frames_per_burst": 1,
|
||||
"session_id": 1,
|
||||
"payload": "dynamic",
|
||||
"data": "dynamic",
|
||||
}
|
||||
|
||||
# arq burst ack
|
||||
|
@ -175,18 +175,19 @@ class DataFrameFactory:
|
|||
|
||||
def construct(self, frametype, content, frame_length=LENGTH_SIG1_FRAME):
|
||||
# frame_length: can be set manually for data frames, whose length can be dynamic regarding corresponding mode
|
||||
|
||||
# data bursts have a frame type range of 01-50
|
||||
if frametype in range(1, 50):
|
||||
frame_template = self.template_list[frametype.value]
|
||||
frame_template = self.template_list[frametype]
|
||||
frame = bytearray(frame_length)
|
||||
# override "dynamic" value of payload length
|
||||
self.template_list[frame_template].payload = frame_length - 3
|
||||
self.template_list[frametype]["data"] = frame_length - 3
|
||||
frame[:1] = bytes([frametype])
|
||||
|
||||
else:
|
||||
frame_template = self.template_list[frametype.value]
|
||||
frame_length = frame_template["frame_length"]
|
||||
frame = bytearray(frame_length)
|
||||
frame[:1] = bytes([frametype.value])
|
||||
|
||||
buffer_position = 1
|
||||
for key, item_length in frame_template.items():
|
||||
|
@ -194,7 +195,6 @@ class DataFrameFactory:
|
|||
frame[buffer_position: buffer_position + item_length] = content[key]
|
||||
buffer_position += item_length
|
||||
|
||||
frame[:1] = bytes([frametype.value])
|
||||
return frame
|
||||
|
||||
def deconstruct(self, frame):
|
||||
|
@ -212,16 +212,24 @@ class DataFrameFactory:
|
|||
|
||||
for key, item_length in frame_template.items():
|
||||
if key != "frame_length":
|
||||
data = frame[buffer_position: buffer_position + item_length]
|
||||
# data is always on the last payload slots
|
||||
if item_length in ["dynamic"] and key in["data"]:
|
||||
data = frame[buffer_position:]
|
||||
item_length = len(data)
|
||||
else:
|
||||
data = frame[buffer_position: buffer_position + item_length]
|
||||
|
||||
# Process the data based on the key
|
||||
if key in ["origin", "destination"]:
|
||||
extracted_data[key] = helpers.bytes_to_callsign(data).decode()
|
||||
|
||||
if key in ["origin_crc", "destination_crc"]:
|
||||
extracted_data[key] = data.hex()
|
||||
|
||||
elif key == "gridsquare":
|
||||
extracted_data[key] = helpers.decode_grid(data)
|
||||
|
||||
elif key in ["session_id", "speed_level"]:
|
||||
elif key in ["session_id", "speed_level", "n_frames_per_burst"]:
|
||||
extracted_data[key] = int.from_bytes(data, 'big')
|
||||
|
||||
else:
|
||||
|
@ -319,9 +327,7 @@ class DataFrameFactory:
|
|||
return test_frame
|
||||
|
||||
def build_arq_session_connect(self, isWideband, destination, session_id):
|
||||
print(isWideband)
|
||||
print(destination)
|
||||
print(session_id)
|
||||
|
||||
payload = {
|
||||
"destination_crc": helpers.get_crc_24(destination),
|
||||
"origin_crc": helpers.get_crc_24(self.myfullcall),
|
||||
|
@ -351,11 +357,11 @@ class DataFrameFactory:
|
|||
def build_arq_data_frame(self, session_id: bytes, n_frames_per_burst: int, max_size: int, n_frame: int, frame_payload: bytes):
|
||||
payload = {
|
||||
"n_frames_per_burst": bytes([n_frames_per_burst]),
|
||||
"session_id": session_id,
|
||||
"session_id": session_id.to_bytes(1, 'big'),
|
||||
"data": frame_payload
|
||||
}
|
||||
|
||||
return self.construct(FR_TYPE.FR_TYPE.BURST_01.value + n_frame, payload, frame_length=max_size)
|
||||
return self.construct(FR_TYPE.BURST_01.value + (n_frame-1), payload, frame_length=max_size)
|
||||
|
||||
|
||||
def build_arq_burst_ack(self, session_id: bytes, snr: int, speed_level: int, len_arq_rx_frame_buffer: int):
|
||||
|
|
|
@ -35,6 +35,7 @@ class DISPATCHER():
|
|||
FR_TYPE.ARQ_CONNECTION_OPEN.value: {"class": ARQFrameHandler, "name": "ARQ OPEN SESSION"},
|
||||
FR_TYPE.ARQ_STOP.value: {"class": ARQFrameHandler, "name": "ARQ STOP TX"},
|
||||
FR_TYPE.BEACON.value: {"class": FrameHandler, "name": "BEACON"},
|
||||
FR_TYPE.BURST_01.value:{"class": ARQFrameHandler, "name": "BURST_01"},
|
||||
FR_TYPE.BURST_ACK.value: {"class": FrameHandler, "name": "BURST ACK"},
|
||||
FR_TYPE.BURST_NACK.value: {"class": FrameHandler, "name": "BURST NACK"},
|
||||
FR_TYPE.CQ.value: {"class": CQFrameHandler, "name": "CQ"},
|
||||
|
|
|
@ -23,3 +23,9 @@ class ARQFrameHandler(frame_handler.FrameHandler):
|
|||
if frame['frame_type_int'] in [FR.ARQ_SESSION_OPEN_ACK_N.value, FR.ARQ_SESSION_OPEN_ACK_W.value]:
|
||||
iss_session:ARQSessionISS = self.states.get_arq_iss_session(frame['session_id'])
|
||||
iss_session.on_connection_ack_received(frame)
|
||||
|
||||
# ARQ session data frame received
|
||||
if frame['frame_type_int'] in [FR.BURST_01.value, FR.BURST_02.value, FR.BURST_03.value, FR.BURST_04.value, FR.BURST_05.value]:
|
||||
print("received data frame....")
|
||||
irs_session:ARQSessionIRS = self.states.get_arq_irs_session(frame['session_id'])
|
||||
irs_session.on_data_received(frame)
|
|
@ -11,8 +11,7 @@ class FRAME_TYPE(Enum):
|
|||
BURST_02 = 2
|
||||
BURST_03 = 3
|
||||
BURST_04 = 4
|
||||
# ...
|
||||
BURST_50 = 50
|
||||
BURST_05 = 5
|
||||
BURST_ACK = 60
|
||||
FR_ACK = 61
|
||||
FR_REPEAT = 62
|
||||
|
|
Loading…
Reference in a new issue