QRSS Rx Network receiver. A receiver to sample a segment of RF spectrum and send this data to a server for further processing and display. NXP mbed Design Challenge entry (Honorable Mention). Published in Circuit Cellar, Feb 2012
Dependencies: NetServices mbed DNSResolver
Diff: BufferSys.h
- Revision:
- 0:82ff15078322
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BufferSys.h Wed Jan 25 20:32:53 2012 +0000 @@ -0,0 +1,612 @@ +/*--------------------------------------------------------------------------- + + QRSS Receiver Application + + by Clayton ZL3TKA/VK1TKA + clayton@isnotcrazy.com + + Header File for Buffer System + Designed to buffer 32 bit I/Q samples + +---------------------------------------------------------------------------*/ +#ifndef _BUFFERSYS_H +#define _BUFFERSYS_H + +#include "mbed.h" +#include "global.h" + +// Definitions + +#ifndef BUFFERSYS_SIZE + #define BUFFERSYS_SIZE 512 +#endif + +// +// Structures +// + +//--------------------------------------------------------------------------- +// +// A Sample structure +// The single data sample point +// +typedef struct _data_sample +{ + int32_t iQData; + int32_t iIData; +} TDataSample; + +// Long samples - more bit sizes +// Not used by the buffers, but available for other parts in the system +typedef struct _long_data_sample +{ + int64_t iQData; + int64_t iIData; +} TLongDataSample; + +extern const TDataSample NullSample; + +// +// Classes +// + +// Forward references +class TBufferPool; + +//--------------------------------------------------------------------------- +// +// A Buffer Data Class +// The actual thing that holds the sample data +// +class TBufferData +{ + // create/destroy + public: + // creates the buffer + TBufferData() : + iLength(0), + pNext(NULL), + iRefCount(0), + pPool(NULL) + {} + // delete the buffer + ~TBufferData() + {} + + // API + public: + + // Check the reference count + // Any operation that changes a buffer's data (or provides a write pointer) MUST check + // iRefCount and throw exception if not = 1 + inline void CheckRefCount( void ) const + { + if ( iRefCount != 1 ) + error( "TBufferData::CheckRefCount RefCount not equal to 1\r\n" ); + } + + // Clear the buffer + void Clear( void ) + { + iLength = 0; + } + + // Append a sample + bool Append( const TDataSample *pSample ) + { + CheckRefCount(); + // Check for overflows + if ( iLength>=BUFFERSYS_SIZE ) + return false; // no room + // Append the data + asSamples[iLength] = *pSample; + iLength ++; + return true; + } + + // Remove samples form the end of the buffer + // Fails if there are not enough samples to remove + bool Remove( int iSamples ) + { + CheckRefCount(); + if ( iSamples<0 ) + error( "TBufferData::Remove Invalid remove number\r\n" ); + // Check for underflow + if ( iLength<iSamples ) + { // underflow - remove all anyway + iLength = 0; + return false; + } + // adjust the length + iLength -= iSamples; + return true; + } + + // data + private: + + // the buffer + TDataSample asSamples[BUFFERSYS_SIZE]; + + // data size count + int iLength; // current samples count + + // a pointer for queuing + TBufferData *pNext; + + // a reference counter for counting holders of this buffer + int iRefCount; + + // a timestamp of the sample capture + uint32_t uiTimestamp; + + // a pointer to this buffers pool (to return it too) + TBufferPool *pPool; // the pool that the buffer came from + +#ifdef BUFFER_DEBUG + // details of buffer ownership (for debugging only) + bool bQueued; // the buffer is in a queue + bool bPooled; // the buffer is in a pool (unused buffer) +#endif + + //Declare the buffer classes as friendly + //so it can access the protected members of buffers. + friend class TBufferHandle; + friend class TBufferQueue; + friend class TBufferPool; + + +}; + +//--------------------------------------------------------------------------- +// +// A Buffer Handle Class +// Something that holds a buffer +// Can also be the base class for something that processes a buffer +// +class TBufferHandle +{ + // create/destroy + public: + TBufferHandle() : + pMyBuffer( NULL ) + {} + + virtual ~TBufferHandle() + { // release any attached buffer + Release(); + } + + // buffer attached/release + public: + // test if the handle has a buffer attached + inline bool HasBuffer( void ) const + { + if ( pMyBuffer != NULL ) + return true; + return false; + } + + protected: + // attached a buffer to the handle + bool Attach( TBufferData * pBuffer ) + { + // release any old buffer + Release(); + + // Attach the buffer to the handler + if ( pBuffer != NULL ) + { + pMyBuffer = pBuffer; + // Increment the reference count of the buffer + pMyBuffer->iRefCount++; + return true; + } + return false; + } + // debug - check that a buffer is attached + inline void CheckForBuffer( void ) const + { + if ( pMyBuffer == NULL ) + error( "TBufferHandle::CheckForBuffer Handle does not have a buffer attached\r\n" ); + } + + public: + // transfer a buffer from another handle + bool TransferBuffer( TBufferHandle & Handle ) + { + // attach buffer from other handle + if ( !Attach(Handle.pMyBuffer) ) + return false; + // release buffer from the other handle + Handle.Release(); + return true; + } + + // release the buffer from the handle + void Release( void ); + + // Set the timestamp + void Timestamp( uint32_t uiTime ) + { + if ( HasBuffer() ) + pMyBuffer->uiTimestamp = uiTime; + } + + // Read the timestamp + uint32_t Timestamp() + { + if ( HasBuffer() ) + return pMyBuffer->uiTimestamp; + return 0; + } + + // buffer manipulation + public: + // append a sample + bool Append( const TDataSample &Sample ) + { + CheckForBuffer(); + return pMyBuffer->Append( &Sample ); + } + + // Remove characters form the end of the buffer + // Fails if there are not enough bytes to remove + bool Remove( int iBytes ) + { + CheckForBuffer(); + return pMyBuffer->Remove( iBytes ); + } + + // Clear the buffer + void Clear( void ) + { + CheckForBuffer(); + pMyBuffer->Clear(); + } + + // set buffer length (after data has been manually added) + void SetLength( int iLen ) + { + if ( HasBuffer() ) + { + if ( iLen<0 ) + iLen = 0; + if ( iLen>BUFFERSYS_SIZE ) + iLen = BUFFERSYS_SIZE; + pMyBuffer->iLength = iLen; + } + } + + // buffer examination + public: + // get buffer length + int Length( void ) const + { + if ( !HasBuffer() ) + return 0; + return pMyBuffer->iLength; + } + + // get buffer size + int Size( void ) const + { + if ( !HasBuffer() ) + return 0; + return BUFFERSYS_SIZE; + } + + int Room( void ) const + { + if ( !HasBuffer() ) + return 0; + return ( BUFFERSYS_SIZE - pMyBuffer->iLength ); + } + + // get a pointer to the buffer data + TDataSample * SamplePtr( int iIndex=0 ) + { + if ( !HasBuffer() ) + return NULL; // no buffer + if ( iIndex>pMyBuffer->iLength ) + return NULL; // index past end of buffer + return &(pMyBuffer->asSamples[iIndex]); + } + // get buffer data (note that there is no way to detect failure) + const TDataSample operator []( int iIndex ) const + { + if ( HasBuffer() && (iIndex<pMyBuffer->iLength) && (iIndex>=0) ) + return pMyBuffer->asSamples[iIndex]; + return NullSample; // otherwise return empty sample + } + + // data + protected: + // pointer to the buffer being references to + TBufferData *pMyBuffer; + + friend class TBufferQueue; + friend class TBufferPool; +}; + +//--------------------------------------------------------------------------- +// +// A Buffer Queue +// A queue of buffers +// +class TBufferQueue +{ + // create/destroy + public: + TBufferQueue() : + pFront(NULL), + pBack(NULL), + iCount(0) + {} + + virtual ~TBufferQueue() + { + // release all buffer + Flush(); + } + + // queue manipulation + public: + // peek at the front buffer on the queue, but still leave the buffer there + // (buffer must not be editted) + bool Peek( TBufferHandle &Handle ) const + { // attached the buffer to the handle + return Handle.Attach( pFront ); // Attach also inc ref count + } + + // remove the first buffer from the queue and return in the handle + bool Read( TBufferHandle &Handle ) + { + // release any old buffers + Handle.Release(); + // check for any buffers + if ( iCount<=0 ) + return false; //Nothing in queue + // get the front buffer + TBufferData * pRemovedBuffer = pFront; + if ( pRemovedBuffer==NULL ) + error( "TBufferQueue::Read queue pFront pointer!\r\n" ); + // adjust the queue ptrs + RemovePtrFromQueue(); +#ifdef BUFFER_DEBUG + // reset queued flag + pRemovedBuffer->bQueued = false; +#endif + // no RefCount adjustment needed - buffer is added to handle but release from the queue + // Manually put the buffer into the (empty) handle + Handle.pMyBuffer = pRemovedBuffer; + return true; + } + + // Write a buffer into the queue, removing it from the handle + bool Write( TBufferHandle &Handle ) + { + // check there is a buffer + if ( !Handle.HasBuffer() ) + return false; + // Buffer is manually moved (Reference counter is untouched) + // Add msg ptr to the queue (does not adjust the reference counter) + AddPtrToQueue( Handle.pMyBuffer ); + // Flag the buffer as queued +#ifdef BUFFER_DEBUG + Handle.pMyBuffer->bQueued = true; +#endif + // no RefCount adjustment needed - buffer is added to queue but release from the handle + // Manually remove the buffer from the handle + Handle.pMyBuffer = NULL; + return true; + } + + // Return number of queued buffers + int Count() const + { return iCount; } + + // Test if empty + bool Empty() const + { return (iCount==0); } + + // strip all buffers from the queue + bool Flush( void ) + { + // check for buffers to flush + if ( iCount==0 ) + return false; + // read and release buffers until no more to read + TBufferHandle MsgHandle; + while ( Read(MsgHandle) ) + { // release the buffers + MsgHandle.Release(); + } + return true; + } + + // internal methods + protected: + // Add the buffer to the end of the queue + // Does not do any checks etc or adjust buffer reference count + void AddPtrToQueue( TBufferData *pMsg ) + { + pMsg->pNext = NULL; + if ( iCount == 0 ) + { // Queue is currently empty + // Front = back = buffer + pFront = pMsg; + pBack = pMsg; + iCount = 1; + } + else + { // Add the buffer to the back of the queue + pBack->pNext = pMsg; + pBack = pMsg; + iCount++; + } + } + + // Remove a pointer from the front of the queue + // Does not do any checks etc or adjust buffer reference count - just removes pointer + void RemovePtrFromQueue( void ) + { + // adjust the queue + if ( iCount<=1 ) + { // Empty queue + pFront = NULL; + pBack = NULL; + iCount=0; + } + else + { + // Remove first item + pFront = pFront->pNext; + // Decrement the number of buffers in the queue + iCount--; + } + } + + // data + protected: + TBufferData *pFront; // front of the queue (out point) + TBufferData *pBack; // back of the queue (in point) + int iCount; // number of items in the queue + + friend class TBufferHandle; + + + + +}; + +//--------------------------------------------------------------------------- +// +// A Buffer Pool +// A pool of free buffers +// +class TBufferPool : protected TBufferQueue +{ + // create/destroy + public: + // create an pool and optionally add buffers to it off the stack + TBufferPool( int iNumMsgs=0 ) : + iBuffCount(0) + { + if (iNumMsgs>0) + CreateBuffers( iNumMsgs ); + } + // destroy a pool and all of its internal methods + virtual ~TBufferPool() + { + // delete all buffers + TBufferHandle MsgHandle; + while ( Read(MsgHandle) ) + { + // delete the TBufferData + delete MsgHandle.pMyBuffer; + // clear the buffer handle + MsgHandle.pMyBuffer = NULL; + } + } + + // pool setup + public: + // Add buffers to the pool + // Buffers are created off the heap + bool CreateBuffers( int iNumMsgs ) + { + TBufferData * pBuff; + // Loop and create msgs + while ( iNumMsgs>0 ) + { + //printf( "Creating buffer %d\r\n", iBuffCount ); + // Create the new buffer + pBuff = new TBufferData; + if ( pBuff==NULL ) + return false; + // add the buffer to the pool + pBuff->pPool = this; + ReturnToPool( pBuff ); + iBuffCount++; + iNumMsgs--; + } + return true; + } + + // add a new buffer to the pool - + // either as a buffer (with or without a data structure) + // or as a data structure with a buffer + void AddNewMsgToPool( TBufferData & Buffer ) + { + Buffer.pPool = this; + ReturnToPool( &Buffer ); + iBuffCount++; + } + + // add an array of buffers to the pool + void AddNewMsgsToPool( TBufferData *pBuffer, int iCount ) + { + while ( iCount>0 ) + { + AddNewMsgToPool( *pBuffer ); + pBuffer++; + iCount--; + } + } + + // place or return a buffer in the pool + void ReturnToPool( TBufferData * pBuffer ) + { + // Add to the queue (does not adjust the reference counter) + AddPtrToQueue( pBuffer ); + // zero reference (should already be the case) + pBuffer->iRefCount = 0; +#ifdef BUFFER_DEBUG + // Flag the buffer as pooled + pBuffer->bPooled = true; +#endif + } + + // Message Handling + public: + // buffer creation - takes a msg from the pool + bool Create( TBufferHandle &Handle ) + { + // read the buffer from the queue + if ( !Read(Handle) ) + return false; + // inc ref count (RefCount is 0 in pool, and Read does not adjust it) + Handle.pMyBuffer->iRefCount++; +#ifdef BUFFER_DEBUG + // reset pool flag + Handle.pMyBuffer->bPooled = false; +#endif + // Initialise the buffer + Handle.Clear(); + Handle.pMyBuffer->uiTimestamp = 0; + return true; + } + + // Pool Status + public: + // return number of buffers available + int Available() const + { return iCount; } + + // data + protected: + int iBuffCount; // number of buffers installed in the pool + + friend class TBufferData; + friend class TBufferHandle; + +}; + + +#endif + +//--------------------------------------------------------------------------- +// END +//--------------------------------------------------------------------------- +