Fix V24 startup queue race and preserve frames on write failure

pull/116/head
Tim Sawyer 3 weeks ago
parent c7a1c5a3b7
commit 148f884cfe

@ -482,6 +482,8 @@ int ModemV24::writeSerial(RingBuffer<uint8_t>* queue)
* | Length | Tag | int64_t timestamp in ms | data | * | Length | Tag | int64_t timestamp in ms | data |
*/ */
std::lock_guard<std::mutex> lock(m_txP25QueueLock);
// check empty // check empty
if (queue->isEmpty()) if (queue->isEmpty())
return 0U; return 0U;
@ -491,18 +493,16 @@ int ModemV24::writeSerial(RingBuffer<uint8_t>* queue)
::memset(length, 0x00U, 2U); ::memset(length, 0x00U, 2U);
queue->peek(length, 2U); queue->peek(length, 2U);
// convert length byets to int // convert length bytes 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 bytes stuck in the queue by themselves
if (queue->dataSize() == 2U && len > queue->dataSize()) { if (queue->dataSize() == 2U && len > queue->dataSize()) {
queue->get(length, 2U); // ensure we pop bytes off queue->get(length, 2U); // ensure we pop bytes off
return 0U; 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();
int64_t ts = 0L; int64_t ts = 0L;
@ -525,23 +525,32 @@ int ModemV24::writeSerial(RingBuffer<uint8_t>* queue)
// 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 (queue->dataSize() >= len + 11U) { if (queue->dataSize() >= len + 11U) {
// Get the length, tag and timestamp // Peek the full entry so we can keep it queued if a write fails.
uint8_t lengthTagTs[11U]; DECLARE_UINT8_ARRAY(entry, len + 11U);
queue->get(lengthTagTs, 11U); queue->peek(entry, len + 11U);
// Get the actual data // Get the length, tag, timestamp and payload pointers from peeked data.
DECLARE_UINT8_ARRAY(buffer, len); uint8_t* lengthTagTs = entry;
queue->get(buffer, len); uint8_t* buffer = entry + 11U;
// Sanity check on data tag // Sanity check on data tag
uint8_t tag = lengthTagTs[2U]; uint8_t tag = lengthTagTs[2U];
if (tag != TAG_DATA) { if (tag != TAG_DATA) {
LogError(LOG_MODEM, "Got unexpected data tag from TX P25 ringbuffer! %02X", tag); LogError(LOG_MODEM, "Got unexpected data tag from TX P25 ringbuffer! %02X", tag);
// Drop malformed entry so we can recover queue alignment.
DECLARE_UINT8_ARRAY(discard, len + 11U);
queue->get(discard, len + 11U);
return 0U; return 0U;
} }
// we already checked the timestamp above, so we just get the data and write it // we already checked the timestamp above, so we just write it
int ret = m_port->write(buffer, len); int ret = m_port->write(buffer, len);
if (ret > 0) {
// Only remove an entry once it was written successfully.
DECLARE_UINT8_ARRAY(discard, len + 11U);
queue->get(discard, len + 11U);
}
if (ret > 0 && m_debug && m_txStartupTraceActive && m_txStartupTraceWritesLeft > 0U) { if (ret > 0 && m_debug && m_txStartupTraceActive && m_txStartupTraceWritesLeft > 0U) {
uint8_t frameType = (len > 4U) ? buffer[4U] : 0xFFU; uint8_t frameType = (len > 4U) ? buffer[4U] : 0xFFU;
const char* queueName = (queue == &m_txImmP25Queue) ? "imm" : "norm"; const char* queueName = (queue == &m_txImmP25Queue) ? "imm" : "norm";
@ -559,6 +568,15 @@ int ModemV24::writeSerial(RingBuffer<uint8_t>* queue)
if (m_txStartupTraceWritesLeft == 0U) { if (m_txStartupTraceWritesLeft == 0U) {
m_txStartupTraceActive = false; m_txStartupTraceActive = false;
} }
} else if (ret <= 0 && m_debug && m_txStartupTraceActive) {
uint8_t frameType = (len > 4U) ? buffer[4U] : 0xFFU;
const char* queueName = (queue == &m_txImmP25Queue) ? "imm" : "norm";
int64_t nowMs = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()).count();
int64_t dtStart = (int64_t)(nowMs - (int64_t)m_txStartupTraceT0);
LogDebugEx(LOG_MODEM, "ModemV24::writeSerial()",
"TX startup write blocked/fail: q=%s, frameType=$%02X, dtStart=%lld ms, ret=%d, txQ=%u, immQ=%u, p25Space=%u",
queueName, frameType, dtStart, ret, m_txP25Queue.dataSize(), m_txImmP25Queue.dataSize(), m_p25Space);
} }
return ret; return ret;

Loading…
Cancel
Save

Powered by TurnKey Linux.