timeval tvNow, tvTimeout, tvNextEpoch;
tvNow = TimeUtils::getTime();
tvTimeout = tvNow;
tvNextEpoch = timevalNextEpoch(tvNow, m_epochMicroseconds);
quint32 processingDelayAdjustment = 0;
fd_set readS, exS;
int maxFd = 0;
#define SELECT_TIMING_TEST
#ifdef SELECT_TIMING_TEST
timeval tvStart, tvElapsed;
tvStart = tvNow;
tvElapsed = tvNow;
#endif
// Task loop
while (!m_stopped)
{
// Setup for ::select() statement
FD_ZERO(&readS);
FD_ZERO(&exS);
maxFd = 0;
maxFd = qMax(maxFd, udpSocketDescriptor);
// Add UDP socket to read file descriptor set
FD_SET(udpSocketDescriptor, &readS);
FD_SET(udpSocketDescriptor, &exS);
// Iterate through list of active sockets TCP-IP sockets
for (QMap<int, SockInfo *>::iterator it = m_currentSockets.begin(); it != m_currentSockets.end(); ++it)
{
int socket = it.key();
// Add TCP socket to read and exception file descriptor sets
FD_SET(socket, &readS);
FD_SET(socket, &exS);
maxFd = qMax(maxFd, socket);
}
// Update select statement timeout value to the interval to the start of the next epoch
timeoutUpdate(tvTimeout, tvNextEpoch, processingDelayAdjustment);
// Count of available file descriptors
int count = 0;
// Invoke select if the timeout to the next epoch is non-zero
if (tvTimeout.tv_usec != 0 || tvTimeout.tv_sec != 0)
{
#ifdef SELECT_TIMING_TEST
#define SELECT_TIMING_TEST_LOGLEVEL logDEBUG4
if (FILELog::ReportingLevel() >= SELECT_TIMING_TEST_LOGLEVEL)
{
// Get start time prior to select
TimeUtils::getTime(&tvStart);
msg
= QString("Select In: now (%1/%2), timeout (%3/%4), tvNextEpoch (%5/%6)").
arg(tvStart.
tv_sec).
arg(tvStart.
tv_usec).
arg(tvTimeout.
tv_sec).
arg(tvTimeout.
tv_usec).
arg(tvNextEpoch.
tv_sec).
arg(tvNextEpoch.
tv_usec);
FILE_LOG(SELECT_TIMING_TEST_LOGLEVEL) << qPrintable(msg);
}
#endif
// Wait for a number of file descriptors to change status or a timeout
count = ::select(maxFd + 1, &readS, NULL, &exS, &tvTimeout);
#ifdef SELECT_TIMING_TEST
if (FILELog::ReportingLevel() >= SELECT_TIMING_TEST_LOGLEVEL)
{
// Get system time after select call
tvNow = TimeUtils::getTime();
// Display elapsed time and other content
tvElapsed = tvNow - tvStart;
msg
= QString("Select Out: now (%1/%2), timeout (%3/%4), tvNextEpoch (%5/%6), elapsed (%7/%8), count %9").
arg(tvNow.tv_sec).arg(tvNow.tv_usec).arg(tvTimeout.tv_sec).arg(tvTimeout.tv_usec).
arg(tvNextEpoch.tv_sec).arg(tvNextEpoch.tv_usec).arg(tvElapsed.tv_sec).arg(tvElapsed.tv_usec).arg(count);
FILE_LOG(SELECT_TIMING_TEST_LOGLEVEL) << qPrintable(msg);
}
#endif
}
// Get system time after select call
tvNow = TimeUtils::getTime();
// On epoch boundary, perform epoch activities
if (tvNextEpoch <= tvNow)
{
// Update the time of the next epoch (calculate the time of day to the start of the next epoch boundary)
tvNextEpoch = timevalNextEpoch(tvNow, m_epochMicroseconds);
// Should be aligned to even multiple of epoch on timeout. Calculate how far off it was to make runtime adjustment for the next pass (routine timeoutUpdate())
processingDelayAdjustment = tvNow.tv_usec % m_epochMicroseconds;
if (FILELog::ReportingLevel() >= logDEBUG4)
{
int epochNumber = timevalToEpoch(tvNow.tv_usec, m_epochMicroseconds);
msg
= QString("TDMA: Epoch %1 at (%2/%3), timeout (%4/%5), delay adjust (%6)").
arg(epochNumber).arg(tvNow.tv_sec).arg(tvNow.tv_usec).arg(tvTimeout.tv_sec).arg(tvTimeout.tv_usec).arg(processingDelayAdjustment);
FILE_LOG(logDEBUG4) << qPrintable(msg);
}
onEpoch();
} // end Epoch activities
// Exit thread when stopped
if (m_stopped)
{
break;
}
// Packets found, process them
if (count > 0)
{
// RadioG-LM TA radio queue status messages
if (FD_ISSET(udpSocketDescriptor, &readS))
{
if (FILELog::ReportingLevel() >= logDEBUG4)
{
msg
= QString("TDMA: select() exit with count %1: UDP socket read file descriptor %2 set at (%3/%4)").
arg(count).arg(udpSocketDescriptor).arg(tvNow.tv_sec).arg(tvNow.tv_usec);
FILE_LOG(logDEBUG4) << qPrintable(msg);
}
// Assemble a full UDP datagram
do
{
datagram.resize(m_udpSocket->pendingDatagramSize());
m_udpSocket->readDatagram(datagram.data(), datagram.size(), &recvFrom);
} while (m_udpSocket->hasPendingDatagrams());
// Process contents of UDP datagram
processLinkManagerMessage(datagram, recvFrom);
}
// UDP socket exception
if (FD_ISSET(udpSocketDescriptor, &exS))
{
FILE_LOG(logERROR) << "TDMA: select() exception detected for UDP socket: " << udpSocketDescriptor;
}
// Check all TCP-IP LM-QM connections in the collection
for (QMap<int, SockInfo *>::iterator it = m_currentSockets.begin(); it != m_currentSockets.end(); ++it)
{
int socket = it.key();
// Socket read
if (FD_ISSET(socket, &readS))
{
if (FILELog::ReportingLevel() >= logDEBUG4)
{
msg
= QString("TDMA: select() exit with count %1: TCP-IP socket read file descriptor %2 set at (%3/%4)").
arg(count).arg(socket).arg(tvNow.tv_sec).arg(tvNow.tv_usec);
FILE_LOG(logDEBUG4) << qPrintable(msg);
}
// QM TCP-IP receive handler
SockInfo *sockInfo = it.value();
if (sockInfo)
{
processSocketMessage(sockInfo);
}
}
}
} // end count > 1
} // end while
timeval tvNow, tvTimeout, tvNextEpoch;
tvNow = TimeUtils::getTime();
tvTimeout = tvNow;
tvNextEpoch = timevalNextEpoch(tvNow, m_epochMicroseconds);
quint32 processingDelayAdjustment = 0;
fd_set readS, exS;
int maxFd = 0;
#define SELECT_TIMING_TEST
#ifdef SELECT_TIMING_TEST
timeval tvStart, tvElapsed;
tvStart = tvNow;
tvElapsed = tvNow;
#endif
// Task loop
while (!m_stopped)
{
// Setup for ::select() statement
FD_ZERO(&readS);
FD_ZERO(&exS);
maxFd = 0;
maxFd = qMax(maxFd, udpSocketDescriptor);
// Add UDP socket to read file descriptor set
FD_SET(udpSocketDescriptor, &readS);
FD_SET(udpSocketDescriptor, &exS);
// Iterate through list of active sockets TCP-IP sockets
for (QMap<int, SockInfo *>::iterator it = m_currentSockets.begin(); it != m_currentSockets.end(); ++it)
{
int socket = it.key();
// Add TCP socket to read and exception file descriptor sets
FD_SET(socket, &readS);
FD_SET(socket, &exS);
maxFd = qMax(maxFd, socket);
}
// Update select statement timeout value to the interval to the start of the next epoch
timeoutUpdate(tvTimeout, tvNextEpoch, processingDelayAdjustment);
// Count of available file descriptors
int count = 0;
// Invoke select if the timeout to the next epoch is non-zero
if (tvTimeout.tv_usec != 0 || tvTimeout.tv_sec != 0)
{
#ifdef SELECT_TIMING_TEST
#define SELECT_TIMING_TEST_LOGLEVEL logDEBUG4
if (FILELog::ReportingLevel() >= SELECT_TIMING_TEST_LOGLEVEL)
{
// Get start time prior to select
TimeUtils::getTime(&tvStart);
msg = QString("Select In: now (%1/%2), timeout (%3/%4), tvNextEpoch (%5/%6)").arg(tvStart.tv_sec).arg(tvStart.tv_usec).arg(tvTimeout.tv_sec).arg(tvTimeout.tv_usec).arg(tvNextEpoch.tv_sec).arg(tvNextEpoch.tv_usec);
FILE_LOG(SELECT_TIMING_TEST_LOGLEVEL) << qPrintable(msg);
}
#endif
// Wait for a number of file descriptors to change status or a timeout
count = ::select(maxFd + 1, &readS, NULL, &exS, &tvTimeout);
#ifdef SELECT_TIMING_TEST
if (FILELog::ReportingLevel() >= SELECT_TIMING_TEST_LOGLEVEL)
{
// Get system time after select call
tvNow = TimeUtils::getTime();
// Display elapsed time and other content
tvElapsed = tvNow - tvStart;
msg = QString("Select Out: now (%1/%2), timeout (%3/%4), tvNextEpoch (%5/%6), elapsed (%7/%8), count %9").
arg(tvNow.tv_sec).arg(tvNow.tv_usec).arg(tvTimeout.tv_sec).arg(tvTimeout.tv_usec).
arg(tvNextEpoch.tv_sec).arg(tvNextEpoch.tv_usec).arg(tvElapsed.tv_sec).arg(tvElapsed.tv_usec).arg(count);
FILE_LOG(SELECT_TIMING_TEST_LOGLEVEL) << qPrintable(msg);
}
#endif
}
// Get system time after select call
tvNow = TimeUtils::getTime();
// On epoch boundary, perform epoch activities
if (tvNextEpoch <= tvNow)
{
// Update the time of the next epoch (calculate the time of day to the start of the next epoch boundary)
tvNextEpoch = timevalNextEpoch(tvNow, m_epochMicroseconds);
// Should be aligned to even multiple of epoch on timeout. Calculate how far off it was to make runtime adjustment for the next pass (routine timeoutUpdate())
processingDelayAdjustment = tvNow.tv_usec % m_epochMicroseconds;
if (FILELog::ReportingLevel() >= logDEBUG4)
{
int epochNumber = timevalToEpoch(tvNow.tv_usec, m_epochMicroseconds);
msg = QString("TDMA: Epoch %1 at (%2/%3), timeout (%4/%5), delay adjust (%6)").
arg(epochNumber).arg(tvNow.tv_sec).arg(tvNow.tv_usec).arg(tvTimeout.tv_sec).arg(tvTimeout.tv_usec).arg(processingDelayAdjustment);
FILE_LOG(logDEBUG4) << qPrintable(msg);
}
onEpoch();
} // end Epoch activities
// Exit thread when stopped
if (m_stopped)
{
break;
}
// Packets found, process them
if (count > 0)
{
// RadioG-LM TA radio queue status messages
if (FD_ISSET(udpSocketDescriptor, &readS))
{
if (FILELog::ReportingLevel() >= logDEBUG4)
{
msg = QString("TDMA: select() exit with count %1: UDP socket read file descriptor %2 set at (%3/%4)").
arg(count).arg(udpSocketDescriptor).arg(tvNow.tv_sec).arg(tvNow.tv_usec);
FILE_LOG(logDEBUG4) << qPrintable(msg);
}
static QHostAddress recvFrom;
static QByteArray datagram;
// Assemble a full UDP datagram
do
{
datagram.resize(m_udpSocket->pendingDatagramSize());
m_udpSocket->readDatagram(datagram.data(), datagram.size(), &recvFrom);
} while (m_udpSocket->hasPendingDatagrams());
// Process contents of UDP datagram
processLinkManagerMessage(datagram, recvFrom);
}
// UDP socket exception
if (FD_ISSET(udpSocketDescriptor, &exS))
{
FILE_LOG(logERROR) << "TDMA: select() exception detected for UDP socket: " << udpSocketDescriptor;
}
// Check all TCP-IP LM-QM connections in the collection
for (QMap<int, SockInfo *>::iterator it = m_currentSockets.begin(); it != m_currentSockets.end(); ++it)
{
int socket = it.key();
// Socket read
if (FD_ISSET(socket, &readS))
{
if (FILELog::ReportingLevel() >= logDEBUG4)
{
msg = QString("TDMA: select() exit with count %1: TCP-IP socket read file descriptor %2 set at (%3/%4)").
arg(count).arg(socket).arg(tvNow.tv_sec).arg(tvNow.tv_usec);
FILE_LOG(logDEBUG4) << qPrintable(msg);
}
// QM TCP-IP receive handler
SockInfo *sockInfo = it.value();
if (sockInfo)
{
processSocketMessage(sockInfo);
}
}
}
} // end count > 1
} // end while
To copy to clipboard, switch view to plain text mode
Bookmarks