Merge branch 'develop' of github.com:DJ2LS/FreeDATA into develop

This commit is contained in:
Mashintime 2023-12-09 11:36:04 -05:00
commit 41e13770b8
8 changed files with 87 additions and 75 deletions

View file

@ -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>

View file

@ -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>

View file

@ -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''

View file

@ -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):

View file

@ -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):

View file

@ -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"},

View file

@ -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)

View file

@ -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