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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers BufferSys.h Source File

BufferSys.h

00001 /*---------------------------------------------------------------------------
00002 
00003     QRSS Receiver Application
00004         
00005     by Clayton ZL3TKA/VK1TKA
00006     clayton@isnotcrazy.com
00007 
00008     Header File for Buffer System
00009     Designed to buffer 32 bit I/Q samples
00010 
00011 ---------------------------------------------------------------------------*/
00012 #ifndef _BUFFERSYS_H
00013 #define _BUFFERSYS_H
00014 
00015 #include "mbed.h"
00016 #include "global.h"
00017 
00018 // Definitions
00019 
00020 #ifndef BUFFERSYS_SIZE
00021   #define BUFFERSYS_SIZE    512
00022 #endif
00023 
00024 //
00025 // Structures
00026 //
00027 
00028 //---------------------------------------------------------------------------
00029 //
00030 //  A Sample structure
00031 //      The single data sample point
00032 //
00033 typedef struct _data_sample
00034 {
00035     int32_t     iQData;
00036     int32_t     iIData;
00037 } TDataSample;
00038 
00039 // Long samples - more bit sizes
00040 // Not used by the buffers, but available for other parts in the system
00041 typedef struct _long_data_sample
00042 {
00043     int64_t     iQData;
00044     int64_t     iIData;
00045 } TLongDataSample;
00046 
00047 extern const TDataSample NullSample;
00048  
00049 //
00050 // Classes
00051 //
00052 
00053 // Forward references
00054 class TBufferPool;
00055 
00056 //---------------------------------------------------------------------------
00057 //
00058 //  A Buffer Data Class
00059 //      The actual thing that holds the sample data
00060 //
00061 class TBufferData
00062 {
00063     // create/destroy
00064     public:
00065         // creates the buffer
00066         TBufferData() :
00067             iLength(0),
00068             pNext(NULL),
00069             iRefCount(0),
00070             pPool(NULL)
00071             {}
00072         // delete the buffer
00073         ~TBufferData()
00074             {}
00075 
00076     // API
00077     public:
00078 
00079         // Check the reference count
00080         //  Any operation that changes a buffer's data (or provides a write pointer) MUST check 
00081         //  iRefCount and throw exception if not = 1
00082         inline void CheckRefCount( void ) const
00083         {
00084             if ( iRefCount != 1 ) 
00085                 error( "TBufferData::CheckRefCount RefCount not equal to 1\r\n" );
00086         }
00087 
00088         // Clear the buffer
00089         void Clear( void )
00090         {
00091             iLength = 0;
00092         }
00093 
00094         // Append a sample
00095         bool Append( const TDataSample *pSample )
00096         {
00097             CheckRefCount();
00098             // Check for overflows
00099             if ( iLength>=BUFFERSYS_SIZE )
00100                 return false;   // no room
00101             // Append the data
00102             asSamples[iLength] = *pSample;
00103             iLength ++;
00104             return true;
00105         }
00106 
00107         // Remove samples form the end of the buffer
00108         //  Fails if there are not enough samples to remove
00109         bool Remove( int iSamples )
00110         {
00111             CheckRefCount();
00112             if ( iSamples<0 )
00113                 error( "TBufferData::Remove Invalid remove number\r\n" );
00114             // Check for underflow
00115             if ( iLength<iSamples )
00116             {   // underflow - remove all anyway
00117                 iLength = 0;
00118                 return false;
00119             }
00120             // adjust the length
00121             iLength -= iSamples;
00122             return true;
00123         }
00124 
00125     // data
00126     private:
00127     
00128         // the buffer
00129         TDataSample     asSamples[BUFFERSYS_SIZE];
00130     
00131         // data size count
00132         int             iLength;    // current samples count
00133         
00134         // a pointer for queuing
00135         TBufferData     *pNext;
00136         
00137         // a reference counter for counting holders of this buffer
00138         int             iRefCount;
00139 
00140         // a timestamp of the sample capture
00141         uint32_t        uiTimestamp;
00142         
00143         // a pointer to this buffers pool (to return it too)
00144         TBufferPool     *pPool;         // the pool that the buffer came from
00145 
00146 #ifdef BUFFER_DEBUG        
00147         // details of buffer ownership (for debugging only)
00148         bool    bQueued;                // the buffer is in a queue
00149         bool    bPooled;                // the buffer is in a pool (unused buffer)
00150 #endif
00151 
00152         //Declare the buffer classes as friendly
00153         //so it can access the protected members of buffers.
00154         friend class TBufferHandle;
00155         friend class TBufferQueue;
00156         friend class TBufferPool;
00157         
00158         
00159 };
00160 
00161 //---------------------------------------------------------------------------
00162 //
00163 //  A Buffer Handle Class
00164 //      Something that holds a buffer
00165 //      Can also be the base class for something that processes a buffer
00166 //
00167 class TBufferHandle
00168 {
00169     // create/destroy
00170     public:
00171         TBufferHandle() :
00172             pMyBuffer( NULL )
00173             {}
00174 
00175         virtual ~TBufferHandle()
00176             {   // release any attached buffer
00177                 Release();
00178             }
00179 
00180     // buffer attached/release  
00181     public:
00182         // test if the handle has a buffer attached
00183         inline bool HasBuffer( void ) const
00184         {
00185             if ( pMyBuffer != NULL ) 
00186                 return true;
00187             return false;
00188         }
00189 
00190     protected:
00191         // attached a buffer to the handle
00192         bool Attach( TBufferData * pBuffer )
00193         {
00194             // release any old buffer
00195             Release();
00196 
00197             // Attach the buffer to the handler
00198             if ( pBuffer != NULL )
00199             {
00200                 pMyBuffer = pBuffer;
00201                 // Increment the reference count of the buffer
00202                 pMyBuffer->iRefCount++;
00203                 return true;
00204             }
00205             return false;
00206         }
00207         // debug - check that a buffer is attached
00208         inline void CheckForBuffer( void ) const
00209         {
00210             if ( pMyBuffer == NULL ) 
00211                 error( "TBufferHandle::CheckForBuffer Handle does not have a buffer attached\r\n" );
00212         }
00213 
00214     public:
00215         // transfer a buffer from another handle
00216         bool TransferBuffer( TBufferHandle & Handle )
00217         {
00218             // attach buffer from other handle
00219             if ( !Attach(Handle.pMyBuffer) )
00220                 return false;
00221             // release buffer from the other handle                
00222             Handle.Release();
00223             return true;
00224         }
00225 
00226         // release the buffer from the handle
00227         void Release( void );
00228 
00229         // Set the timestamp
00230         void Timestamp( uint32_t uiTime )
00231         {
00232             if ( HasBuffer() )
00233                 pMyBuffer->uiTimestamp = uiTime;
00234         }
00235             
00236         // Read the timestamp
00237         uint32_t Timestamp()
00238         {
00239             if ( HasBuffer() )
00240                 return pMyBuffer->uiTimestamp;
00241             return 0;
00242         }
00243 
00244     // buffer manipulation
00245     public:
00246         // append a sample
00247         bool Append( const TDataSample &Sample )
00248         {
00249             CheckForBuffer();
00250             return pMyBuffer->Append( &Sample );
00251         }
00252 
00253         // Remove characters form the end of the buffer
00254         //  Fails if there are not enough bytes to remove
00255         bool Remove( int iBytes )
00256         {
00257             CheckForBuffer();
00258             return pMyBuffer->Remove( iBytes );
00259         }
00260 
00261         // Clear the buffer
00262         void Clear( void )
00263         {
00264             CheckForBuffer();
00265             pMyBuffer->Clear();
00266         }
00267     
00268         // set buffer length (after data has been manually added)
00269         void SetLength( int iLen )
00270         {
00271             if ( HasBuffer() )
00272             {
00273                 if ( iLen<0 )
00274                     iLen = 0;
00275                 if ( iLen>BUFFERSYS_SIZE )
00276                     iLen = BUFFERSYS_SIZE;
00277                 pMyBuffer->iLength = iLen;
00278             }
00279         }
00280 
00281     // buffer examination
00282     public:
00283         // get buffer length
00284         int Length( void ) const
00285         {
00286             if ( !HasBuffer() )
00287                 return 0;
00288             return pMyBuffer->iLength;
00289         }
00290         
00291         // get buffer size
00292         int Size( void ) const
00293         {
00294             if ( !HasBuffer() )
00295                 return 0;
00296             return BUFFERSYS_SIZE;
00297         }
00298 
00299         int Room( void ) const
00300         {
00301             if ( !HasBuffer() )
00302                 return 0;
00303             return ( BUFFERSYS_SIZE - pMyBuffer->iLength );
00304         }
00305 
00306         // get a pointer to the buffer data    
00307         TDataSample * SamplePtr( int iIndex=0 )
00308         {
00309             if ( !HasBuffer() )
00310                 return NULL;        // no buffer
00311             if ( iIndex>pMyBuffer->iLength )
00312                 return NULL;        // index past end of buffer
00313             return &(pMyBuffer->asSamples[iIndex]);
00314         }
00315         // get buffer data (note that there is no way to detect failure)
00316         const TDataSample operator []( int iIndex ) const
00317         {
00318             if ( HasBuffer() && (iIndex<pMyBuffer->iLength) && (iIndex>=0) )
00319                 return pMyBuffer->asSamples[iIndex];
00320             return NullSample;  // otherwise return empty sample
00321         }
00322 
00323     // data
00324     protected:
00325         // pointer to the buffer being references to
00326         TBufferData    *pMyBuffer;
00327         
00328     friend class TBufferQueue;
00329     friend class TBufferPool;
00330 };
00331 
00332 //---------------------------------------------------------------------------
00333 //
00334 //  A Buffer Queue
00335 //      A queue of buffers
00336 //
00337 class TBufferQueue
00338 {
00339     // create/destroy
00340     public:
00341         TBufferQueue() :
00342             pFront(NULL),
00343             pBack(NULL),
00344             iCount(0)
00345             {}
00346 
00347         virtual ~TBufferQueue()
00348         {
00349             // release all buffer
00350             Flush();
00351         }
00352 
00353     // queue manipulation
00354     public:
00355         // peek at the front buffer on the queue, but still leave the buffer there
00356         // (buffer must not be editted)    
00357         bool Peek( TBufferHandle &Handle ) const
00358         {   // attached the buffer to the handle
00359             return Handle.Attach( pFront );     // Attach also inc ref count
00360         }
00361 
00362         // remove the first buffer from the queue and return in the handle
00363         bool Read( TBufferHandle &Handle )
00364         {
00365             // release any old buffers
00366             Handle.Release();
00367             // check for any buffers
00368             if ( iCount<=0 )
00369                 return false;   //Nothing in queue
00370             // get the front buffer
00371             TBufferData * pRemovedBuffer = pFront;
00372             if ( pRemovedBuffer==NULL )
00373                 error( "TBufferQueue::Read queue pFront pointer!\r\n" );
00374             // adjust the queue ptrs
00375             RemovePtrFromQueue();
00376 #ifdef BUFFER_DEBUG        
00377             // reset queued flag
00378             pRemovedBuffer->bQueued = false;
00379 #endif
00380             // no RefCount adjustment needed - buffer is added to handle but release from the queue
00381             // Manually put the buffer into the (empty) handle
00382             Handle.pMyBuffer = pRemovedBuffer;
00383             return true;
00384         }
00385         
00386         // Write a buffer into the queue, removing it from the handle
00387         bool Write( TBufferHandle &Handle )
00388         {
00389             // check there is a buffer
00390             if ( !Handle.HasBuffer() ) 
00391                 return false;
00392             // Buffer is manually moved (Reference counter is untouched)
00393             // Add msg ptr to the queue (does not adjust the reference counter)
00394             AddPtrToQueue( Handle.pMyBuffer ); 
00395             // Flag the buffer as queued
00396 #ifdef BUFFER_DEBUG        
00397             Handle.pMyBuffer->bQueued = true;       
00398 #endif
00399             // no RefCount adjustment needed - buffer is added to queue but release from the handle
00400             // Manually remove the buffer from the handle
00401             Handle.pMyBuffer = NULL;
00402             return true;
00403         }
00404     
00405         // Return number of queued buffers
00406         int Count() const
00407             { return iCount; }
00408 
00409         // Test if empty
00410         bool Empty() const
00411             { return (iCount==0); }
00412 
00413         // strip all buffers from the queue
00414         bool Flush( void )
00415         {
00416             // check for buffers to flush
00417             if ( iCount==0 )
00418                 return false;
00419             // read and release buffers until no more to read
00420             TBufferHandle MsgHandle;
00421             while ( Read(MsgHandle) )
00422             {   // release the buffers
00423                 MsgHandle.Release();
00424             }
00425             return true;
00426         }
00427 
00428     // internal methods
00429     protected:
00430         // Add the buffer to the end of the queue 
00431         //  Does not do any checks etc or adjust buffer reference count
00432         void AddPtrToQueue( TBufferData *pMsg )
00433         {
00434             pMsg->pNext = NULL;    
00435             if ( iCount == 0 ) 
00436             {   // Queue is currently empty
00437                 // Front = back = buffer
00438                 pFront = pMsg;
00439                 pBack = pMsg;
00440                 iCount = 1;
00441             }   
00442             else 
00443             {   // Add the buffer to the back of the queue
00444                 pBack->pNext = pMsg;
00445                 pBack = pMsg;
00446                 iCount++;
00447             }
00448         }
00449       
00450         // Remove a pointer from the front of the queue
00451         //  Does not do any checks etc or adjust buffer reference count - just removes pointer
00452         void RemovePtrFromQueue( void )
00453         {
00454             // adjust the queue
00455             if ( iCount<=1 )
00456             {   // Empty queue
00457                 pFront = NULL;
00458                 pBack = NULL;
00459                 iCount=0;
00460             } 
00461             else 
00462             {
00463                 // Remove first item
00464                 pFront = pFront->pNext;
00465                 // Decrement the number of buffers in the queue
00466                 iCount--;
00467             }
00468         }
00469         
00470     // data
00471     protected:
00472         TBufferData    *pFront;        // front of the queue (out point)
00473         TBufferData    *pBack;         // back of the queue (in point)
00474         int         iCount;         // number of items in the queue
00475 
00476     friend class TBufferHandle;
00477 
00478 
00479 
00480 
00481 };
00482 
00483 //---------------------------------------------------------------------------
00484 //
00485 //  A Buffer Pool
00486 //      A pool of free buffers
00487 //
00488 class TBufferPool : protected TBufferQueue
00489 {
00490     // create/destroy
00491     public:
00492         // create an pool and optionally add buffers to it off the stack
00493         TBufferPool( int iNumMsgs=0 ) :
00494             iBuffCount(0)
00495             {
00496                 if (iNumMsgs>0)
00497                     CreateBuffers( iNumMsgs );
00498             }
00499         // destroy a pool and all of its internal methods
00500         virtual ~TBufferPool()
00501         {
00502             // delete all buffers
00503             TBufferHandle MsgHandle;
00504             while ( Read(MsgHandle) )
00505             {
00506                 // delete the TBufferData
00507                 delete MsgHandle.pMyBuffer;
00508                 // clear the buffer handle
00509                 MsgHandle.pMyBuffer = NULL;
00510             }
00511         }
00512 
00513     // pool setup
00514     public:
00515         // Add buffers to the pool
00516         // Buffers are created off the heap
00517         bool CreateBuffers( int iNumMsgs )
00518         {
00519             TBufferData * pBuff;
00520             // Loop and create msgs
00521             while ( iNumMsgs>0 )
00522             {   
00523                 //printf( "Creating buffer %d\r\n", iBuffCount );
00524                 // Create the new buffer
00525                 pBuff = new TBufferData;
00526                 if ( pBuff==NULL )
00527                     return false;
00528                 // add the buffer to the pool
00529                 pBuff->pPool = this;
00530                 ReturnToPool( pBuff );
00531                 iBuffCount++;
00532                 iNumMsgs--;
00533             }
00534             return true;           
00535         }
00536     
00537         // add a new buffer to the pool - 
00538         //      either as a buffer (with or without a data structure)
00539         //      or as a data structure with a buffer
00540         void AddNewMsgToPool( TBufferData & Buffer )
00541         {
00542             Buffer.pPool = this;
00543             ReturnToPool( &Buffer );
00544             iBuffCount++;
00545         }
00546 
00547         // add an array of buffers to the pool
00548         void AddNewMsgsToPool( TBufferData *pBuffer, int iCount )
00549         {
00550             while ( iCount>0 )
00551             {
00552                 AddNewMsgToPool( *pBuffer );
00553                 pBuffer++;
00554                 iCount--;
00555             }
00556         }
00557 
00558         // place or return a buffer in the pool
00559         void ReturnToPool( TBufferData * pBuffer )
00560         {
00561             // Add to the queue (does not adjust the reference counter)
00562             AddPtrToQueue( pBuffer );
00563             // zero reference (should already be the case)
00564             pBuffer->iRefCount = 0;
00565 #ifdef BUFFER_DEBUG
00566             // Flag the buffer as pooled
00567             pBuffer->bPooled = true;       
00568 #endif
00569         }
00570 
00571     // Message Handling
00572     public:
00573         // buffer creation - takes a msg from the pool
00574         bool Create( TBufferHandle &Handle )
00575         {
00576             // read the buffer from the queue
00577             if ( !Read(Handle) )
00578                 return false;
00579             // inc ref count (RefCount is 0 in pool, and Read does not adjust it)
00580             Handle.pMyBuffer->iRefCount++;
00581 #ifdef BUFFER_DEBUG
00582             // reset pool flag
00583             Handle.pMyBuffer->bPooled = false;
00584 #endif
00585             // Initialise the buffer
00586             Handle.Clear();
00587             Handle.pMyBuffer->uiTimestamp = 0;
00588             return true;
00589         }
00590 
00591     // Pool Status
00592     public:
00593         // return number of buffers available
00594         int Available() const
00595             { return iCount; }
00596 
00597     // data
00598     protected:
00599         int     iBuffCount;      // number of buffers installed in the pool
00600     
00601     friend class TBufferData;
00602     friend class TBufferHandle;
00603     
00604 };
00605 
00606 
00607 #endif
00608 
00609 //---------------------------------------------------------------------------
00610 //  END
00611 //---------------------------------------------------------------------------
00612