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/host/modem/ModemV24.h

411 lines
12 KiB

// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Modem Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2024-2025 Bryan Biedenkapp, N2PLL
*
*/
/**
* @file ModemV24.h
* @ingroup modem
* @file ModemV24.cpp
* @ingroup modem
*/
#if !defined(__MODEM_V24_H__)
#define __MODEM_V24_H__
#include "Defines.h"
#include "common/edac/RS634717.h"
#include "common/p25/dfsi/frames/MotVoiceHeader1.h"
#include "common/p25/dfsi/frames/MotVoiceHeader2.h"
#include "common/p25/lc/LC.h"
#include "common/p25/Audio.h"
#include "common/p25/NID.h"
#include "modem/Modem.h"
namespace modem
{
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
/**
* @addtogroup modem
* @{
*/
/**
* @brief DFSI serial tx flags used to determine proper jitter handling of data in ringbuffer.
* @ingroup modem
*/
enum SERIAL_TX_TYPE {
STT_NO_DATA, //! No Data
STT_NON_IMBE, //! Non-IMBE Data/Signalling Frame
STT_NON_IMBE_NO_JITTER, //! Non-IMBE Data/Signalling Frame with Jitter Disabled
STT_IMBE //! IMBE Voice Frame
};
/** @} */
// ---------------------------------------------------------------------------
// Class Declaration
// ---------------------------------------------------------------------------
/**
* @brief Represents DFSI call data.
* @ingroup modem
*/
class HOST_SW_API DFSICallData {
public:
auto operator=(DFSICallData&) -> DFSICallData& = delete;
auto operator=(DFSICallData&&) -> DFSICallData& = delete;
DFSICallData(DFSICallData&) = delete;
/**
* @brief Initializes a new instance of the DFSICallData class.
*/
DFSICallData() :
srcId(0U),
dstId(0U),
lco(0U),
mfId(P25DEF::MFG_STANDARD),
serviceOptions(0U),
lsd1(0U),
lsd2(0U),
MI(nullptr),
algoId(P25DEF::ALGO_UNENCRYPT),
kId(0U),
VHDR1(nullptr),
VHDR2(nullptr),
netLDU1(nullptr),
netLDU2(nullptr)
{
MI = new uint8_t[P25DEF::MI_LENGTH_BYTES];
VHDR1 = new uint8_t[p25::dfsi::frames::MotVoiceHeader1::HCW_LENGTH];
VHDR2 = new uint8_t[p25::dfsi::frames::MotVoiceHeader2::HCW_LENGTH];
netLDU1 = new uint8_t[9U * 25U];
netLDU2 = new uint8_t[9U * 25U];
::memset(netLDU1, 0x00U, 9U * 25U);
::memset(netLDU2, 0x00U, 9U * 25U);
resetCallData();
}
/**
* @brief Finalizes a instance of the DFSICallData class.
*/
~DFSICallData()
{
if (MI != nullptr)
delete[] MI;
if (VHDR1 != nullptr)
delete[] VHDR1;
if (VHDR2 != nullptr)
delete[] VHDR2;
if (netLDU1 != nullptr)
delete[] netLDU1;
if (netLDU2 != nullptr)
delete[] netLDU2;
}
/**
* @brief Helper to reset the call data associated with this connection.
*/
void resetCallData()
{
srcId = 0U;
dstId = 0U;
lco = 0U;
mfId = P25DEF::MFG_STANDARD;
serviceOptions = 0U;
lsd1 = 0U;
lsd2 = 0U;
if (MI != nullptr)
::memset(MI, 0x00U, P25DEF::MI_LENGTH_BYTES);
algoId = P25DEF::ALGO_UNENCRYPT;
kId = 0U;
if (VHDR1 != nullptr)
::memset(VHDR1, 0x00U, p25::dfsi::frames::MotVoiceHeader1::HCW_LENGTH);
if (VHDR2 != nullptr)
::memset(VHDR2, 0x00U, p25::dfsi::frames::MotVoiceHeader2::HCW_LENGTH);
if (netLDU1 != nullptr)
::memset(netLDU1, 0x00U, 9U * 25U);
if (netLDU2 != nullptr)
::memset(netLDU2, 0x00U, 9U * 25U);
n = 0U;
seqNo = 0U;
}
public:
/** @name Call Data */
/**
* @brief Source Radio ID.
*/
uint32_t srcId;
/**
* @brief Destination ID.
*/
uint32_t dstId;
/**
* @brief Link Control Opcode.
*/
uint8_t lco;
/**
* @brief Manufacturer ID.
*/
uint8_t mfId;
/**
* @brief Call Service Options.
*/
uint8_t serviceOptions;
/**
* @brief Low Speed Data 1.
*/
uint8_t lsd1;
/**
* @brief Low Speed Data 2.
*/
uint8_t lsd2;
/**
* @brief Encryption Message Indicator.
*/
uint8_t* MI;
/**
* @brief Encryption Algorithm ID.
*/
uint8_t algoId;
/**
* @brief Encryption Key ID.
*/
uint32_t kId;
/**
* @brief Voice Header 1.
*/
uint8_t* VHDR1;
/**
* @brief Voice Header 2.
*/
uint8_t* VHDR2;
/**
* @brief Sequence Number.
*/
uint32_t seqNo;
/**
* @brief
*/
uint8_t n;
/**
* @brief LDU1 Buffer.
*/
uint8_t* netLDU1;
/**
* @brief LDU2 Buffer.
*/
uint8_t* netLDU2;
/** @} */
};
// ---------------------------------------------------------------------------
// Class Declaration
// ---------------------------------------------------------------------------
/**
* @brief Implements the core interface to the V.24 modem hardware.
* @ingroup modem
*/
class HOST_SW_API ModemV24 : public Modem {
public:
/**
* @brief Initializes a new instance of the ModemV24 class.
* @param port Port the air interface modem is connected to.
* @param duplex Flag indicating the modem is operating in duplex mode.
* @param p25QueueSize Modem P25 Rx frame buffer queue size (bytes).
* @param p25TxQueueSize Modem P25 Tx frame buffer queue size (bytes).
* @param rtrt Flag indicating whether or not RT/RT is enabled.
* @param diu Flag indicating whether or not V.24 communications are to a DIU.
* @param jitter
* @param dumpModemStatus Flag indicating whether the modem status is dumped to the log.
* @param trace Flag indicating whether air interface modem trace is enabled.
* @param debug Flag indicating whether air interface modem debug is enabled.
*/
ModemV24(port::IModemPort* port, bool duplex, uint32_t p25QueueSize, uint32_t p25TxQueueSize,
bool rtrt, bool diu, uint16_t jitter, bool dumpModemStatus, bool trace, bool debug);
/**
* @brief Finalizes a instance of the ModemV24 class.
*/
~ModemV24();
/**
* @brief Sets the call timeout.
* @param timeout Timeout.
*/
void setCallTimeout(uint16_t timeout);
/**
* @brief Sets the P25 NAC.
* @param nac NAC.
*/
void setP25NAC(uint32_t nac) override;
/**
* @brief Helper to set the TIA-102 format DFSI frame flag.
* @param set
*/
void setTIAFormat(bool set);
/**
* @brief Opens connection to the air interface modem.
* @returns bool True, if connection to modem is made, otherwise false.
*/
bool open() override;
/**
* @brief Updates the modem by the passed number of milliseconds.
* @param ms Number of milliseconds.
*/
void clock(uint32_t ms) override;
/**
* @brief Closes connection to the air interface modem.
*/
void close() override;
/**
* @brief Helper to test if the P25 ring buffer has free space.
* @returns bool True, if the P25 ring buffer has free space, otherwise false.
*/
bool hasP25Space(uint32_t length) const override;
/**
* @brief Writes raw data to the air interface modem.
* @param data Data to write to modem.
* @param length Length of data to write.
* @returns int Actual length of data written.
*/
int write(const uint8_t* data, uint32_t length) override;
private:
bool m_rtrt;
bool m_diu;
uint8_t m_superFrameCnt;
p25::Audio m_audio;
p25::NID* m_nid;
RingBuffer<uint8_t> m_txP25Queue;
DFSICallData* m_txCall;
DFSICallData* m_rxCall;
bool m_txCallInProgress;
bool m_rxCallInProgress;
uint64_t m_txLastFrameTime;
uint64_t m_rxLastFrameTime;
uint16_t m_callTimeout;
uint16_t m_jitter;
uint64_t m_lastP25Tx;
edac::RS634717 m_rs;
bool m_useTIAFormat;
/**
* @brief Helper to write data from the P25 Tx queue to the serial interface.
* @return int Actual number of bytes written to the serial interface.
*/
int writeSerial();
/**
* @brief Helper to store converted Rx frames.
* @param buffer Buffer containing converted Rx frame.
* @param length Length of buffer.
*/
void storeConvertedRx(const uint8_t* buffer, uint32_t length);
/**
* @brief Helper to generate a P25 TDU packet.
* @param buffer Buffer to create TDU.
*/
void create_TDU(uint8_t* buffer);
/**
* @brief Internal helper to convert from V.24/DFSI to TIA-102 air interface.
* @param data Buffer containing data to convert.
* @param length Length of buffer.
*/
void convertToAir(const uint8_t *data, uint32_t length);
/**
* @brief Internal helper to convert from TIA-102 DFSI to TIA-102 air interface.
* @param data Buffer containing data to convert.
* @param length Length of buffer.
*/
void convertToAirTIA(const uint8_t *data, uint32_t length);
/**
* @brief Helper to add a V.24 data frame to the P25 Tx queue with the proper timestamp and formatting.
* @param data Buffer containing V.24 data frame to send.
* @param len Length of buffer.
* @param msgType Type of message to send (used for proper jitter clocking).
*/
void queueP25Frame(uint8_t* data, uint16_t length, SERIAL_TX_TYPE msgType);
/**
* @brief Send a start of stream sequence (HDU, etc) to the connected serial V24 device.
* @param[in] control Instance of p25::lc::LC containing link control data.
*/
void startOfStream(const p25::lc::LC& control);
/**
* @brief Send an end of stream sequence (TDU, etc) to the connected serial V24 device.
*/
void endOfStream();
/**
* @brief Helper to generate the NID value.
* @param duid P25 DUID.
* @returns uint16_t P25 NID.
*/
uint16_t generateNID(P25DEF::DUID::E duid = P25DEF::DUID::LDU1);
/**
* @brief Send a start of stream sequence (HDU, etc) to the connected UDP TIA-102 device.
* @param[in] control Instance of p25::lc::LC containing link control data.
*/
void startOfStreamTIA(const p25::lc::LC& control);
/**
* @brief Send an end of stream sequence (TDU, etc) to the connected UDP TIA-102 device.
*/
void endOfStreamTIA();
/**
* @brief Internal helper to convert from TIA-102 air interface to V.24/DFSI.
* @param data Buffer containing data to convert.
* @param length Length of buffer.
*/
void convertFromAir(uint8_t* data, uint32_t length);
/**
* @brief Internal helper to convert from TIA-102 air interface to TIA-102 DFSI.
* @param data Buffer containing data to convert.
* @param length Length of buffer.
*/
void convertFromAirTIA(uint8_t* data, uint32_t length);
};
} // namespace modem
#endif // __MODEM_V24_H__

Powered by TurnKey Linux.