You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dvmhost/src/sysview/TransmitWndBase.h

393 lines
11 KiB

// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - FNE System View
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file TransmitWndBase.h
* @ingroup fneSysView
*/
#if !defined(__TRANSMIT_WND_BASE_H__)
#define __TRANSMIT_WND_BASE_H__
#include "common/lookups/AffiliationLookup.h"
#include "common/dmr/DMRDefines.h"
#include "common/dmr/lc/CSBK.h"
#include "common/dmr/lc/csbk/CSBKFactory.h"
#include "common/dmr/SlotType.h"
#include "common/dmr/Sync.h"
#include "common/p25/P25Defines.h"
#include "common/p25/lc/LC.h"
#include "common/p25/lc/TSBK.h"
#include "common/p25/lc/tsbk/TSBKFactory.h"
#include "common/p25/Sync.h"
#include "host/modem/Modem.h"
#include "SysViewMain.h"
#include "FDblDialog.h"
#include <final/final.h>
using namespace finalcut;
// ---------------------------------------------------------------------------
// Class Declaration
// ---------------------------------------------------------------------------
/**
* @brief This class implements the line edit control for RIDs.
* @ingroup fneSysView
*/
class HOST_SW_API RIDLineEdit final : public FLineEdit {
public:
/**
* @brief Initializes a new instance of the RIDLineEdit class.
* @param widget
*/
explicit RIDLineEdit(FWidget* widget = nullptr) : FLineEdit{widget}
{
setInputFilter("[[:digit:]]");
}
/*
** Event Handlers
*/
/**
* @brief Event that occurs on keyboard key press.
* @param e Keyboard Event.
*/
void onKeyPress(finalcut::FKeyEvent* e) override
{
const auto key = e->key();
if (key == FKey::Up) {
emitCallback("up-pressed");
e->accept();
return;
} else if (key == FKey::Down) {
emitCallback("down-pressed");
e->accept();
return;
}
FLineEdit::onKeyPress(e);
}
};
// ---------------------------------------------------------------------------
// Class Declaration
// ---------------------------------------------------------------------------
/**
* @brief This class implements the base class for transmit windows.
* @ingroup fneSysView
*/
class HOST_SW_API TransmitWndBase : public FDblDialog {
public:
/**
* @brief Initializes a new instance of the TransmitWndBase class.
* @param widget
*/
explicit TransmitWndBase(FWidget* widget = nullptr) : FDblDialog{widget}
{
/* stub */
}
protected:
uint8_t m_mode = modem::STATE_DMR;
/**
* @brief Initializes the window layout.
*/
void initLayout() override
{
FDialog::setMinimizable(true);
FDialog::setShadow();
std::size_t maxWidth, maxHeight;
const auto& rootWidget = getRootWidget();
if (rootWidget) {
maxWidth = rootWidget->getClientWidth();
maxHeight = rootWidget->getClientHeight();
}
else {
// fallback to xterm default size
maxWidth = 80;
maxHeight = 24;
}
const int x = 1 + int((maxWidth - getWidth()) / 2);
const int y = 1 + int((maxHeight - getHeight()) / 3);
FWindow::setPos(FPoint{x, y}, false);
FDialog::adjustSize();
FDialog::setModal();
initControls();
FDialog::initLayout();
rootWidget->redraw(); // bryanb: wtf?
redraw();
}
/**
* @brief Initializes window controls.
*/
virtual void initControls()
{
resizeControls();
m_dmrSlotLabel.setGeometry(FPoint(2, 4), FSize(10, 1));
m_dmrSlot.setGeometry(FPoint(18, 4), FSize(5, 1));
m_dmrSlot.setRange(1, 2);
m_dmrSlot.setValue(1);
m_dmrSlot.setShadow(false);
m_digModeGroup.setGeometry(FPoint(2, 1), FSize(56, 2));
m_modeDMR.setPos(FPoint(1, 1));
m_modeDMR.addCallback("toggled", [&]() {
if (m_modeDMR.isChecked()) {
m_mode = modem::STATE_DMR;
m_dmrSlot.setEnable(true);
redraw();
}
});
m_modeP25.setPos(FPoint(13, 1));
m_modeP25.addCallback("toggled", [&]() {
if (m_modeP25.isChecked()) {
m_mode = modem::STATE_P25;
m_dmrSlot.setEnable(false);
redraw();
}
});
/*
m_modeNXDN.setPos(FPoint(22, 1));
m_modeNXDN.addCallback("toggled", [&]() {
if (m_modeNXDN.isChecked()) {
m_mode = modem::STATE_NXDN;
m_dmrSlot.setEnable(false);
redraw();
}
});
*/
focusFirstChild();
}
/**
* @brief
*/
void resizeControls()
{
// transmit button and close button logic
m_txButton.setGeometry(FPoint(3, int(getHeight()) - 6), FSize(10, 3));
m_txButton.addCallback("clicked", [&]() { setTransmit(); });
m_closeButton.setGeometry(FPoint(17, int(getHeight()) - 6), FSize(9, 3));
m_closeButton.addCallback("clicked", [&]() { hide(); });
}
/**
* @brief Adjusts window size.
*/
void adjustSize() override
{
FDialog::adjustSize();
}
/*
** Event Handlers
*/
/**
* @brief Event that occurs on keyboard key press.
* @param e Keyboard Event.
*/
void onKeyPress(finalcut::FKeyEvent* e) override
{
const auto key = e->key();
if (key == FKey::Escape) {
this->close();
}
else if (key == FKey::F12) {
setTransmit();
}
}
/**
* @brief Event that occurs when the window is closed.
* @param e Close Event
*/
void onClose(FCloseEvent* e) override
{
hide();
}
protected:
/**
* @brief Helper to write a DMR extended function packet.
* @param slot DMR slot number.
* @param func
* @param arg
* @param dstId
*/
void writeDMR_Ext_Func(uint8_t slot, uint32_t func, uint32_t arg, uint32_t dstId)
{
using namespace dmr;
using namespace dmr::defines;
using namespace dmr::lc::csbk;
std::unique_ptr<CSBK_EXT_FNCT> csbk = std::make_unique<CSBK_EXT_FNCT>();
csbk->setGI(false);
csbk->setExtendedFunction(func);
csbk->setSrcId(arg);
csbk->setDstId(dstId);
LogMessage(LOG_RF, "DMR Slot %u, CSBK, %s, op = $%02X, arg = %u, tgt = %u",
slot, csbk->toString().c_str(), func, arg, dstId);
write_CSBK(slot, csbk.get());
}
/**
* @brief Helper to write a network CSBK.
* @param slot DMR slot number.
* @param csbk Instance of dmr::lc::CSBK.
*/
void write_CSBK(uint8_t slot, dmr::lc::CSBK* csbk)
{
using namespace dmr;
using namespace dmr::defines;
uint8_t data[DMR_FRAME_LENGTH_BYTES + 2U];
::memset(data + 2U, 0x00U, DMR_FRAME_LENGTH_BYTES);
SlotType slotType;
slotType.setColorCode(0U);
slotType.setDataType(DataType::CSBK);
// Regenerate the CSBK data
csbk->encode(data + 2U);
// Regenerate the Slot Type
slotType.encode(data + 2U);
// Convert the Data Sync to be from the BS or MS as needed
Sync::addDMRDataSync(data + 2U, true);
data::NetData dmrData;
dmrData.setSlotNo(slot);
dmrData.setDataType(DataType::CSBK);
dmrData.setSrcId(csbk->getSrcId());
dmrData.setDstId(csbk->getDstId());
dmrData.setFLCO(csbk->getGI() ? FLCO::GROUP : FLCO::PRIVATE);
dmrData.setN(0U);
dmrData.setSeqNo(0U);
dmrData.setBER(0U);
dmrData.setRSSI(0U);
dmrData.setData(data + 2U);
getNetwork()->writeDMR(dmrData);
}
/**
* @brief Helper to write a P25 extended function packet.
* @param func
* @param arg
* @param dstId
*/
void writeP25_Ext_Func(uint32_t func, uint32_t arg, uint32_t dstId)
{
using namespace p25;
using namespace p25::defines;
using namespace p25::lc::tsbk;
std::unique_ptr<IOSP_EXT_FNCT> iosp = std::make_unique<IOSP_EXT_FNCT>();
iosp->setExtendedFunction(func);
iosp->setSrcId(arg);
iosp->setDstId(dstId);
// class $02 is Motorola -- set the MFID properly
if ((func >> 8) == 0x02U) {
iosp->setMFId(MFG_MOT);
}
LogMessage(LOG_RF, P25_TSDU_STR ", %s, mfId = $%02X, op = $%02X, arg = %u, tgt = %u",
iosp->toString().c_str(), iosp->getMFId(), iosp->getExtendedFunction(), iosp->getSrcId(), iosp->getDstId());
write_TSDU(iosp.get());
}
/**
* @brief Helper to write a network TSDU.
* @param tsbk Instance of p25::lc::TSBK.
*/
void write_TSDU(p25::lc::TSBK* tsbk)
{
using namespace p25;
using namespace p25::defines;
uint8_t data[P25_TSDU_FRAME_LENGTH_BYTES];
::memset(data, 0x00U, P25_TSDU_FRAME_LENGTH_BYTES);
// Generate Sync
Sync::addP25Sync(data);
// network bursts have no NID
// Generate TSBK block
tsbk->setLastBlock(true); // always set last block -- this a Single Block TSDU
tsbk->encode(data);
// Add busy bits
P25Utils::addStatusBits(data, P25_TSDU_FRAME_LENGTH_BYTES, false);
// Set first busy bits to 1,1
P25Utils::setStatusBits(data, P25_SS0_START, true, true);
if (g_debug) {
LogDebug(LOG_RF, P25_TSDU_STR ", lco = $%02X, mfId = $%02X, lastBlock = %u, AIV = %u, EX = %u, srcId = %u, dstId = %u, sysId = $%03X, netId = $%05X",
tsbk->getLCO(), tsbk->getMFId(), tsbk->getLastBlock(), tsbk->getAIV(), tsbk->getEX(), tsbk->getSrcId(), tsbk->getDstId(),
tsbk->getSysId(), tsbk->getNetId());
Utils::dump(1U, "!!! *TSDU (SBF) TSBK Block Data", data + P25_PREAMBLE_LENGTH_BYTES, P25_TSBK_FEC_LENGTH_BYTES);
}
lc::LC lc = lc::LC();
lc.setLCO(tsbk->getLCO());
lc.setMFId(tsbk->getMFId());
lc.setSrcId(tsbk->getSrcId());
lc.setDstId(tsbk->getDstId());
getNetwork()->writeP25TSDU(lc, data);
}
/**
* @brief Helper to transmit.
*/
virtual void setTransmit()
{
/* stub */
}
FButton m_txButton{"Transmit", this};
FButton m_closeButton{"Close", this};
FButtonGroup m_digModeGroup{"Digital Mode", this};
FRadioButton m_modeDMR{"DMR", &m_digModeGroup};
FRadioButton m_modeP25{"P25", &m_digModeGroup};
// FRadioButton m_modeNXDN{"NXDN", &m_digModeGroup};
FLabel m_dmrSlotLabel{"DMR Slot: ", this};
FSpinBox m_dmrSlot{this};
};
#endif // __TRANSMIT_WND_BASE_H__

Powered by TurnKey Linux.