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

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
+//---------------------------------------------------------------------------
+