Download Pelican User Guide
Transcript
3.2 Importing Data I: Concepts, Data Emulators and Chunkers
11
}
// Creates a suitable device ready for reading.
QIODevice* SignalChunker::newDevice()
{
// Return an opened QUdpSocket.
QUdpSocket* socket = new QUdpSocket;
socket->bind(QHostAddress(host()), port());
// Wait for the socket to bind.
while (socket->state() != QUdpSocket::BoundState) {}
return socket;
}
// Called whenever there is data available on the device.
void SignalChunker::next(QIODevice* device)
{
// Get a pointer to the UDP socket.
QUdpSocket* udpSocket = static_cast<QUdpSocket*>(device);
_bytesRead = 0;
// Get writable buffer space for the chunk.
WritableData writableData = getDataStorage(_chunkSize);
if (writableData.isValid()) {
// Get pointer to start of writable memory.
char* ptr = (char*) (writableData.ptr());
// Read datagrams for chunk from the UDP socket.
while (isActive() && _bytesRead < _chunkSize) {
// Read the datagram, but avoid using pendingDatagramSize().
if (!udpSocket->hasPendingDatagrams()) {
// MUST WAIT for the next datagram.
udpSocket->waitForReadyRead(100);
continue;
}
qint64 maxlen = _chunkSize - _bytesRead;
qint64 length = udpSocket->readDatagram(ptr + _bytesRead, maxlen);
if (length > 0)
_bytesRead += length;
}
}
// Must discard the datagram if there is no available space.
else {
udpSocket->readDatagram(0, 0);
}
}
Note that a reference to the XML configuration node for the chunker will be automatically supplied to the constructor
from the application’s configuration file: we then simply need to extract the relevant configuration settings using
methods on the supplied ConfigNode object. The ConfigNode::getOption method returns a QString containing the
text in the required tag name and attribute function arguments. To illustrate what is needed here, the chunker
expects an XML snippet like this:
<SignalChunker>
<data type="SignalData" chunkSize="33792" />
<connection host="127.0.0.1" port="2001" />
</SignalChunker>
The data type, host name and port number are stored by the AbstractChunker base class, and so do not need
to be read again. The contents of the string containing "chunkSize" are converted to an integer value using the
QString::toInt() method. This initialisation step only happens once, at program launch, so there is no cost penalty
involved here. The attributes are stored in private class variables for later use.
Our SignalChunker::next() method must first call the inherited method AbstractChunker::getDataStorage(). This
calls routines in the DataManager and returns a pointer to a block of memory of the required size, wrapped inside
a WritableData container. When the WritableData object goes out of scope at the end of the method, the chunk
of data it references is automatically placed on a queue so that it can be processed by an available pipeline. The
SignalChunker::next() method must therefore accumulate the required number of UDP packets into a chunk before
exiting.
After obtaining the block of writable data, we must check that the memory it holds is actually available for writing
using WritableData::isValid(): if not (for example, because the buffer has run out of space), the UDP datagram must
be discarded. Provided that the memory is valid, we obtain a pointer to it using WritableData::ptr(), and read the
data from the socket using the methods on QUdpSocket or QIODevice: A pointer to the socket is passed to the
Generated on Tue Jan 22 2013 11:07:31 for Pelican User Guide by Doxygen