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 9 hours ago
parent c044e42d90
commit 87ad34f539

@ -721,7 +721,7 @@ bool Host::createModem()
}
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);
((ModemV24*)m_modem)->setCallTimeout(dfsiCallTimeout);
((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 the state is idle; set to DMR, start mode timer and start DMR idle frames
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 the state is idle; set to DMR, start mode timer and start DMR idle frames
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 the state is idle; set to NXDN and start mode timer
if (host->m_state == STATE_IDLE) {

@ -256,7 +256,8 @@ void* Host::threadP25Writer(void* arg)
if (nextLen > 0U) {
bool ret = host->m_modem->hasP25Space(nextLen);
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 the state is idle; set to P25 and start mode timer
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. */
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);
switch (slotNo) {
case 1U:
return m_slot1->getFrame(data);
return m_slot1->getFrame(data, imm);
case 2U:
return m_slot2->getFrame(data);
return m_slot2->getFrame(data, imm);
default:
LogError(LOG_DMR, "DMR, invalid slot, slotNo = %u", slotNo);
return 0U;

@ -159,9 +159,10 @@ namespace dmr
* @brief Get frame data from data ring buffer.
* @param slotNo DMR slot number.
* @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.
*/
uint32_t getFrame(uint32_t slotNo, uint8_t* data);
uint32_t getFrame(uint32_t slotNo, uint8_t* data, bool *imm = nullptr);
/** @} */
/** @name Data Clocking */

@ -361,7 +361,7 @@ bool Slot::isQueueFull()
/* 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);
@ -374,10 +374,16 @@ uint32_t Slot::getFrame(uint8_t* data)
// tx immediate queue takes priority
if (!m_txImmQueue.isEmpty()) {
if (imm != nullptr)
*imm = true;
m_txImmQueue.get(&len, 1U);
m_txImmQueue.get(data, len);
}
else {
if (imm != nullptr)
*imm = false;
m_txQueue.get(&len, 1U);
m_txQueue.get(data, len);
}

@ -146,9 +146,10 @@ namespace dmr
/**
* @brief Get frame data from data ring buffer.
* @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.
*/
uint32_t getFrame(uint8_t* data);
uint32_t getFrame(uint8_t* data, bool* imm);
/**
* @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. */
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(length > 0U);
@ -1404,7 +1404,7 @@ bool Modem::writeDMRFrame1(const uint8_t* data, uint32_t length)
if (m_trace)
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)) {
LogError(LOG_MODEM, "Error writing DMR slot 1 data");
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. */
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(length > 0U);
@ -1458,7 +1458,7 @@ bool Modem::writeDMRFrame2(const uint8_t* data, uint32_t length)
if (m_trace)
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)) {
LogError(LOG_MODEM, "Error writing DMR slot 2 data");
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. */
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(length > 0U);
@ -1523,7 +1523,7 @@ bool Modem::writeP25Frame(const uint8_t* data, uint32_t length)
if (m_trace)
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)) {
LogError(LOG_MODEM, "Error writing P25 data");
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. */
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(length > 0U);
@ -1577,7 +1577,7 @@ bool Modem::writeNXDNFrame(const uint8_t* data, uint32_t length)
if (m_trace)
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)) {
LogError(LOG_MODEM, "Error writing NXDN data");
return false;
@ -1704,7 +1704,7 @@ bool Modem::setDMRIgnoreCACH_AT(uint8_t slotNo)
/* 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);
}

@ -602,30 +602,34 @@ namespace modem
* @brief Writes DMR Slot 1 frame data to the DMR Slot 1 ring buffer.
* @param[in] data Data to write to ring buffer.
* @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.
*/
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.
* @param[in] data Data to write to ring buffer.
* @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.
*/
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.
* @param[in] data Data to write to ring buffer.
* @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.
*/
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.
* @param[in] data Data to write to ring buffer.
* @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.
*/
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.
@ -656,9 +660,10 @@ namespace modem
* @brief Writes raw data to the air interface modem.
* @param data Data to write to modem.
* @param length Length of data to write.
* @param imm Flag indicating whether the frame is immediate.
* @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.

@ -47,7 +47,8 @@ ModemV24::ModemV24(port::IModemPort* port, bool duplex, uint32_t p25QueueSize, u
m_superFrameCnt(0U),
m_audio(),
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_rxCall(),
m_txCallInProgress(false),
@ -58,7 +59,8 @@ ModemV24::ModemV24(port::IModemPort* port, bool duplex, uint32_t p25QueueSize, u
m_jitter(jitter),
m_lastP25Tx(0U),
m_rs(),
m_useTIAFormat(false)
m_useTIAFormat(false),
m_txP25QueueLock()
{
m_v24Connected = false; // defaulted to false for V.24 modems
@ -389,8 +391,13 @@ void ModemV24::clock(uint32_t ms)
reset();
}
int len = 0;
// 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) {
LogDebug(LOG_MODEM, "Wrote %u-byte message to the serial V24 device", len);
} else if (len < 0) {
@ -430,7 +437,7 @@ bool ModemV24::hasP25Space(uint32_t length) const
/* 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);
@ -446,12 +453,12 @@ int ModemV24::write(const uint8_t* data, uint32_t length)
::memcpy(buffer, data + 2U, length);
if (m_useTIAFormat)
convertFromAirTIA(buffer, length);
convertFromAirTIA(buffer, length, imm);
else
convertFromAirV24(buffer, length);
convertFromAirV24(buffer, length, imm);
return length;
} 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. */
int ModemV24::writeSerial()
int ModemV24::writeSerial(RingBuffer<uint8_t>* queue)
{
/*
* Serial TX ringbuffer format:
@ -471,32 +478,38 @@ int ModemV24::writeSerial()
*/
// check empty
if (m_txP25Queue.isEmpty())
if (queue->isEmpty())
return 0U;
// get length
uint8_t length[2U];
::memset(length, 0x00U, 2U);
m_txP25Queue.peek(length, 2U);
queue->peek(length, 2U);
// convert length byets to int
uint16_t len = 0U;
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
if (m_txP25Queue.dataSize() == 2U && len > m_txP25Queue.dataSize()) {
m_txP25Queue.get(length, 2U); // ensure we pop bytes off
if (queue->dataSize() == 2U && len > queue->dataSize()) {
queue->get(length, 2U); // ensure we pop bytes off
return 0U;
}
// check available modem space
if (m_p25Space < len)
return 0U;
std::lock_guard<std::mutex> lock(m_txP25QueueLock);
// get current timestamp
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
if (m_txP25Queue.dataSize() >= 11U) {
if (queue->dataSize() >= 11U) {
uint8_t lengthTagTs[11U];
::memset(lengthTagTs, 0x00U, 11U);
m_txP25Queue.peek(lengthTagTs, 11U);
queue->peek(lengthTagTs, 11U);
// get the timestamp
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)
if (m_txP25Queue.dataSize() >= len + 11U) {
if (queue->dataSize() >= len + 11U) {
// Get the length, tag and timestamp
uint8_t lengthTagTs[11U];
m_txP25Queue.get(lengthTagTs, 11U);
queue->get(lengthTagTs, 11U);
// Get the actual data
DECLARE_UINT8_ARRAY(buffer, len);
m_txP25Queue.get(buffer, len);
queue->get(buffer, len);
// Sanity check on data tag
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 */
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(len > 0U);
@ -2347,6 +2360,17 @@ void ModemV24::queueP25Frame(uint8_t* data, uint16_t len, SERIAL_TX_TYPE msgType
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
uint8_t length[2U];
if (len > 255U)
@ -2355,16 +2379,25 @@ void ModemV24::queueP25Frame(uint8_t* data, uint16_t len, SERIAL_TX_TYPE msgType
length[0U] = 0x00U;
length[1U] = len & 0xFFU;
if (imm)
m_txImmP25Queue.addData(length, 2U);
else
m_txP25Queue.addData(length, 2U);
// add the data tag
uint8_t tag = TAG_DATA;
if (imm)
m_txImmP25Queue.addData(&tag, 1U);
else
m_txP25Queue.addData(&tag, 1U);
// convert 64-bit timestamp to 8 bytes and add
uint8_t tsBytes[8U];
assert(sizeof msgTime == 8U);
::memcpy(tsBytes, &msgTime, 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
@ -2373,13 +2406,21 @@ void ModemV24::queueP25Frame(uint8_t* data, uint16_t len, SERIAL_TX_TYPE msgType
header[1U] = len & 0xFFU;
header[2U] = CMD_P25_DATA;
header[3U] = 0x00U;
if (imm)
m_txImmP25Queue.addData(header, 4U);
else
m_txP25Queue.addData(header, 4U);
// add the data
if (imm)
m_txImmP25Queue.addData(data, len - 4U);
else
m_txP25Queue.addData(data, len - 4U);
// update the last message time
m_lastP25Tx = msgTime;
return true;
}
/* 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. */
void ModemV24::convertFromAirV24(uint8_t* data, uint32_t length)
void ModemV24::convertFromAirV24(uint8_t* data, uint32_t length, bool imm)
{
assert(data != nullptr);
assert(length > 0U);
@ -3131,7 +3172,7 @@ void ModemV24::convertFromAirV24(uint8_t* data, uint32_t length)
if (m_trace)
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;
@ -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. */
void ModemV24::convertFromAirTIA(uint8_t* data, uint32_t length)
void ModemV24::convertFromAirTIA(uint8_t* data, uint32_t length, bool imm)
{
assert(data != nullptr);
assert(length > 0U);

@ -578,9 +578,10 @@ namespace modem
* @brief Writes raw data to the air interface modem.
* @param data Data to write to modem.
* @param length Length of data to write.
* @param imm Flag indicating whether the frame is immediate.
* @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:
bool m_rtrt;
@ -592,6 +593,7 @@ namespace modem
p25::NID* m_nid;
RingBuffer<uint8_t> m_txP25Queue;
RingBuffer<uint8_t> m_txImmP25Queue;
DFSICallData* m_txCall;
DFSICallData* m_rxCall;
@ -609,11 +611,14 @@ namespace modem
bool m_useTIAFormat;
std::mutex m_txP25QueueLock;
/**
* @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.
*/
int writeSerial();
int writeSerial(RingBuffer<uint8_t>* queue);
/**
* @brief Helper to store converted Rx frames.
@ -651,8 +656,10 @@ namespace modem
* @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).
* @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.
@ -689,14 +696,16 @@ namespace modem
* @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.
* @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.
* @param data Buffer containing data to convert.
* @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

@ -550,7 +550,7 @@ bool Control::isQueueFull()
/* 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);
@ -563,10 +563,16 @@ uint32_t Control::getFrame(uint8_t* data)
// tx immediate queue takes priority
if (!m_txImmQueue.isEmpty()) {
if (imm != nullptr)
*imm = true;
m_txImmQueue.get(&len, 1U);
m_txImmQueue.get(data, len);
}
else {
if (imm != nullptr)
*imm = false;
m_txQueue.get(&len, 1U);
m_txQueue.get(data, len);
}

@ -160,9 +160,10 @@ namespace nxdn
/**
* @brief Get frame data from data ring buffer.
* @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.
*/
uint32_t getFrame(uint8_t* data);
uint32_t getFrame(uint8_t* data, bool* imm = nullptr);
/** @} */
/** @name Data Clocking */

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

@ -170,9 +170,10 @@ namespace p25
/**
* @brief Get frame data from data ring buffer.
* @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.
*/
uint32_t getFrame(uint8_t* data);
uint32_t getFrame(uint8_t* data, bool* imm = nullptr);
/** @} */
/**

Loading…
Cancel
Save

Powered by TurnKey Linux.