properly set the V.24 Tx buffer size to the FIFO length like done for air and hotspot modems; pass whether or not the frame being written to the modem is an immediate frame; modify V.24 modem to properly maintain two independant buffers, one for background/normal priority frames, and one for immediate priority frames (this helps with CC mode delays, there are more buffering issues, likely at the modem to mitgate but thats a future project);

r05a04_dev
Bryan Biedenkapp 14 hours ago
parent c044e42d90
commit 87ad34f539

@ -721,7 +721,7 @@ bool Host::createModem()
} }
if (m_isModemDFSI) { if (m_isModemDFSI) {
m_modem = new ModemV24(modemPort, m_duplex, m_p25QueueSizeBytes, m_p25QueueSizeBytes, rtrt, jitter, m_modem = new ModemV24(modemPort, m_duplex, m_p25QueueSizeBytes, p25FifoLength, rtrt, jitter,
dumpModemStatus, displayModemDebugMessages, trace, debug); dumpModemStatus, displayModemDebugMessages, trace, debug);
((ModemV24*)m_modem)->setCallTimeout(dfsiCallTimeout); ((ModemV24*)m_modem)->setCallTimeout(dfsiCallTimeout);
((ModemV24*)m_modem)->setTIAFormat(dfsiTIAMode); ((ModemV24*)m_modem)->setTIAFormat(dfsiTIAMode);

@ -267,7 +267,8 @@ void* Host::threadDMRWriter1(void* arg)
} }
} }
uint32_t len = host->m_dmr->getFrame(1U, data); bool imm = false;
uint32_t len = host->m_dmr->getFrame(1U, data, &imm);
if (len > 0U) { if (len > 0U) {
// if the state is idle; set to DMR, start mode timer and start DMR idle frames // if the state is idle; set to DMR, start mode timer and start DMR idle frames
if (host->m_state == STATE_IDLE) { if (host->m_state == STATE_IDLE) {
@ -551,7 +552,8 @@ void* Host::threadDMRWriter2(void* arg)
} }
} }
uint32_t len = host->m_dmr->getFrame(2U, data); bool imm = false;
uint32_t len = host->m_dmr->getFrame(2U, data, &imm);
if (len > 0U) { if (len > 0U) {
// if the state is idle; set to DMR, start mode timer and start DMR idle frames // if the state is idle; set to DMR, start mode timer and start DMR idle frames
if (host->m_state == STATE_IDLE) { if (host->m_state == STATE_IDLE) {

@ -213,7 +213,8 @@ void* Host::threadNXDNWriter(void* arg)
} }
} }
uint32_t len = host->m_nxdn->getFrame(data); bool imm = false;
uint32_t len = host->m_nxdn->getFrame(data, &imm);
if (len > 0U) { if (len > 0U) {
// if the state is idle; set to NXDN and start mode timer // if the state is idle; set to NXDN and start mode timer
if (host->m_state == STATE_IDLE) { if (host->m_state == STATE_IDLE) {

@ -256,7 +256,8 @@ void* Host::threadP25Writer(void* arg)
if (nextLen > 0U) { if (nextLen > 0U) {
bool ret = host->m_modem->hasP25Space(nextLen); bool ret = host->m_modem->hasP25Space(nextLen);
if (ret) { if (ret) {
uint32_t len = host->m_p25->getFrame(data); bool imm = false;
uint32_t len = host->m_p25->getFrame(data, &imm);
if (len > 0U) { if (len > 0U) {
// if the state is idle; set to P25 and start mode timer // if the state is idle; set to P25 and start mode timer
if (host->m_state == STATE_IDLE) { if (host->m_state == STATE_IDLE) {

@ -372,15 +372,15 @@ bool Control::isQueueFull(uint32_t slotNo)
/* Get a data frame for slot, from data ring buffer. */ /* Get a data frame for slot, from data ring buffer. */
uint32_t Control::getFrame(uint32_t slotNo, uint8_t* data) uint32_t Control::getFrame(uint32_t slotNo, uint8_t* data, bool *imm)
{ {
assert(data != nullptr); assert(data != nullptr);
switch (slotNo) { switch (slotNo) {
case 1U: case 1U:
return m_slot1->getFrame(data); return m_slot1->getFrame(data, imm);
case 2U: case 2U:
return m_slot2->getFrame(data); return m_slot2->getFrame(data, imm);
default: default:
LogError(LOG_DMR, "DMR, invalid slot, slotNo = %u", slotNo); LogError(LOG_DMR, "DMR, invalid slot, slotNo = %u", slotNo);
return 0U; return 0U;

@ -159,9 +159,10 @@ namespace dmr
* @brief Get frame data from data ring buffer. * @brief Get frame data from data ring buffer.
* @param slotNo DMR slot number. * @param slotNo DMR slot number.
* @param[out] data Buffer to store frame data. * @param[out] data Buffer to store frame data.
* @param[out] imm Flag indicating whether the frame is immediate.
* @returns uint32_t Length of frame data retrieved. * @returns uint32_t Length of frame data retrieved.
*/ */
uint32_t getFrame(uint32_t slotNo, uint8_t* data); uint32_t getFrame(uint32_t slotNo, uint8_t* data, bool *imm = nullptr);
/** @} */ /** @} */
/** @name Data Clocking */ /** @name Data Clocking */

@ -361,7 +361,7 @@ bool Slot::isQueueFull()
/* Get frame data from data ring buffer. */ /* Get frame data from data ring buffer. */
uint32_t Slot::getFrame(uint8_t* data) uint32_t Slot::getFrame(uint8_t* data, bool* imm)
{ {
assert(data != nullptr); assert(data != nullptr);
@ -374,10 +374,16 @@ uint32_t Slot::getFrame(uint8_t* data)
// tx immediate queue takes priority // tx immediate queue takes priority
if (!m_txImmQueue.isEmpty()) { if (!m_txImmQueue.isEmpty()) {
if (imm != nullptr)
*imm = true;
m_txImmQueue.get(&len, 1U); m_txImmQueue.get(&len, 1U);
m_txImmQueue.get(data, len); m_txImmQueue.get(data, len);
} }
else { else {
if (imm != nullptr)
*imm = false;
m_txQueue.get(&len, 1U); m_txQueue.get(&len, 1U);
m_txQueue.get(data, len); m_txQueue.get(data, len);
} }

@ -146,9 +146,10 @@ namespace dmr
/** /**
* @brief Get frame data from data ring buffer. * @brief Get frame data from data ring buffer.
* @param[out] data Buffer to store frame data. * @param[out] data Buffer to store frame data.
* @param[out] imm Flag indicating whether the frame is immediate.
* @returns uint32_t Length of frame data retrieved. * @returns uint32_t Length of frame data retrieved.
*/ */
uint32_t getFrame(uint8_t* data); uint32_t getFrame(uint8_t* data, bool* imm);
/** /**
* @brief Process a data frames from the network. * @brief Process a data frames from the network.

@ -1371,7 +1371,7 @@ void Modem::injectNXDNFrame(const uint8_t* data, uint32_t length)
/* Writes DMR Slot 1 frame data to the DMR Slot 1 ring buffer. */ /* Writes DMR Slot 1 frame data to the DMR Slot 1 ring buffer. */
bool Modem::writeDMRFrame1(const uint8_t* data, uint32_t length) bool Modem::writeDMRFrame1(const uint8_t* data, uint32_t length, bool imm)
{ {
assert(data != nullptr); assert(data != nullptr);
assert(length > 0U); assert(length > 0U);
@ -1404,7 +1404,7 @@ bool Modem::writeDMRFrame1(const uint8_t* data, uint32_t length)
if (m_trace) if (m_trace)
Utils::dump(1U, "Modem::writeDMRFrame1(), Immediate TX DMR Data 1", buffer + 3U, length - 1U); Utils::dump(1U, "Modem::writeDMRFrame1(), Immediate TX DMR Data 1", buffer + 3U, length - 1U);
int ret = write(buffer, len); int ret = write(buffer, len, imm);
if (ret != int(len)) { if (ret != int(len)) {
LogError(LOG_MODEM, "Error writing DMR slot 1 data"); LogError(LOG_MODEM, "Error writing DMR slot 1 data");
return false; return false;
@ -1425,7 +1425,7 @@ bool Modem::writeDMRFrame1(const uint8_t* data, uint32_t length)
/* Writes DMR Slot 2 frame data to the DMR Slot 2 ring buffer. */ /* Writes DMR Slot 2 frame data to the DMR Slot 2 ring buffer. */
bool Modem::writeDMRFrame2(const uint8_t* data, uint32_t length) bool Modem::writeDMRFrame2(const uint8_t* data, uint32_t length, bool imm)
{ {
assert(data != nullptr); assert(data != nullptr);
assert(length > 0U); assert(length > 0U);
@ -1458,7 +1458,7 @@ bool Modem::writeDMRFrame2(const uint8_t* data, uint32_t length)
if (m_trace) if (m_trace)
Utils::dump(1U, "Modem::writeDMRFrame2(), Immediate TX DMR Data 2", buffer + 3U, length - 1U); Utils::dump(1U, "Modem::writeDMRFrame2(), Immediate TX DMR Data 2", buffer + 3U, length - 1U);
int ret = write(buffer, len); int ret = write(buffer, len, imm);
if (ret != int(len)) { if (ret != int(len)) {
LogError(LOG_MODEM, "Error writing DMR slot 2 data"); LogError(LOG_MODEM, "Error writing DMR slot 2 data");
return false; return false;
@ -1479,7 +1479,7 @@ bool Modem::writeDMRFrame2(const uint8_t* data, uint32_t length)
/* Writes P25 frame data to the P25 ring buffer. */ /* Writes P25 frame data to the P25 ring buffer. */
bool Modem::writeP25Frame(const uint8_t* data, uint32_t length) bool Modem::writeP25Frame(const uint8_t* data, uint32_t length, bool imm)
{ {
assert(data != nullptr); assert(data != nullptr);
assert(length > 0U); assert(length > 0U);
@ -1523,7 +1523,7 @@ bool Modem::writeP25Frame(const uint8_t* data, uint32_t length)
if (m_trace) if (m_trace)
Utils::dump(1U, "Modem::writeP25Frame(), Immediate TX P25 Data", buffer + 3U, length - 3U); Utils::dump(1U, "Modem::writeP25Frame(), Immediate TX P25 Data", buffer + 3U, length - 3U);
int ret = write(buffer, len); int ret = write(buffer, len, imm);
if (ret != int(len)) { if (ret != int(len)) {
LogError(LOG_MODEM, "Error writing P25 data"); LogError(LOG_MODEM, "Error writing P25 data");
return false; return false;
@ -1544,7 +1544,7 @@ bool Modem::writeP25Frame(const uint8_t* data, uint32_t length)
/* Writes NXDN frame data to the NXDN ring buffer. */ /* Writes NXDN frame data to the NXDN ring buffer. */
bool Modem::writeNXDNFrame(const uint8_t* data, uint32_t length) bool Modem::writeNXDNFrame(const uint8_t* data, uint32_t length, bool imm)
{ {
assert(data != nullptr); assert(data != nullptr);
assert(length > 0U); assert(length > 0U);
@ -1577,7 +1577,7 @@ bool Modem::writeNXDNFrame(const uint8_t* data, uint32_t length)
if (m_trace) if (m_trace)
Utils::dump(1U, "Modem::writeNXDNFrame(), Immediate TX NXDN Data", buffer + 3U, length - 1U); Utils::dump(1U, "Modem::writeNXDNFrame(), Immediate TX NXDN Data", buffer + 3U, length - 1U);
int ret = write(buffer, len); int ret = write(buffer, len, imm);
if (ret != int(len)) { if (ret != int(len)) {
LogError(LOG_MODEM, "Error writing NXDN data"); LogError(LOG_MODEM, "Error writing NXDN data");
return false; return false;
@ -1704,7 +1704,7 @@ bool Modem::setDMRIgnoreCACH_AT(uint8_t slotNo)
/* Writes raw data to the air interface modem. */ /* Writes raw data to the air interface modem. */
int Modem::write(const uint8_t* data, uint32_t length) int Modem::write(const uint8_t* data, uint32_t length, bool imm)
{ {
return m_port->write(data, length); return m_port->write(data, length);
} }

@ -602,30 +602,34 @@ namespace modem
* @brief Writes DMR Slot 1 frame data to the DMR Slot 1 ring buffer. * @brief Writes DMR Slot 1 frame data to the DMR Slot 1 ring buffer.
* @param[in] data Data to write to ring buffer. * @param[in] data Data to write to ring buffer.
* @param length Length of data to write. * @param length Length of data to write.
* @param imm Flag indicating whether the frame is immediate.
* @returns bool True, if data is written, otherwise false. * @returns bool True, if data is written, otherwise false.
*/ */
bool writeDMRFrame1(const uint8_t* data, uint32_t length); bool writeDMRFrame1(const uint8_t* data, uint32_t length, bool imm = false);
/** /**
* @brief Writes DMR Slot 2 frame data to the DMR Slot 2 ring buffer. * @brief Writes DMR Slot 2 frame data to the DMR Slot 2 ring buffer.
* @param[in] data Data to write to ring buffer. * @param[in] data Data to write to ring buffer.
* @param length Length of data to write. * @param length Length of data to write.
* @param imm Flag indicating whether the frame is immediate.
* @returns bool True, if data is written, otherwise false. * @returns bool True, if data is written, otherwise false.
*/ */
bool writeDMRFrame2(const uint8_t* data, uint32_t length); bool writeDMRFrame2(const uint8_t* data, uint32_t length, bool imm = false);
/** /**
* @brief Writes P25 frame data to the P25 ring buffer. * @brief Writes P25 frame data to the P25 ring buffer.
* @param[in] data Data to write to ring buffer. * @param[in] data Data to write to ring buffer.
* @param length Length of data to write. * @param length Length of data to write.
* @param imm Flag indicating whether the frame is immediate.
* @returns bool True, if data is written, otherwise false. * @returns bool True, if data is written, otherwise false.
*/ */
bool writeP25Frame(const uint8_t* data, uint32_t length); bool writeP25Frame(const uint8_t* data, uint32_t length, bool imm = false);
/** /**
* @brief Writes NXDN frame data to the NXDN ring buffer. * @brief Writes NXDN frame data to the NXDN ring buffer.
* @param[in] data Data to write to ring buffer. * @param[in] data Data to write to ring buffer.
* @param length Length of data to write. * @param length Length of data to write.
* @param imm Flag indicating whether the frame is immediate.
* @returns bool True, if data is written, otherwise false. * @returns bool True, if data is written, otherwise false.
*/ */
bool writeNXDNFrame(const uint8_t* data, uint32_t length); bool writeNXDNFrame(const uint8_t* data, uint32_t length, bool imm = false);
/** /**
* @brief Triggers the start of DMR transmit. * @brief Triggers the start of DMR transmit.
@ -656,9 +660,10 @@ namespace modem
* @brief Writes raw data to the air interface modem. * @brief Writes raw data to the air interface modem.
* @param data Data to write to modem. * @param data Data to write to modem.
* @param length Length of data to write. * @param length Length of data to write.
* @param imm Flag indicating whether the frame is immediate.
* @returns int Actual length of data written. * @returns int Actual length of data written.
*/ */
virtual int write(const uint8_t* data, uint32_t length); virtual int write(const uint8_t* data, uint32_t length, bool imm = false);
/** /**
* @brief Gets the flag for the V.24 connection state. * @brief Gets the flag for the V.24 connection state.

@ -47,7 +47,8 @@ ModemV24::ModemV24(port::IModemPort* port, bool duplex, uint32_t p25QueueSize, u
m_superFrameCnt(0U), m_superFrameCnt(0U),
m_audio(), m_audio(),
m_nid(nullptr), m_nid(nullptr),
m_txP25Queue(p25TxQueueSize, "TX P25 Queue"), m_txP25Queue(p25TxQueueSize, "V.24 TX P25 Queue"),
m_txImmP25Queue(p25TxQueueSize, "V.24 TX Immediate P25 Queue"),
m_txCall(), m_txCall(),
m_rxCall(), m_rxCall(),
m_txCallInProgress(false), m_txCallInProgress(false),
@ -58,7 +59,8 @@ ModemV24::ModemV24(port::IModemPort* port, bool duplex, uint32_t p25QueueSize, u
m_jitter(jitter), m_jitter(jitter),
m_lastP25Tx(0U), m_lastP25Tx(0U),
m_rs(), m_rs(),
m_useTIAFormat(false) m_useTIAFormat(false),
m_txP25QueueLock()
{ {
m_v24Connected = false; // defaulted to false for V.24 modems m_v24Connected = false; // defaulted to false for V.24 modems
@ -389,8 +391,13 @@ void ModemV24::clock(uint32_t ms)
reset(); reset();
} }
int len = 0;
// write anything waiting to the serial port // write anything waiting to the serial port
int len = writeSerial(); if (!m_txImmP25Queue.isEmpty())
len = writeSerial(&m_txImmP25Queue);
else
len = writeSerial(&m_txP25Queue);
if (m_debug && len > 0) { if (m_debug && len > 0) {
LogDebug(LOG_MODEM, "Wrote %u-byte message to the serial V24 device", len); LogDebug(LOG_MODEM, "Wrote %u-byte message to the serial V24 device", len);
} else if (len < 0) { } else if (len < 0) {
@ -430,7 +437,7 @@ bool ModemV24::hasP25Space(uint32_t length) const
/* Writes raw data to the air interface modem. */ /* Writes raw data to the air interface modem. */
int ModemV24::write(const uint8_t* data, uint32_t length) int ModemV24::write(const uint8_t* data, uint32_t length, bool imm)
{ {
assert(data != nullptr); assert(data != nullptr);
@ -446,12 +453,12 @@ int ModemV24::write(const uint8_t* data, uint32_t length)
::memcpy(buffer, data + 2U, length); ::memcpy(buffer, data + 2U, length);
if (m_useTIAFormat) if (m_useTIAFormat)
convertFromAirTIA(buffer, length); convertFromAirTIA(buffer, length, imm);
else else
convertFromAirV24(buffer, length); convertFromAirV24(buffer, length, imm);
return length; return length;
} else { } else {
return Modem::write(data, length); return Modem::write(data, length, imm);
} }
} }
@ -461,7 +468,7 @@ int ModemV24::write(const uint8_t* data, uint32_t length)
/* Helper to write data from the P25 Tx queue to the serial interface. */ /* Helper to write data from the P25 Tx queue to the serial interface. */
int ModemV24::writeSerial() int ModemV24::writeSerial(RingBuffer<uint8_t>* queue)
{ {
/* /*
* Serial TX ringbuffer format: * Serial TX ringbuffer format:
@ -471,32 +478,38 @@ int ModemV24::writeSerial()
*/ */
// check empty // check empty
if (m_txP25Queue.isEmpty()) if (queue->isEmpty())
return 0U; return 0U;
// get length // get length
uint8_t length[2U]; uint8_t length[2U];
::memset(length, 0x00U, 2U); ::memset(length, 0x00U, 2U);
m_txP25Queue.peek(length, 2U); queue->peek(length, 2U);
// convert length byets to int // convert length byets to int
uint16_t len = 0U; uint16_t len = 0U;
len = (length[0U] << 8) + length[1U]; len = (length[0U] << 8) + length[1U];
// this ensures we never get in a situation where we have length & type bytes stuck in the queue by themselves // this ensures we never get in a situation where we have length & type bytes stuck in the queue by themselves
if (m_txP25Queue.dataSize() == 2U && len > m_txP25Queue.dataSize()) { if (queue->dataSize() == 2U && len > queue->dataSize()) {
m_txP25Queue.get(length, 2U); // ensure we pop bytes off queue->get(length, 2U); // ensure we pop bytes off
return 0U; return 0U;
} }
// check available modem space
if (m_p25Space < len)
return 0U;
std::lock_guard<std::mutex> lock(m_txP25QueueLock);
// get current timestamp // get current timestamp
int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
// peek the timestamp to see if we should wait // peek the timestamp to see if we should wait
if (m_txP25Queue.dataSize() >= 11U) { if (queue->dataSize() >= 11U) {
uint8_t lengthTagTs[11U]; uint8_t lengthTagTs[11U];
::memset(lengthTagTs, 0x00U, 11U); ::memset(lengthTagTs, 0x00U, 11U);
m_txP25Queue.peek(lengthTagTs, 11U); queue->peek(lengthTagTs, 11U);
// get the timestamp // get the timestamp
int64_t ts; int64_t ts;
@ -510,14 +523,14 @@ int ModemV24::writeSerial()
} }
// check if we have enough data to get everything - len + 2U (length bytes) + 1U (tag) + 8U (timestamp) // check if we have enough data to get everything - len + 2U (length bytes) + 1U (tag) + 8U (timestamp)
if (m_txP25Queue.dataSize() >= len + 11U) { if (queue->dataSize() >= len + 11U) {
// Get the length, tag and timestamp // Get the length, tag and timestamp
uint8_t lengthTagTs[11U]; uint8_t lengthTagTs[11U];
m_txP25Queue.get(lengthTagTs, 11U); queue->get(lengthTagTs, 11U);
// Get the actual data // Get the actual data
DECLARE_UINT8_ARRAY(buffer, len); DECLARE_UINT8_ARRAY(buffer, len);
m_txP25Queue.get(buffer, len); queue->get(buffer, len);
// Sanity check on data tag // Sanity check on data tag
uint8_t tag = lengthTagTs[2U]; uint8_t tag = lengthTagTs[2U];
@ -2300,7 +2313,7 @@ void ModemV24::convertToAirTIA(const uint8_t *data, uint32_t length)
/* Helper to add a V.24 data frame to the P25 TX queue with the proper timestamp and formatting */ /* Helper to add a V.24 data frame to the P25 TX queue with the proper timestamp and formatting */
void ModemV24::queueP25Frame(uint8_t* data, uint16_t len, SERIAL_TX_TYPE msgType) bool ModemV24::queueP25Frame(uint8_t* data, uint16_t len, SERIAL_TX_TYPE msgType, bool imm)
{ {
assert(data != nullptr); assert(data != nullptr);
assert(len > 0U); assert(len > 0U);
@ -2347,6 +2360,17 @@ void ModemV24::queueP25Frame(uint8_t* data, uint16_t len, SERIAL_TX_TYPE msgType
len += 4U; len += 4U;
std::lock_guard<std::mutex> lock(m_txP25QueueLock);
// check available ringbuffer space
if (imm) {
if (m_txImmP25Queue.freeSpace() < (len + 11U))
return false;
} else {
if (m_txP25Queue.freeSpace() < (len + 11U))
return false;
}
// convert 16-bit length to 2 bytes // convert 16-bit length to 2 bytes
uint8_t length[2U]; uint8_t length[2U];
if (len > 255U) if (len > 255U)
@ -2355,17 +2379,26 @@ void ModemV24::queueP25Frame(uint8_t* data, uint16_t len, SERIAL_TX_TYPE msgType
length[0U] = 0x00U; length[0U] = 0x00U;
length[1U] = len & 0xFFU; length[1U] = len & 0xFFU;
m_txP25Queue.addData(length, 2U); if (imm)
m_txImmP25Queue.addData(length, 2U);
else
m_txP25Queue.addData(length, 2U);
// add the data tag // add the data tag
uint8_t tag = TAG_DATA; uint8_t tag = TAG_DATA;
m_txP25Queue.addData(&tag, 1U); if (imm)
m_txImmP25Queue.addData(&tag, 1U);
else
m_txP25Queue.addData(&tag, 1U);
// convert 64-bit timestamp to 8 bytes and add // convert 64-bit timestamp to 8 bytes and add
uint8_t tsBytes[8U]; uint8_t tsBytes[8U];
assert(sizeof msgTime == 8U); assert(sizeof msgTime == 8U);
::memcpy(tsBytes, &msgTime, 8U); ::memcpy(tsBytes, &msgTime, 8U);
m_txP25Queue.addData(tsBytes, 8U); if (imm)
m_txImmP25Queue.addData(tsBytes, 8U);
else
m_txP25Queue.addData(tsBytes, 8U);
// add the DVM start byte, length byte, CMD byte, and padding 0 // add the DVM start byte, length byte, CMD byte, and padding 0
uint8_t header[4U]; uint8_t header[4U];
@ -2373,13 +2406,21 @@ void ModemV24::queueP25Frame(uint8_t* data, uint16_t len, SERIAL_TX_TYPE msgType
header[1U] = len & 0xFFU; header[1U] = len & 0xFFU;
header[2U] = CMD_P25_DATA; header[2U] = CMD_P25_DATA;
header[3U] = 0x00U; header[3U] = 0x00U;
m_txP25Queue.addData(header, 4U); if (imm)
m_txImmP25Queue.addData(header, 4U);
else
m_txP25Queue.addData(header, 4U);
// add the data // add the data
m_txP25Queue.addData(data, len - 4U); if (imm)
m_txImmP25Queue.addData(data, len - 4U);
else
m_txP25Queue.addData(data, len - 4U);
// update the last message time // update the last message time
m_lastP25Tx = msgTime; m_lastP25Tx = msgTime;
return true;
} }
/* Send a start of stream sequence (HDU, etc) to the connected serial V.24 device */ /* Send a start of stream sequence (HDU, etc) to the connected serial V.24 device */
@ -2680,7 +2721,7 @@ void ModemV24::ackStartOfStreamTIA()
/* Internal helper to convert from TIA-102 air interface to V.24/DFSI. */ /* Internal helper to convert from TIA-102 air interface to V.24/DFSI. */
void ModemV24::convertFromAirV24(uint8_t* data, uint32_t length) void ModemV24::convertFromAirV24(uint8_t* data, uint32_t length, bool imm)
{ {
assert(data != nullptr); assert(data != nullptr);
assert(length > 0U); assert(length > 0U);
@ -3131,7 +3172,7 @@ void ModemV24::convertFromAirV24(uint8_t* data, uint32_t length)
if (m_trace) if (m_trace)
Utils::dump(1U, "ModemV24::convertFromAirV24(), MotTSBKFrame", tsbkBuf, DFSI_MOT_TSBK_LEN); Utils::dump(1U, "ModemV24::convertFromAirV24(), MotTSBKFrame", tsbkBuf, DFSI_MOT_TSBK_LEN);
queueP25Frame(tsbkBuf, DFSI_MOT_TSBK_LEN, STT_DATA_FAST); queueP25Frame(tsbkBuf, DFSI_MOT_TSBK_LEN, STT_DATA_FAST, imm);
} }
break; break;
@ -3322,7 +3363,7 @@ void ModemV24::convertFromAirV24(uint8_t* data, uint32_t length)
/* Internal helper to convert from TIA-102 air interface to TIA-102 DFSI. */ /* Internal helper to convert from TIA-102 air interface to TIA-102 DFSI. */
void ModemV24::convertFromAirTIA(uint8_t* data, uint32_t length) void ModemV24::convertFromAirTIA(uint8_t* data, uint32_t length, bool imm)
{ {
assert(data != nullptr); assert(data != nullptr);
assert(length > 0U); assert(length > 0U);

@ -578,9 +578,10 @@ namespace modem
* @brief Writes raw data to the air interface modem. * @brief Writes raw data to the air interface modem.
* @param data Data to write to modem. * @param data Data to write to modem.
* @param length Length of data to write. * @param length Length of data to write.
* @param imm Flag indicating whether the frame is immediate.
* @returns int Actual length of data written. * @returns int Actual length of data written.
*/ */
int write(const uint8_t* data, uint32_t length) override; int write(const uint8_t* data, uint32_t length, bool imm = false) override;
private: private:
bool m_rtrt; bool m_rtrt;
@ -592,6 +593,7 @@ namespace modem
p25::NID* m_nid; p25::NID* m_nid;
RingBuffer<uint8_t> m_txP25Queue; RingBuffer<uint8_t> m_txP25Queue;
RingBuffer<uint8_t> m_txImmP25Queue;
DFSICallData* m_txCall; DFSICallData* m_txCall;
DFSICallData* m_rxCall; DFSICallData* m_rxCall;
@ -609,11 +611,14 @@ namespace modem
bool m_useTIAFormat; bool m_useTIAFormat;
std::mutex m_txP25QueueLock;
/** /**
* @brief Helper to write data from the P25 Tx queue to the serial interface. * @brief Helper to write data from the P25 Tx queue to the serial interface.
* @param[in] queue Pointer to the ring buffer containing data to write.
* @return int Actual number of bytes written to the serial interface. * @return int Actual number of bytes written to the serial interface.
*/ */
int writeSerial(); int writeSerial(RingBuffer<uint8_t>* queue);
/** /**
* @brief Helper to store converted Rx frames. * @brief Helper to store converted Rx frames.
@ -651,8 +656,10 @@ namespace modem
* @param data Buffer containing V.24 data frame to send. * @param data Buffer containing V.24 data frame to send.
* @param len Length of buffer. * @param len Length of buffer.
* @param msgType Type of message to send (used for proper jitter clocking). * @param msgType Type of message to send (used for proper jitter clocking).
* @param imm Flag indicating whether the frame is immediate.
* @returns bool True, if data is queued, otherwise false.
*/ */
void queueP25Frame(uint8_t* data, uint16_t length, SERIAL_TX_TYPE msgType); bool queueP25Frame(uint8_t* data, uint16_t length, SERIAL_TX_TYPE msgType, bool imm = false);
/** /**
* @brief Send a start of stream sequence (HDU, etc) to the connected serial V24 device. * @brief Send a start of stream sequence (HDU, etc) to the connected serial V24 device.
@ -689,14 +696,16 @@ namespace modem
* @brief Internal helper to convert from TIA-102 air interface to V.24/DFSI. * @brief Internal helper to convert from TIA-102 air interface to V.24/DFSI.
* @param data Buffer containing data to convert. * @param data Buffer containing data to convert.
* @param length Length of buffer. * @param length Length of buffer.
* @param imm Flag indicating whether the frame is immediate.
*/ */
void convertFromAirV24(uint8_t* data, uint32_t length); void convertFromAirV24(uint8_t* data, uint32_t length, bool imm);
/** /**
* @brief Internal helper to convert from TIA-102 air interface to TIA-102 DFSI. * @brief Internal helper to convert from TIA-102 air interface to TIA-102 DFSI.
* @param data Buffer containing data to convert. * @param data Buffer containing data to convert.
* @param length Length of buffer. * @param length Length of buffer.
* @param imm Flag indicating whether the frame is immediate.
*/ */
void convertFromAirTIA(uint8_t* data, uint32_t length); void convertFromAirTIA(uint8_t* data, uint32_t length, bool imm);
}; };
} // namespace modem } // namespace modem

@ -550,7 +550,7 @@ bool Control::isQueueFull()
/* Get frame data from data ring buffer. */ /* Get frame data from data ring buffer. */
uint32_t Control::getFrame(uint8_t* data) uint32_t Control::getFrame(uint8_t* data, bool* imm)
{ {
assert(data != nullptr); assert(data != nullptr);
@ -563,10 +563,16 @@ uint32_t Control::getFrame(uint8_t* data)
// tx immediate queue takes priority // tx immediate queue takes priority
if (!m_txImmQueue.isEmpty()) { if (!m_txImmQueue.isEmpty()) {
if (imm != nullptr)
*imm = true;
m_txImmQueue.get(&len, 1U); m_txImmQueue.get(&len, 1U);
m_txImmQueue.get(data, len); m_txImmQueue.get(data, len);
} }
else { else {
if (imm != nullptr)
*imm = false;
m_txQueue.get(&len, 1U); m_txQueue.get(&len, 1U);
m_txQueue.get(data, len); m_txQueue.get(data, len);
} }

@ -160,9 +160,10 @@ namespace nxdn
/** /**
* @brief Get frame data from data ring buffer. * @brief Get frame data from data ring buffer.
* @param[out] data Buffer to store frame data. * @param[out] data Buffer to store frame data.
* @param[out] imm Flag indicating whether the frame is immediate.
* @returns uint32_t Length of frame data retrieved. * @returns uint32_t Length of frame data retrieved.
*/ */
uint32_t getFrame(uint8_t* data); uint32_t getFrame(uint8_t* data, bool* imm = nullptr);
/** @} */ /** @} */
/** @name Data Clocking */ /** @name Data Clocking */

@ -819,7 +819,7 @@ bool Control::isQueueFull()
/* Get frame data from data ring buffer. */ /* Get frame data from data ring buffer. */
uint32_t Control::getFrame(uint8_t* data) uint32_t Control::getFrame(uint8_t* data, bool *imm)
{ {
assert(data != nullptr); assert(data != nullptr);
@ -835,12 +835,18 @@ uint32_t Control::getFrame(uint8_t* data)
// tx immediate queue takes priority // tx immediate queue takes priority
if (!m_txImmQueue.isEmpty()) { if (!m_txImmQueue.isEmpty()) {
if (imm != nullptr)
*imm = true;
m_txImmQueue.get(length, 2U); m_txImmQueue.get(length, 2U);
len = (length[0U] << 8) + length[1U]; len = (length[0U] << 8) + length[1U];
m_txImmQueue.get(data, len); m_txImmQueue.get(data, len);
} }
else { else {
if (imm != nullptr)
*imm = false;
m_txQueue.get(length, 2U); m_txQueue.get(length, 2U);
len = (length[0U] << 8) + length[1U]; len = (length[0U] << 8) + length[1U];

@ -170,9 +170,10 @@ namespace p25
/** /**
* @brief Get frame data from data ring buffer. * @brief Get frame data from data ring buffer.
* @param[out] data Buffer to store frame data. * @param[out] data Buffer to store frame data.
* @param[out] imm Flag indicating whether the frame is immediate.
* @returns uint32_t Length of frame data retrieved. * @returns uint32_t Length of frame data retrieved.
*/ */
uint32_t getFrame(uint8_t* data); uint32_t getFrame(uint8_t* data, bool* imm = nullptr);
/** @} */ /** @} */
/** /**

Loading…
Cancel
Save

Powered by TurnKey Linux.