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

Files at this revision

API Documentation at this revision

Comitter:
claytong
Date:
Wed Jan 25 20:32:53 2012 +0000
Commit message:
1.0 (initial public release)

Changed in this revision

BufferSys.cpp Show annotated file Show diff for this revision Revisions of this file
BufferSys.h Show annotated file Show diff for this revision Revisions of this file
DNSResolver.lib Show annotated file Show diff for this revision Revisions of this file
DSP.cpp Show annotated file Show diff for this revision Revisions of this file
DSP.h Show annotated file Show diff for this revision Revisions of this file
I2S_Rx.cpp Show annotated file Show diff for this revision Revisions of this file
I2S_Rx.h Show annotated file Show diff for this revision Revisions of this file
NetServices.lib Show annotated file Show diff for this revision Revisions of this file
comms.cpp Show annotated file Show diff for this revision Revisions of this file
comms.h Show annotated file Show diff for this revision Revisions of this file
global.h Show annotated file Show diff for this revision Revisions of this file
gps.cpp Show annotated file Show diff for this revision Revisions of this file
gps.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 82ff15078322 BufferSys.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BufferSys.cpp	Wed Jan 25 20:32:53 2012 +0000
@@ -0,0 +1,53 @@
+/*---------------------------------------------------------------------------
+
+    QRSS Receiver Application
+        
+    by Clayton ZL3TKA/VK1TKA
+    clayton@isnotcrazy.com
+    
+    Buffer System
+
+---------------------------------------------------------------------------*/
+// include files
+
+#include "BufferSys.h"
+
+// Definitions
+
+// Macros
+
+// Local Data
+
+// Global Data
+const TDataSample NullSample = {0,0};
+
+// Function Prototypes
+
+//---------------------------------------------------------------------------
+//  BUFFER SYSTEM METHODS
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+//
+//  Buffer Release Method
+//
+void TBufferHandle::Release( void )
+{
+    if ( !HasBuffer() )
+        return;
+    // If the handler was the only reference to the buffer
+    //  then the buffer should be released to the pool
+    if ( pMyBuffer->iRefCount<=0 )
+         error( "TBufferHandle::CheckForBuffer Invalid TBufferData iRefCount in Release - %d\r\n", pMyBuffer->iRefCount );
+    pMyBuffer->iRefCount--;
+    if ( pMyBuffer->iRefCount==0 )
+    {   // Release message to the pool it came from
+        pMyBuffer->pPool->ReturnToPool( pMyBuffer );
+    } 
+    // Detach the message from the handler
+    pMyBuffer = NULL;
+}
+
+//---------------------------------------------------------------------------
+//  END
+//---------------------------------------------------------------------------
diff -r 000000000000 -r 82ff15078322 BufferSys.h
--- /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
+//---------------------------------------------------------------------------
+
diff -r 000000000000 -r 82ff15078322 DNSResolver.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DNSResolver.lib	Wed Jan 25 20:32:53 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/hlipka/code/DNSResolver/#83c60912e03f
diff -r 000000000000 -r 82ff15078322 DSP.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DSP.cpp	Wed Jan 25 20:32:53 2012 +0000
@@ -0,0 +1,451 @@
+/*---------------------------------------------------------------------------
+
+    QRSS Receiver Application
+        
+    by Clayton ZL3TKA/VK1TKA
+    clayton@isnotcrazy.com
+
+    DSP Processing class
+
+---------------------------------------------------------------------------*/
+// include files
+
+#include "DSP.h"
+
+// Definitions
+
+// Macros
+
+// Local Data
+
+// Global Data
+
+// Function Prototypes
+
+
+/*
+
+    LP FIR Filter calculated from Web calculator
+        http://www-users.cs.york.ac.uk/~fisher/cgi-bin/mkfscript
+
+    Sample Rate:    35156
+    Corner Freq:    200
+    Taps:           511
+    Beta:           0.5
+
+// Digital filter designed by mkfilter/mkshape/gencode   A.J. Fisher
+//  Command line: /www/usr/fisher/helpers/mkshape -c 5.6889293435e-03 5.0000000000e-01 511 -b 16 -l
+
+#define NZEROS 510
+#define GAIN   8.763528442e+01
+
+static float xv[NZEROS+1];
+
+static float xcoeffs[] =
+  { +0.0006713867, +0.0008544922, +0.0010375977, +0.0012817383,
+    +0.0015258789, +0.0017700195, +0.0020446777, +0.0023498535,
+    +0.0026855469, +0.0030212402, +0.0033874512, +0.0037841797,
+    +0.0041809082, +0.0046081543, +0.0050659180, +0.0055236816,
+    +0.0060119629, +0.0065002441, +0.0070190430, +0.0075378418,
+    +0.0080871582, +0.0086364746, +0.0092163086, +0.0097961426,
+    +0.0103759766, +0.0109558105, +0.0115661621, +0.0121765137,
+    +0.0127868652, +0.0133972168, +0.0140075684, +0.0146179199,
+    +0.0151977539, +0.0158081055, +0.0163879395, +0.0169677734,
+    +0.0175476074, +0.0180969238, +0.0186462402, +0.0191650391,
+    +0.0196533203, +0.0201416016, +0.0205688477, +0.0209960938,
+    +0.0213928223, +0.0217590332, +0.0220947266, +0.0223693848,
+    +0.0226440430, +0.0228576660, +0.0230102539, +0.0231323242,
+    +0.0232238770, +0.0232238770, +0.0232238770, +0.0231323242,
+    +0.0229797363, +0.0227966309, +0.0225219727, +0.0222167969,
+    +0.0218200684, +0.0213623047, +0.0208435059, +0.0202636719,
+    +0.0195922852, +0.0188598633, +0.0180664062, +0.0171813965,
+    +0.0162048340, +0.0151672363, +0.0140380859, +0.0128479004,
+    +0.0115661621, +0.0102233887, +0.0087890625, +0.0072631836,
+    +0.0056762695, +0.0039978027, +0.0022277832, +0.0003967285,
+    -0.0015258789, -0.0035095215, -0.0055847168, -0.0077514648,
+    -0.0099792480, -0.0122680664, -0.0146484375, -0.0170898438,
+    -0.0195922852, -0.0221557617, -0.0248107910, -0.0274963379,
+    -0.0302429199, -0.0330505371, -0.0359191895, -0.0388183594,
+    -0.0417785645, -0.0447692871, -0.0477905273, -0.0508422852,
+    -0.0539245605, -0.0570373535, -0.0601501465, -0.0632934570,
+    -0.0664367676, -0.0695800781, -0.0727233887, -0.0758666992,
+    -0.0789794922, -0.0820922852, -0.0851745605, -0.0881958008,
+    -0.0912170410, -0.0941467285, -0.0970764160, -0.0999145508,
+    -0.1026916504, -0.1054077148, -0.1080322266, -0.1105651856,
+    -0.1130065918, -0.1153564453, -0.1175842285, -0.1197204590,
+    -0.1217346191, -0.1235961914, -0.1253356934, -0.1269226074,
+    -0.1283569336, -0.1296386719, -0.1307373047, -0.1316833496,
+    -0.1324462891, -0.1329956055, -0.1333923340, -0.1335754394,
+    -0.1335144043, -0.1332702637, -0.1328125000, -0.1321105957,
+    -0.1311950684, -0.1300048828, -0.1286010742, -0.1269226074,
+    -0.1250000000, -0.1228332519, -0.1203613281, -0.1176452637,
+    -0.1146545410, -0.1113586426, -0.1077880859, -0.1039428711,
+    -0.0997924805, -0.0953369141, -0.0906066895, -0.0855407715,
+    -0.0802001953, -0.0745544434, -0.0686035156, -0.0623168945,
+    -0.0557250977, -0.0488586426, -0.0416564941, -0.0341186523,
+    -0.0263061523, -0.0181579590, -0.0097351074, -0.0009765625,
+    +0.0080871582, +0.0174255371, +0.0270996094, +0.0370483398,
+    +0.0473022461, +0.0578308105, +0.0686645508, +0.0797729492,
+    +0.0911560059, +0.1028137207, +0.1147155762, +0.1268920898,
+    +0.1393432617, +0.1520080566, +0.1649169922, +0.1780700684,
+    +0.1914367676, +0.2050170898, +0.2188110352, +0.2327880859,
+    +0.2469482422, +0.2613220215, +0.2758178711, +0.2904968262,
+    +0.3053283691, +0.3203125000, +0.3353881836, +0.3505859375,
+    +0.3659057617, +0.3812866211, +0.3967590332, +0.4122924805,
+    +0.4279174805, +0.4435424805, +0.4591979981, +0.4748840332,
+    +0.4905700684, +0.5062561035, +0.5219116211, +0.5375366211,
+    +0.5531005859, +0.5686035156, +0.5840148926, +0.5993652344,
+    +0.6145935059, +0.6296997070, +0.6446838379, +0.6595153809,
+    +0.6741943359, +0.6886901855, +0.7030334473, +0.7171325684,
+    +0.7310485840, +0.7447204590, +0.7581787109, +0.7713623047,
+    +0.7843017578, +0.7969665527, +0.8093261719, +0.8214111328,
+    +0.8331604004, +0.8446044922, +0.8557128906, +0.8664855957,
+    +0.8768920898, +0.8869323730, +0.8966064453, +0.9058837891,
+    +0.9147949219, +0.9232788086, +0.9313659668, +0.9390258789,
+    +0.9462585449, +0.9530944824, +0.9594421387, +0.9653625488,
+    +0.9708557129, +0.9758605957, +0.9804077148, +0.9844970703,
+    +0.9880981445, +0.9912414551, +0.9938964844, +0.9960937500,
+    +0.9977722168, +0.9989929199, +0.9997253418, +0.9999694824,
+    +0.9997253418, +0.9989929199, +0.9977722168, +0.9960937500,
+    +0.9938964844, +0.9912414551, +0.9880981445, +0.9844970703,
+    +0.9804077148, +0.9758605957, +0.9708557129, +0.9653625488,
+    +0.9594421387, +0.9530944824, +0.9462585449, +0.9390258789,
+    +0.9313659668, +0.9232788086, +0.9147949219, +0.9058837891,
+    +0.8966064453, +0.8869323730, +0.8768920898, +0.8664855957,
+    +0.8557128906, +0.8446044922, +0.8331604004, +0.8214111328,
+    +0.8093261719, +0.7969665527, +0.7843017578, +0.7713623047,
+    +0.7581787109, +0.7447204590, +0.7310485840, +0.7171325684,
+    +0.7030334473, +0.6886901855, +0.6741943359, +0.6595153809,
+    +0.6446838379, +0.6296997070, +0.6145935059, +0.5993652344,
+    +0.5840148926, +0.5686035156, +0.5531005859, +0.5375366211,
+    +0.5219116211, +0.5062561035, +0.4905700684, +0.4748840332,
+    +0.4591979981, +0.4435424805, +0.4279174805, +0.4122924805,
+    +0.3967590332, +0.3812866211, +0.3659057617, +0.3505859375,
+    +0.3353881836, +0.3203125000, +0.3053283691, +0.2904968262,
+    +0.2758178711, +0.2613220215, +0.2469482422, +0.2327880859,
+    +0.2188110352, +0.2050170898, +0.1914367676, +0.1780700684,
+    +0.1649169922, +0.1520080566, +0.1393432617, +0.1268920898,
+    +0.1147155762, +0.1028137207, +0.0911560059, +0.0797729492,
+    +0.0686645508, +0.0578308105, +0.0473022461, +0.0370483398,
+    +0.0270996094, +0.0174255371, +0.0080871582, -0.0009765625,
+    -0.0097351074, -0.0181579590, -0.0263061523, -0.0341186523,
+    -0.0416564941, -0.0488586426, -0.0557250977, -0.0623168945,
+    -0.0686035156, -0.0745544434, -0.0802001953, -0.0855407715,
+    -0.0906066895, -0.0953369141, -0.0997924805, -0.1039428711,
+    -0.1077880859, -0.1113586426, -0.1146545410, -0.1176452637,
+    -0.1203613281, -0.1228332519, -0.1250000000, -0.1269226074,
+    -0.1286010742, -0.1300048828, -0.1311950684, -0.1321105957,
+    -0.1328125000, -0.1332702637, -0.1335144043, -0.1335754394,
+    -0.1333923340, -0.1329956055, -0.1324462891, -0.1316833496,
+    -0.1307373047, -0.1296386719, -0.1283569336, -0.1269226074,
+    -0.1253356934, -0.1235961914, -0.1217346191, -0.1197204590,
+    -0.1175842285, -0.1153564453, -0.1130065918, -0.1105651856,
+    -0.1080322266, -0.1054077148, -0.1026916504, -0.0999145508,
+    -0.0970764160, -0.0941467285, -0.0912170410, -0.0881958008,
+    -0.0851745605, -0.0820922852, -0.0789794922, -0.0758666992,
+    -0.0727233887, -0.0695800781, -0.0664367676, -0.0632934570,
+    -0.0601501465, -0.0570373535, -0.0539245605, -0.0508422852,
+    -0.0477905273, -0.0447692871, -0.0417785645, -0.0388183594,
+    -0.0359191895, -0.0330505371, -0.0302429199, -0.0274963379,
+    -0.0248107910, -0.0221557617, -0.0195922852, -0.0170898438,
+    -0.0146484375, -0.0122680664, -0.0099792480, -0.0077514648,
+    -0.0055847168, -0.0035095215, -0.0015258789, +0.0003967285,
+    +0.0022277832, +0.0039978027, +0.0056762695, +0.0072631836,
+    +0.0087890625, +0.0102233887, +0.0115661621, +0.0128479004,
+    +0.0140380859, +0.0151672363, +0.0162048340, +0.0171813965,
+    +0.0180664062, +0.0188598633, +0.0195922852, +0.0202636719,
+    +0.0208435059, +0.0213623047, +0.0218200684, +0.0222167969,
+    +0.0225219727, +0.0227966309, +0.0229797363, +0.0231323242,
+    +0.0232238770, +0.0232238770, +0.0232238770, +0.0231323242,
+    +0.0230102539, +0.0228576660, +0.0226440430, +0.0223693848,
+    +0.0220947266, +0.0217590332, +0.0213928223, +0.0209960938,
+    +0.0205688477, +0.0201416016, +0.0196533203, +0.0191650391,
+    +0.0186462402, +0.0180969238, +0.0175476074, +0.0169677734,
+    +0.0163879395, +0.0158081055, +0.0151977539, +0.0146179199,
+    +0.0140075684, +0.0133972168, +0.0127868652, +0.0121765137,
+    +0.0115661621, +0.0109558105, +0.0103759766, +0.0097961426,
+    +0.0092163086, +0.0086364746, +0.0080871582, +0.0075378418,
+    +0.0070190430, +0.0065002441, +0.0060119629, +0.0055236816,
+    +0.0050659180, +0.0046081543, +0.0041809082, +0.0037841797,
+    +0.0033874512, +0.0030212402, +0.0026855469, +0.0023498535,
+    +0.0020446777, +0.0017700195, +0.0015258789, +0.0012817383,
+    +0.0010375977, +0.0008544922, +0.0006713867,
+  };
+
+static void filterloop()
+  { for (;;)
+      { float sum; int i;
+        for (i = 0; i < NZEROS; i++) xv[i] = xv[i+1];
+        xv[NZEROS] = next input value / GAIN;
+        sum = 0.0;
+        for (i = 0; i <= NZEROS; i++) sum += (xcoeffs[i] * xv[i]);
+        next output value = sum;
+      }
+  }
+
+*/
+
+const int16_t aiFIRCoefficients[DSP_FIR_COEFFICIENTS] = {
+        22,28,34,42,50,58,67,77,
+        88,99,111,124,137,151,166,181,
+        197,213,230,247,265,283,302,321,
+        340,359,379,399,419,439,459,479,
+        498,518,537,556,575,593,611,628,
+        644,660,674,688,701,713,724,733,
+        742,749,754,758,761,761,761,758,
+        753,747,738,728,715,700,683,664,
+        642,618,592,563,531,497,460,421,
+        379,335,288,238,186,131,73,13,
+        -50,-115,-183,-254,-327,-402,-480,-560,
+        -642,-726,-813,-901,-991,-1083,-1177,-1272,
+        -1369,-1467,-1566,-1666,-1767,-1869,-1971,-2074,
+        -2177,-2280,-2383,-2486,-2588,-2690,-2791,-2890,
+        -2989,-3085,-3181,-3274,-3365,-3454,-3540,-3623,
+        -3703,-3780,-3853,-3923,-3989,-4050,-4107,-4159,
+        -4206,-4248,-4284,-4315,-4340,-4358,-4371,-4377,
+        -4375,-4367,-4352,-4329,-4299,-4260,-4214,-4159,
+        -4096,-4025,-3944,-3855,-3757,-3649,-3532,-3406,
+        -3270,-3124,-2969,-2803,-2628,-2443,-2248,-2042,
+        -1826,-1601,-1365,-1118,-862,-595,-319,-32,
+        265,571,888,1214,1550,1895,2250,2614,
+        2987,3369,3759,4158,4566,4981,5404,5835,
+        6273,6718,7170,7628,8092,8563,9038,9519,
+        10005,10496,10990,11488,11990,12494,13001,13510,
+        14022,14534,15047,15561,16075,16589,17102,17614,
+        18124,18632,19137,19640,20139,20634,21125,21611,
+        22092,22567,23037,23499,23955,24403,24844,25276,
+        25700,26115,26520,26916,27301,27676,28040,28393,
+        28734,29063,29380,29684,29976,30254,30519,30770,
+        31007,31231,31439,31633,31813,31977,32126,32260,
+        32378,32481,32568,32640,32695,32735,32759,32767,
+        32759,32735,32695,32640,32568,32481,32378,32260,
+        32126,31977,31813,31633,31439,31231,31007,30770,
+        30519,30254,29976,29684,29380,29063,28734,28393,
+        28040,27676,27301,26916,26520,26115,25700,25276,
+        24844,24403,23955,23499,23037,22567,22092,21611,
+        21125,20634,20139,19640,19137,18632,18124,17614,
+        17102,16589,16075,15561,15047,14534,14022,13510,
+        13001,12494,11990,11488,10990,10496,10005,9519,
+        9038,8563,8092,7628,7170,6718,6273,5835,
+        5404,4981,4566,4158,3759,3369,2987,2614,
+        2250,1895,1550,1214,888,571,265,-32,
+        -319,-595,-862,-1118,-1365,-1601,-1826,-2042,
+        -2248,-2443,-2628,-2803,-2969,-3124,-3270,-3406,
+        -3532,-3649,-3757,-3855,-3944,-4025,-4096,-4159,
+        -4214,-4260,-4299,-4329,-4352,-4367,-4375,-4377,
+        -4371,-4358,-4340,-4315,-4284,-4248,-4206,-4159,
+        -4107,-4050,-3989,-3923,-3853,-3780,-3703,-3623,
+        -3540,-3454,-3365,-3274,-3181,-3085,-2989,-2890,
+        -2791,-2690,-2588,-2486,-2383,-2280,-2177,-2074,
+        -1971,-1869,-1767,-1666,-1566,-1467,-1369,-1272,
+        -1177,-1083,-991,-901,-813,-726,-642,-560,
+        -480,-402,-327,-254,-183,-115,-50,13,
+        73,131,186,238,288,335,379,421,
+        460,497,531,563,592,618,642,664,
+        683,700,715,728,738,747,753,758,
+        761,761,761,758,754,749,742,733,
+        724,713,701,688,674,660,644,628,
+        611,593,575,556,537,518,498,479,
+        459,439,419,399,379,359,340,321,
+        302,283,265,247,230,213,197,181,
+        166,151,137,124,111,99,88,77,
+        67,58,50,42,34,28,22
+        };
+
+/*
+    Sin table to convert NCO phase to Oscillator outputs
+*/
+const int16_t aiSinTable[256] = {
+        0,6,13,19,25,31,37,44,
+        50,56,62,68,74,80,86,92,
+        98,103,109,115,120,126,131,136,
+        142,147,152,157,162,167,171,176,
+        180,185,189,193,197,201,205,208,
+        212,215,219,222,225,228,231,233,
+        236,238,240,242,244,246,247,249,
+        250,251,252,253,254,254,255,255,
+        255,255,255,254,254,253,252,251,
+        250,249,247,246,244,242,240,238,
+        236,233,231,228,225,222,219,215,
+        212,208,205,201,197,193,189,185,
+        180,176,171,167,162,157,152,147,
+        142,136,131,126,120,115,109,103,
+        98,92,86,80,74,68,62,56,
+        50,44,37,31,25,19,13,6,
+        0,-6,-13,-19,-25,-31,-37,-44,
+        -50,-56,-62,-68,-74,-80,-86,-92,
+        -98,-103,-109,-115,-120,-126,-131,-136,
+        -142,-147,-152,-157,-162,-167,-171,-176,
+        -180,-185,-189,-193,-197,-201,-205,-208,
+        -212,-215,-219,-222,-225,-228,-231,-233,
+        -236,-238,-240,-242,-244,-246,-247,-249,
+        -250,-251,-252,-253,-254,-254,-255,-255,
+        -255,-255,-255,-254,-254,-253,-252,-251,
+        -250,-249,-247,-246,-244,-242,-240,-238,
+        -236,-233,-231,-228,-225,-222,-219,-215,
+        -212,-208,-205,-201,-197,-193,-189,-185,
+        -180,-176,-171,-167,-162,-157,-152,-147,
+        -142,-136,-131,-126,-120,-115,-109,-103,
+        -98,-92,-86,-80,-74,-68,-62,-56,
+        -50,-44,-37,-31,-25,-19,-13,-6 
+        };
+
+//---------------------------------------------------------------------------
+//  LOCAL FUNCTIONS
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+//
+//  Perform a MAC Operation (multiply and Accumulate)
+//      Assumes data is from samples structure, so skips every 2nd sample
+//      Produces a 64 bit result
+//
+int64_t MAC_Samples( int64_t llSum, const int32_t *piSamples, const int16_t *piCoefficients, int iCnt )
+{
+    int64_t llMult;
+    
+    while ( iCnt>0 )
+    {
+        llMult = *piSamples;
+        llMult *= *piCoefficients;
+        llSum += llMult;
+        piSamples++;
+        piSamples++;    // skip other sample pair
+        piCoefficients++;
+        iCnt--;
+    }
+    return llSum;
+}
+
+//---------------------------------------------------------------------------
+//
+//  Convert a 64 bit sum to a 32 bit output
+//
+int32_t ConvertToOutput( int64_t llSum )
+{
+    return (int32_t)(llSum>>FIR_SHIFT_FACTOR);
+}
+
+//---------------------------------------------------------------------------
+//  DSP Methods
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+//
+//  Set up NCO Increment from a frequency value
+//
+void TDSPProcessor::NCOFrequency( int32_t iFreq )
+{
+    int64_t     llFreq;
+    int64_t     llInc;
+
+    // Inc (32bit) = Freq * 2^32 / SampleRate
+    // Use long long (64 bit int) for calculations to prevent overflow and get best resolution
+    llFreq = iFreq;
+    llInc = llFreq * 0x10000 * 0x10000 / SAMPLE_RATE;
+    // Convert back to 32 bit unsigned via integer type
+    uiMixerPhaseIncrement = (uint32_t)((int32_t)llInc);
+    printf( "LO Freq set to %d - NCO Inc set to %u\r\n", iFreq, uiMixerPhaseIncrement );
+}
+
+
+//---------------------------------------------------------------------------
+//
+//  Reset processing
+//
+void TDSPProcessor::Reset()
+{
+    uiMixerPhaseAccumulator = 0;
+    bLPFPartailsValid = false;
+    Release();
+}
+
+//---------------------------------------------------------------------------
+//
+//  Mix samples with LO (local oscillator)
+//
+bool TDSPProcessor::MixLO()
+{
+    int ii;
+    int iLen = Length();
+    TDataSample * pSample;
+    int16_t     iIlo;
+    int16_t     iQlo;
+    int32_t     iIin;
+    int32_t     iQin;
+
+    for ( ii=0,pSample=SamplePtr(); ii<iLen; ii++,pSample++ )
+    {
+        // generate quadrature oscillators. LO I=cos Q=sin
+        iIlo = aiSinTable[ (64+(uiMixerPhaseAccumulator>>24))&0xFF ];     // COS
+        iQlo = aiSinTable[ (uiMixerPhaseAccumulator>>24) ];               // SIN
+        // inc NCO
+        uiMixerPhaseAccumulator += uiMixerPhaseIncrement;
+        // scale samples (they are only 24 bits)
+        iIin = pSample->iIData / 256;
+        iQin = pSample->iQData / 256;
+        // complex multiply sample and LO
+        // (A + Bi) * (C + Di) = (AC - BD) + (BC + AD)i
+        pSample->iIData = (iIin * iIlo) - (iQin * iQlo);
+        pSample->iQData = (iQin * iIlo) + (iIin * iQlo);
+    }
+
+    return true;
+}
+
+//---------------------------------------------------------------------------
+//
+//  LPF processing
+//
+bool TDSPProcessor::LPF()
+{
+/*
+    We just code this up for the parameters defined.
+    It could be dynamically coded, but for simplicity hard-coding will be used
+*/
+#if (BUFFERSYS_SIZE!=512)
+  #error BUFFERSYS_SIZE has changed from 512
+#endif
+#if (DSP_FIR_COEFFICIENTS!=511)
+  #error DSP_FIR_COEFFICIENTS has changed from 511
+#endif
+#if (DECIMATION_RATIO!=64)
+  #error DECIMATION_RATIO has changed from 64
+#endif
+#if (LPF_OUTPUTS_SIZE!=8)
+  #error LPF_OUTPUTS_SIZE has changed from 8
+#endif
+
+    int64_t     iSum;
+    int         ii;
+    bool        bRet = false;
+
+    // Outputs
+    if ( bLPFPartailsValid )
+    {
+        for ( ii=0; ii<8; ii++ )
+        {
+            iSum = MAC_Samples( asLPFPartials[ii].iIData, &(SamplePtr(0)->iIData), &(aiFIRCoefficients[448-(ii*64)]), (ii*64)+62 );
+            asLPFOutputs[ii].iIData = ConvertToOutput( iSum );
+            iSum = MAC_Samples( asLPFPartials[ii].iQData, &(SamplePtr(0)->iQData), &(aiFIRCoefficients[448-(ii*64)]), (ii*64)+62 );
+            asLPFOutputs[ii].iQData = ConvertToOutput( iSum );
+        }
+        bRet = true;
+    }
+    // Partials
+    for ( ii=0; ii<7; ii++ )
+    {
+        asLPFPartials[ii].iIData = MAC_Samples( 0, &(SamplePtr((ii*64)+64)->iIData), &(aiFIRCoefficients[0]), (7-ii)*64 );
+        asLPFPartials[ii].iQData = MAC_Samples( 0, &(SamplePtr((ii*64)+64)->iQData), &(aiFIRCoefficients[0]), (7-ii)*64 );
+    }
+    // Partials[7] = 0
+    asLPFPartials[7].iIData = 0;
+    asLPFPartials[7].iQData = 0;
+    bLPFPartailsValid = true;
+
+    return bRet;
+}
+
+//---------------------------------------------------------------------------
+//  END
+//---------------------------------------------------------------------------
diff -r 000000000000 -r 82ff15078322 DSP.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DSP.h	Wed Jan 25 20:32:53 2012 +0000
@@ -0,0 +1,84 @@
+/*---------------------------------------------------------------------------
+
+    QRSS Receiver Application
+        
+    by Clayton ZL3TKA/VK1TKA
+    clayton@isnotcrazy.com
+
+    Header File for DSP Processing class
+
+---------------------------------------------------------------------------*/
+#ifndef _DSP_H
+#define _DSP_H
+
+#include "mbed.h"
+#include "BufferSys.h"
+
+// Definitions
+
+// Macros
+
+//
+// Classes
+//
+
+//---------------------------------------------------------------------------
+//
+//  DSP Processor Class - based on a buffer handle. Processes the attached samples buffer
+//
+class TDSPProcessor : public TBufferHandle
+{
+
+    // parameters
+    public:
+        // Set NCO phase inc
+        //  Set inc directly
+        void NCOPhaseInc( uint32_t uiPhaseInc )
+            { uiMixerPhaseIncrement = uiPhaseInc; }
+        // Set inc from a frequency
+        void NCOFrequency( int32_t iFreq );
+
+    // results
+    public:
+        // get filtered output data
+        const TDataSample FilteredOutput( int iIndex ) const
+        {
+            if ( !HasBuffer() || (iIndex<0) || (iIndex>=LPF_OUTPUTS_SIZE) )
+                return NullSample;  // return empty sample
+            return asLPFOutputs[iIndex];
+        }
+
+    // processing operations
+    public:
+        // Reset processing
+        void Reset();
+
+        // Mix samples with LO
+        bool MixLO();
+        
+        // LPF processing
+        bool LPF();
+
+    // data
+    protected:
+        // NCO mixer
+        uint32_t        uiMixerPhaseAccumulator;
+        uint32_t        uiMixerPhaseIncrement;
+
+        // LPF outputs
+        TDataSample     asLPFOutputs[LPF_OUTPUTS_SIZE];
+        
+        // LPF partial results (ready to complete with the next buffer)
+        TLongDataSample asLPFPartials[LPF_OUTPUTS_SIZE];
+        
+        // LPF Partials valid flag
+        bool            bLPFPartailsValid;
+        
+};
+
+#endif
+
+//---------------------------------------------------------------------------
+//  END
+//---------------------------------------------------------------------------
+
diff -r 000000000000 -r 82ff15078322 I2S_Rx.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/I2S_Rx.cpp	Wed Jan 25 20:32:53 2012 +0000
@@ -0,0 +1,285 @@
+/*---------------------------------------------------------------------------
+
+    QRSS Receiver Application
+        
+    by Clayton ZL3TKA/VK1TKA
+    clayton@isnotcrazy.com
+
+    I2S Hardware Driver Routines
+
+---------------------------------------------------------------------------*/
+// include files
+
+#include "I2S_Rx.h"
+
+// Definitions
+
+// (bit 12) Source burst size = 1
+// (bit 15) Destination burst size = 1
+// (bit 18) Source Width = 32 bits
+// (bit 21) Destination Width = 32 bits
+// (bit 26) Source Increment
+// (bit 27) Destination Increment
+// (bit 31) enable INT
+#define DMA_CONTROL             ( (0x00 << 12) | (0x00 << 15) | (0x02 << 18) | (0x02 << 21) | (0 << 26) | (1 << 27) | (1U << 31) )
+#define DMA_TC_MASK             0xFFF
+
+// Macros
+
+// Local Data
+
+// pointer to receiver - for use by IRQ routine
+static TI2SReceiver * pI2SReceiver;
+
+// Global Data
+
+// Function Prototypes
+
+//---------------------------------------------------------------------------
+//  IRQ Routines
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+//
+//  DMA Int routine - test and call the object handler if appropriate
+//
+void DMA_IRQHandler(void) 
+{
+    uint32_t regVal;
+
+    // read Int TC (terminal count) Status register
+    regVal = LPC_GPDMA->DMACIntTCStat;
+    // clear interrupts
+    LPC_GPDMA->DMACIntTCClear |= regVal;
+    // test for receiver DMA channel int
+    if ( regVal&1 )
+        pI2SReceiver->DMA_Interrupt();
+}
+
+//---------------------------------------------------------------------------
+//  I2S RECEIVER FUNCTIONS
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+//
+//  TI2SReceiver constructor
+//
+TI2SReceiver::TI2SReceiver( TBufferPool &BuffPol ) :
+            EmptyBuffersPool( BuffPol ),
+            bRunning( false ),
+            ulBufferCount( 0 ),
+            ulBufferAllocations( 0 ),
+            ulBufferFailures( 0 )
+{
+    // Set up I2S pointer for the IRQ routine
+    pI2SReceiver = this;
+    
+    // Enable I2S in the PCONP register (I2S is disabled on reset)
+    LPC_SC->PCONP |= (1 << 27);
+
+    // Connect the I2S sigals to port pins (P0.23 - P0.25)
+    LPC_PINCON->PINSEL1 &= ~( (0x3<<14) | (0x3<<16) | (0x3<<18) );
+    LPC_PINCON->PINSEL1 |=  ( (0x2<<14) | (0x2<<16) | (0x2<<18) );
+}
+
+//---------------------------------------------------------------------------
+//
+//  TI2SReceiver Initialise operation
+//
+void TI2SReceiver::Init()
+{
+    // Enable I2S in the PCONP register (I2S is disabled on reset)
+    LPC_SC->PCONP |= (1 << 27);
+    
+    // Connect the I2S sigals to port pins (P0.23 - P0.25)
+    LPC_PINCON->PINSEL1 &= ~( (0x3<<14) | (0x3<<16) | (0x3<<18) );
+    LPC_PINCON->PINSEL1 |=  ( (0x2<<14) | (0x2<<16) | (0x2<<18) );
+
+    // Stop reception
+    LPC_I2S->I2SDAI = 0x03 | (0x1<<3) | (0x1<<4) | (0x1<<5) | (0x1F<<6);
+
+    // Disable DMA
+    LPC_GPDMACH0->DMACCControl = 0;
+
+    // Initialise DMA
+    LPC_SC->PCONP |= (1 << 29);         // Enable GPDMA clock
+    LPC_GPDMA->DMACConfig = 0x01;       // Enable DMA channels, little endian
+    while ( !(LPC_GPDMA->DMACConfig & 0x01) )  ;
+
+    // Set up DMA Int routine
+    NVIC_SetVector( DMA_IRQn, (uint32_t)DMA_IRQHandler );
+    NVIC_EnableIRQ( DMA_IRQn );
+}
+
+//---------------------------------------------------------------------------
+//
+//  TI2SReceiver Start operation
+//
+void TI2SReceiver::Start()
+{
+    // Stop reception
+    LPC_I2S->I2SDAI = 0x03 | (0x1<<3) | (0x1<<4) | (0x1<<5) | (0x1F<<6);
+    LPC_GPDMACH0->DMACCConfig = 0;
+    LPC_GPDMACH0->DMACCControl = 0;
+    bRunning = false;
+    LPC_GPDMA->DMACIntTCClear = 0x01;   // clear DMA0 flags
+    LPC_GPDMA->DMACIntErrClr = 0x01;
+
+    // Enable DMA
+    // Get new buffer and set up the DMA
+    StartDMATransfer();
+
+    // Slave receive mode. 32 bit data, stereo
+    LPC_I2S->I2SDMA1 = (0x1<<0) | (0x02<<8);        // channel 1 = Rx DMA
+    LPC_I2S->I2SRXMODE = 0;
+    LPC_I2S->I2SDAI = 0x03 | (0x1<<5) | (0x1F<<6);
+    bRunning = true;
+}
+
+//---------------------------------------------------------------------------
+//
+//  TI2SReceiver Stop operation
+//
+void TI2SReceiver::Stop()
+{
+    bRunning = false;
+
+    // Stop reception
+    LPC_I2S->I2SDMA1 = 0;
+    LPC_I2S->I2SDAI = 0x03 | (0x1<<3) | (0x1<<4) | (0x1<<5) | (0x1F<<6);
+    LPC_GPDMACH0->DMACCConfig = 0;
+    LPC_GPDMACH0->DMACCControl = 0;
+
+    // clear out buffers
+    ReceivedBuffers.Flush();
+    CurrentRxBuffer.Release();
+}
+        
+//---------------------------------------------------------------------------
+//
+//  Debug routine - 
+//      Read samples from the I2S by polling it
+//          Returns number of samples read
+//
+int TI2SReceiver::PolledRead( int32_t *piBuffer, int iLen )
+{
+    int iCnt = 0;
+    while ( iLen>0 )
+    {
+        // wait for something in the FIFO
+        if ( ((LPC_I2S->I2SSTATE>>8)&0xF)==0 )
+            continue;
+        // Read it out to the buffer
+        *piBuffer = LPC_I2S->I2SRXFIFO;
+        piBuffer++;
+        iLen--;
+        iCnt++;
+    }
+    return iCnt;
+}
+
+//---------------------------------------------------------------------------
+//
+//  Debug routine - 
+//      Read status register
+//
+uint32_t TI2SReceiver::Status()
+{
+    return LPC_I2S->I2SSTATE;
+}
+//---------------------------------------------------------------------------
+//
+//  Debug routine - 
+//      Report Status
+//
+void TI2SReceiver::Report()
+{
+    printf( "C-%d\r\n", ulBufferCount );
+    printf( "F-%d\r\n", ulBufferFailures );
+/*
+    printf( "I2S Buffers Counter - %d\r\n", ulBufferCount );
+    printf( "I2S Buffer Failures - %d\r\n", ulBufferFailures );
+    printf( "I2S Buffer Allocations - %d\r\n", ulBufferAllocations );
+    printf( "I2S Status Register: 0x%08X\r\n", LPC_I2S->I2SSTATE );
+    printf( "I2S DMA1 Register: 0x%08X\r\n", LPC_I2S->I2SDMA1 );
+    printf( "I2S DMA2 Register: 0x%08X\r\n", LPC_I2S->I2SDMA2 );
+    printf( "DMA Enabled Register: 0x%08X\r\n",  LPC_GPDMA->DMACEnbldChns );
+    printf( "DMA TC Status Register: 0x%08X\r\n",  LPC_GPDMA->DMACIntTCStat );
+    printf( "DMA Err Status Register: 0x%08X\r\n",  LPC_GPDMA->DMACIntErrStat );
+    printf( "DMA Config Register: 0x%08X\r\n",  LPC_GPDMA->DMACConfig );
+    printf( "DMA0 Control Register: 0x%08X\r\n",  LPC_GPDMACH0->DMACCControl );
+    printf( "DMA0 Config Register: 0x%08X\r\n",  LPC_GPDMACH0->DMACCConfig );
+*/
+}
+
+//---------------------------------------------------------------------------
+//
+//  DMA Interrupt Routine
+//
+void TI2SReceiver::DMA_Interrupt( )
+{
+    // exit if receiver is not running
+    if ( !bRunning )
+        return;
+
+    // Queue current buffer
+    CurrentRxBuffer.SetLength( 99999 );     // set length to full buffer size
+    ReceivedBuffers.Write( CurrentRxBuffer );
+    ulBufferCount++;
+
+    // Get new buffer and set up the DMA
+    StartDMATransfer();
+}
+
+//---------------------------------------------------------------------------
+//
+//  Start a new DMA transfer
+//
+void TI2SReceiver::StartDMATransfer()
+{
+    int32_t    *pDataPtr;
+    int         iBufSize;
+
+    // uses DMA0 and sets it up with new buffer (or a dummy buffer if none available)
+    //  DMA channel 0   Source is I2S DMA1 = RX FIFO, Destination is memory
+
+    // count DMA allocations
+    ulBufferAllocations++;
+    
+    // get a buffer
+    pDataPtr = NULL;
+    if ( EmptyBuffersPool.Create(CurrentRxBuffer) )
+    {   // got a buffer
+        pDataPtr = (int32_t *)(CurrentRxBuffer.SamplePtr());
+        iBufSize = CurrentRxBuffer.Size() * 2;          // size = samples*2 (samples are I/Q)
+        CurrentRxBuffer.Timestamp( LPC_TIM2->TC );      // Set timestamp
+    }
+    // check for buffer
+    if ( pDataPtr==NULL )
+    {   // failed to get a buffer - use the dumy buffer
+        ulBufferFailures++;
+        pDataPtr = aulDummyBuffer;
+        iBufSize = I2S_DUMMY_BUFFER_SIZE;
+    }
+
+    // clear any ints
+    LPC_GPDMA->DMACIntTCClear = 0x01;   // clear DMA0 flags
+    LPC_GPDMA->DMACIntErrClr = 0x01;
+
+    // write source addr
+    LPC_GPDMACH0->DMACCSrcAddr = (uint32_t)(&(LPC_I2S->I2SRXFIFO));
+    
+    // write destination
+    LPC_GPDMACH0->DMACCDestAddr = (uint32_t)pDataPtr;
+    
+    // write LL address - use 0 for single transfer
+    LPC_GPDMACH0->DMACCLLI = 0;
+    
+    // write control & config
+    LPC_GPDMACH0->DMACCControl = (iBufSize & DMA_TC_MASK) | DMA_CONTROL;
+    LPC_GPDMACH0->DMACCConfig = 0x08001 | (0x05 << 1) | (0x02 << 11);
+}
+
+//---------------------------------------------------------------------------
+//  END
+//---------------------------------------------------------------------------
diff -r 000000000000 -r 82ff15078322 I2S_Rx.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/I2S_Rx.h	Wed Jan 25 20:32:53 2012 +0000
@@ -0,0 +1,131 @@
+/*---------------------------------------------------------------------------
+
+    QRSS Receiver Application
+        
+    by Clayton ZL3TKA/VK1TKA
+    clayton@isnotcrazy.com
+
+    Header File for I2S Receiver
+        
+    I2S Receiver operates in slave mode
+
+---------------------------------------------------------------------------*/
+#ifndef _I2S_RX_H
+#define _I2S_RX_H
+
+#include "mbed.h"
+#include "BufferSys.h"
+
+// Definitions
+
+#define I2S_DUMMY_BUFFER_SIZE       16
+
+// Macros
+
+//
+// Classes
+//
+
+//---------------------------------------------------------------------------
+//
+//  I2S Receiver Class
+//
+class TI2SReceiver
+{
+    // create/destroy
+    public:
+        TI2SReceiver( TBufferPool &BuffPol );
+        ~TI2SReceiver() 
+            {
+                Stop();
+            }
+
+    // API
+    public:
+        // Initialise the hardware
+        void Init();
+
+        // Start receiving
+        void Start();
+        
+        // Stop receiving
+        void Stop();
+        
+        // Receiver status
+        bool Running()
+            { return bRunning; }
+        
+        // Test for a buffer available
+        //  Return number of queued buffers
+        int Count() const
+            { return ReceivedBuffers.Count(); }
+        //  Test if empty
+        bool Empty() const
+            { return ReceivedBuffers.Empty(); }
+
+        // Read out a buffer
+        bool Read( TBufferHandle &Handle )
+            {
+                // queue is filled from interrupts, so we need to ensure we always access it with interrupts off
+                __disable_irq();
+                bool bRet = ReceivedBuffers.Read(Handle);
+                __enable_irq();
+                return bRet;
+            }
+
+        // report the number of buffer failures
+        uint32_t BufferFailures() const
+            { return ulBufferFailures; }
+
+        // DMA IRQ Routine
+        void DMA_Interrupt(void);
+
+        // Debug routine - 
+        // Read samples from the I2S by polling it
+        //  Returns number of samples read
+        int PolledRead( int32_t *piBuffer, int iLen );
+
+        //  Debug routine - 
+        //      Read status register
+        uint32_t Status();
+
+        //  Debug routine - 
+        //      Report Status
+        void Report();
+
+    // Private methods
+    private:
+
+        //  Start a new DMA transfer
+        void StartDMATransfer();
+
+    // data
+    private:
+        // pool to get buffers from
+        TBufferPool     &EmptyBuffersPool;
+
+        // queue of incoming sample buffers
+        TBufferQueue    ReceivedBuffers;
+
+        // the current buffer being used
+        TBufferHandle   CurrentRxBuffer;
+
+        // flags indicating run status
+        bool            bRunning;
+
+        // a buffer to use when there are no empty buffers available
+        int32_t        aulDummyBuffer[I2S_DUMMY_BUFFER_SIZE];
+        
+        // frame counters etc
+        uint32_t        ulBufferCount;
+        uint32_t        ulBufferAllocations;
+        uint32_t        ulBufferFailures;
+        
+};
+
+#endif
+
+//---------------------------------------------------------------------------
+//  END
+//---------------------------------------------------------------------------
+
diff -r 000000000000 -r 82ff15078322 NetServices.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NetServices.lib	Wed Jan 25 20:32:53 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/simon/code/NetServices/#350011bf8be7
diff -r 000000000000 -r 82ff15078322 comms.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/comms.cpp	Wed Jan 25 20:32:53 2012 +0000
@@ -0,0 +1,328 @@
+/*---------------------------------------------------------------------------
+
+    QRSS Receiver Application
+        
+    by Clayton ZL3TKA/VK1TKA
+    clayton@isnotcrazy.com
+
+    Communications Module
+
+
+---------------------------------------------------------------------------*/
+// include files
+
+#include "comms.h"
+
+// Definitions
+
+#define COMMS_DEBUG     0
+
+// Macros
+
+// Local Data
+
+// Global Data
+
+
+// Function Prototypes
+
+//---------------------------------------------------------------------------
+//  API METHODS
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+//
+//  Initialisation Method
+//
+void TCommunications::Init()
+{
+    eState = ST_START_ETH;
+    iBufferCount = 0;
+    PollTimer.start();
+    CommandTimer.start();
+    uiTestModeInc = 0;
+}
+
+//---------------------------------------------------------------------------
+//
+//  Processing Method
+//      Main state machine
+//
+void TCommunications::Poll()
+{
+    UDPSocketErr udpErr;
+    EthernetErr ethErr;
+    
+    switch ( eState )
+    {
+      case ST_START_ETH:    // Initialise the Ethernet interface
+        EthernetUpLED = 0;
+        RunningLED = 0;
+        ethErr = eth.setup( 25000 );
+        if ( ethErr == ETH_OK ) 
+        {
+            const char * pcHWAddr = eth.getHwAddr();
+            IpAddr ip = eth.getIp();
+            printf("mbed MAC Address is %02X-%02X-%02X-%02X-%02X-%02X\r\n", pcHWAddr[0], pcHWAddr[1], pcHWAddr[2], pcHWAddr[3], pcHWAddr[4], pcHWAddr[5] );
+            printf("mbed IP Address is %d.%d.%d.%d\r\n", ip[0], ip[1], ip[2], ip[3] );
+        } 
+        // Set up UDP
+        ServerSocket.setOnEvent( this, &TCommunications::onUDPSocketEvent );
+        MyPort.setIp( IpAddr() );
+        MyPort.setPort( QRSS_UDP_PORT );
+        ServerSocket.bind( MyPort );
+        udpErr = ServerSocket.bind( MyPort );
+        if ( udpErr != UDPSOCKET_OK )
+        {
+            printf("UDP Bind error %d\r\n", udpErr);
+            break;
+        }
+        // to poll state, and force sending of poll message
+        printf("*POLL_SERVER State*\r\n" );
+        eState = ST_POLL_SERVER;
+        iPPSCount = POLL_MSG_PERIOD;
+        bGotCmnd = false;
+        break;
+
+      case ST_POLL_SERVER:  // Poll the server and wait for it to start the system
+        EthernetUpLED = 1;
+        RunningLED = 0;
+        if ( (iPPSCount>=POLL_MSG_PERIOD) || (PollTimer.read_ms()>POLL_TIMEOUT) )
+        {   // Send a poll message
+            iPPSCount = 0;
+            ServerAddr = dnsService.resolveName( szServerName );
+            if ( ServerAddr.isNull() )
+            {
+                printf("DNS Failed - *START_ETH State*\r\n" );
+                eState = ST_START_ETH;
+                break;
+            }
+            ServerPort.setIp( ServerAddr );
+            ServerPort.setPort( QRSS_UDP_PORT );
+            if ( !SendPollMessage() )
+            {
+                printf("*START_ETH State*\r\n" );
+                eState = ST_START_ETH;
+                break;
+            }
+        }
+        if ( bGotCmnd )
+        {
+            bGotCmnd = false;
+            if ( uiCommand!=0 )
+            {   // start
+                uiNCOPhaseInc = uiNCO;
+                uiTestModeInc = uiTestOsc;
+                printf("*RUNNING State*\r\n" );
+                eState = ST_RUNNING;
+                iBufferCount = 0;
+                CommandTimer.reset();
+            }
+        }
+        break;
+        
+      case ST_RUNNING:       // Running - transfer data to the server
+        EthernetUpLED = 1;
+        RunningLED = 1;
+        if ( (iPPSCount>=POLL_MSG_PERIOD) || (PollTimer.read_ms()>POLL_TIMEOUT) )
+        {   // Send a poll message
+            iPPSCount = 0;
+            if ( !SendPollMessage() )
+            {
+                printf("*START_ETH State*\r\n" );
+                eState = ST_START_ETH;
+                break;
+            }
+        }
+        if ( bGotCmnd )
+        {
+            bGotCmnd = false;
+            CommandTimer.reset();
+            if ( uiCommand==0 )
+            {   // stop
+                printf("*POLL_SERVER State*\r\n" );
+                eState = ST_POLL_SERVER;
+                iPPSCount = POLL_MSG_PERIOD;
+                iBufferCount = 0;
+            }
+        }
+        if ( CommandTimer.read_ms()>RUNNING_TIMEOUT )
+        {
+            printf("Timeout - *POLL_SERVER State*\r\n" );
+            eState = ST_POLL_SERVER;
+            iPPSCount = POLL_MSG_PERIOD;
+            iBufferCount = 0;
+        }
+        break;
+    }
+
+}
+
+//---------------------------------------------------------------------------
+//
+//  RecordPPSTimestamps Method
+//      Records timestamps of events (1PPS or capture of LO divider)
+//
+void TCommunications::RecordPPSTimestamps( uint32_t uiPPSCapture, uint32_t uiLOscCapture, 
+                                            TGPSController::TGPSData &GPSInfo )
+{
+    int ii;
+
+    #if COMMS_DEBUG>0
+      printf( "PPS-Timestamp:Time %d  Count %d  PPSCap %u  LOCap %u    PPS %u   LO %u\r\n", 
+                    LastGPSInfo.iGPSTimeSeconds, iPPSCount, uiPPSCapture, uiLOscCapture,
+                    uiPPSCapture-auiPPSCaptures[0], uiLOscCapture-auiLOscCaptures[0]    );
+    #endif                            
+
+    // clear the captures if GPS is non-operation
+    if ( GPSInfo.iGPSQuality<=0 )
+    {   // GPS is offline
+        uiPPSCapture = 0;
+        uiLOscCapture = 0;
+    }
+
+    // shuffle the queue along
+    for ( ii=7; ii>0; ii-- )
+    {
+        auiPPSCaptures[ii] = auiPPSCaptures[ii-1];
+        auiLOscCaptures[ii] = auiLOscCaptures[ii-1];
+    }
+    // record newest data
+    auiPPSCaptures[0] = uiPPSCapture;
+    auiLOscCaptures[0] = uiLOscCapture;
+    LastGPSInfo = GPSInfo;
+
+    // count event
+    iPPSCount++;
+
+}
+
+//---------------------------------------------------------------------------
+//
+//  Pass sample data for sending. Send when buffer is full
+//
+void TCommunications::SendSamples( uint32_t uiTimestamp, TDataSample sSample )
+{
+    if ( eState!=ST_RUNNING )
+        return;
+
+    if ( iBufferCount==0 )
+    {   // Build buffer header
+        pucBuffDataPtr = (uint8_t *)auiDataBuffer;
+        WriteWord( pucBuffDataPtr, COMM_DATA_MSG,  iBufferCount );
+        WriteWord( pucBuffDataPtr, uiTimestamp,  iBufferCount );
+    }
+    // append data
+    *((TDataSample*)pucBuffDataPtr) = sSample;
+    pucBuffDataPtr += SAMPLE_SET_SIZE;
+    iBufferCount += SAMPLE_SET_SIZE;
+    // send buffer when full
+    if ( iBufferCount>=COMMS_DATABUFF_SIZE )
+    {   // send message
+        int iRet = ServerSocket.sendto( (char *)auiDataBuffer ,iBufferCount, &ServerPort );
+        if ( iRet!=iBufferCount )
+            printf("Sent Error - %d\r\n", iRet );
+        iBufferCount = 0;
+    }
+}
+
+//---------------------------------------------------------------------------
+//  PRIVATE METHODS
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+//
+//  UDP Callback Method
+//
+void TCommunications::onUDPSocketEvent( UDPSocketEvent evnt )
+{
+    if ( evnt==UDPSOCKET_READABLE ) 
+    {
+        uint8_t aucInBf[COMMS_CNTRLBUFF_SIZE];
+        Host    FromHost;
+        int     iLen;
+        while ( 1 )
+        {
+            iLen = ServerSocket.recvfrom( (char *)aucInBf, COMMS_CNTRLBUFF_SIZE, &FromHost );
+            if ( iLen<=0 )
+                break;
+            if ( iLen!=COMM_CMND_MSG_LENGTH )
+                continue;
+            if ( ReadWord(&(aucInBf[0]))!=COMM_CMND_MSG )
+                continue;
+            if ( ReadWord(&(aucInBf[4]))!=COMM_MSG_VERSION )
+                continue;
+            // have a real message!
+            uiCommand = ReadWord( &(aucInBf[8]) );
+            uiNCO = ReadWord( &(aucInBf[12]) );
+            uiTestOsc = ReadWord( &(aucInBf[16]) );
+            bGotCmnd = true;
+            #if COMMS_DEBUG>0
+             printf("Command %d\r\n", uiCommand );
+             printf("NCO %d\r\n", uiNCO );
+             printf("Test %d\r\n", uiTestOsc );
+            #endif
+        }
+    }
+}
+
+//---------------------------------------------------------------------------
+//
+//  Send a UDP Poll Message
+//
+bool TCommunications::SendPollMessage()
+{
+    // Build poll message
+    uint8_t     aucPollBuffer[150];
+    uint8_t    *pucPtr = aucPollBuffer;
+    int         iLen = 0; 
+    int         iRet;
+
+    // reset the backup timer
+    PollTimer.reset();
+    
+    // Build Message
+    WriteWord( pucPtr, COMM_POLL_MSG,                       iLen );
+    WriteWord( pucPtr, COMM_MSG_VERSION,                    iLen );
+    WriteWord( pucPtr, COMM_MSG_HW_ID,                      iLen );
+    WriteWord( pucPtr, COMM_MSG_SW_VERSION,                 iLen );
+    WriteWord( pucPtr, LastGPSInfo.iGPSQuality,             iLen );
+    WriteWord( pucPtr, LastGPSInfo.iGPSSatellites,          iLen );
+    WriteWord( pucPtr, LastGPSInfo.iGPSTimeSeconds,         iLen );
+    WriteWord( pucPtr, LastGPSInfo.iGPSLatMicroDegrees,     iLen );
+    WriteWord( pucPtr, LastGPSInfo.iGPSLongMicroDegrees,    iLen );
+    WriteWord( pucPtr, LastGPSInfo.iGPSAltitudeMeters,      iLen );
+    WriteWord( pucPtr, COMM_MSG_REF_CLOCK,                  iLen );
+    WriteWord( pucPtr, COMM_MSG_RF_MIXER,                   iLen );
+    WriteWord( pucPtr, COMM_MSG_SAMPLE_CLOCK,               iLen );
+    WriteWord( pucPtr, COMM_MSG_SAMPLE_DIVIDER,             iLen );
+    WriteWord( pucPtr, auiPPSCaptures[0],                   iLen );
+    WriteWord( pucPtr, auiPPSCaptures[1],                   iLen );
+    WriteWord( pucPtr, auiPPSCaptures[2],                   iLen );
+    WriteWord( pucPtr, auiPPSCaptures[3],                   iLen );
+    WriteWord( pucPtr, auiPPSCaptures[4],                   iLen );
+    WriteWord( pucPtr, auiPPSCaptures[5],                   iLen );
+    WriteWord( pucPtr, auiPPSCaptures[6],                   iLen );
+    WriteWord( pucPtr, auiPPSCaptures[7],                   iLen );
+    WriteWord( pucPtr, auiLOscCaptures[0],                  iLen );
+    WriteWord( pucPtr, auiLOscCaptures[1],                  iLen );
+    WriteWord( pucPtr, auiLOscCaptures[2],                  iLen );
+    WriteWord( pucPtr, auiLOscCaptures[3],                  iLen );
+    WriteWord( pucPtr, auiLOscCaptures[4],                  iLen );
+    WriteWord( pucPtr, auiLOscCaptures[5],                  iLen );
+    WriteWord( pucPtr, auiLOscCaptures[6],                  iLen );
+    WriteWord( pucPtr, auiLOscCaptures[7],                  iLen );
+    memcpy( pucPtr, COMM_MSG_NAME, COMM_MSGNAME_LEN );
+    pucPtr += COMM_MSGNAME_LEN;
+    iLen += COMM_MSGNAME_LEN;
+        
+    // send message
+    iRet = ServerSocket.sendto( (char *)aucPollBuffer ,iLen, &ServerPort );
+    if ( iRet < 0 )
+        return false;
+    return true;
+}
+
+//---------------------------------------------------------------------------
+//  END
+//---------------------------------------------------------------------------
diff -r 000000000000 -r 82ff15078322 comms.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/comms.h	Wed Jan 25 20:32:53 2012 +0000
@@ -0,0 +1,211 @@
+/*---------------------------------------------------------------------------
+
+    QRSS Receiver Application
+        
+    by Clayton ZL3TKA/VK1TKA
+    clayton@isnotcrazy.com
+
+    Header File for Communications Module
+
+---------------------------------------------------------------------------*/
+#ifndef _COMMS_H
+#define _COMMS_H
+
+#include "mbed.h"
+#include "global.h"
+#include "EthernetNetIf.h"
+#include "UDPSocket.h"
+#include "dnsresolve.h"
+#include "BufferSys.h"
+#include "gps.h"
+
+// Definitions
+
+// UDP output data size - includes header
+#define COMMS_DATABUFF_HEADER   (4+4)
+#define COMMS_DATABUFF_SIZE     ((LPF_OUTPUTS_SIZE*SAMPLE_SET_SIZE*8)+COMMS_DATABUFF_HEADER)
+
+// UDP Control Buffer Size
+#define COMMS_CNTRLBUFF_SIZE    (60)
+
+// Number of seconds between each poll message
+#define POLL_MSG_PERIOD         (6)
+
+// default poll period in absence of 1PPS (mSec)
+#define POLL_TIMEOUT            (10000)
+
+// time to stop sending data if no commands are received
+#define RUNNING_TIMEOUT         (30000)
+
+//
+//  Message Encoding
+//
+#define COMM_POLL_MSG               10
+#define COMM_CMND_MSG               11
+#define COMM_DATA_MSG               12
+#define COMM_MSG_VERSION            1
+#define COMM_MSG_SW_VERSION         1
+#define COMM_MSG_HW_ID              1
+#define COMM_MSG_REF_CLOCK          96000000
+#define COMM_MSG_RF_MIXER           10125000
+#define COMM_MSG_SAMPLE_CLOCK       13500000
+#define COMM_MSG_SAMPLE_DIVIDER     (384*64)
+#define COMM_MSG_NAME               "QRSS_proto"
+#define COMM_MSGNAME_LEN            10
+
+#define COMM_CMND_MSG_LENGTH        (5*4)
+
+// Macros
+
+//
+// Classes
+//
+
+//---------------------------------------------------------------------------
+//
+//  Communications Class
+//
+class TCommunications
+{
+    // create/destroy
+    public:
+        TCommunications() :
+            EthernetUpLED( LED2 ),
+            RunningLED( LED4 )
+            {}
+        ~TCommunications() 
+            {}
+
+    // Local Types - state machine state
+    typedef enum {
+        ST_START_ETH,
+        ST_POLL_SERVER,
+        ST_RUNNING
+        } TCommsStates;
+
+    // API
+    public:
+        // Initialisation
+        void Init();
+
+        // Set up Server DNS name
+        void SetServer( char *szNm )
+            { 
+                strncpy( szServerName, szNm, sizeof(szServerName) ); 
+                szServerName[sizeof(szServerName)-1] = 0;   // place terminator at end incase name was too long
+            }
+
+        // Processing routine
+        void Poll();
+
+        //  RecordPPSTimestamps Method
+        //      Records timestamps of events (1PPS or capture of LO divider)
+        void RecordPPSTimestamps( uint32_t uiPPSCapture, uint32_t uiLOscCapture, 
+                                  TGPSController::TGPSData &GPSInfo );
+
+        // Test if comms is ready for sample data (ie in RUNNING state)
+        bool Running()
+            { return (eState==ST_RUNNING); }
+
+        // Return NCO Inc setting received
+        uint32_t NCOPhaseInc()
+            { return uiNCOPhaseInc; }
+
+        // Return Test Mode setting received
+        uint32_t TestMode()
+            { return uiTestModeInc; }
+
+        //  Pass sample data for sending. Send when buffer is full
+        void SendSamples( uint32_t uiTimestamp, TDataSample sSample );
+
+
+    // Private methods
+    private:
+        // Callback for incoming UDP data
+        void onUDPSocketEvent( UDPSocketEvent evnt );
+
+        // Send a UDP Poll Message
+        bool SendPollMessage();
+
+        // Place a word into a buffer - network byte order
+       void WriteWord( uint8_t * &pucBuff, int32_t iWord, int &iLn )
+            {
+                *pucBuff = (uint8_t)(iWord>>24);
+                pucBuff++;
+                *pucBuff = (uint8_t)(iWord>>16);
+                pucBuff++;
+                *pucBuff = (uint8_t)(iWord>>8);
+                pucBuff++;
+                *pucBuff = (uint8_t)(iWord>>0);
+                pucBuff++;
+                iLn += 4;
+            }
+
+        // Read a word from a buffer - network byte order
+       uint32_t ReadWord( uint8_t * pucBuff )
+            { return (0x1000000*pucBuff[0]) | (0x10000*pucBuff[1]) | (0x100*pucBuff[2]) | (pucBuff[3]); }
+
+    // data
+    private:
+        // LEDs
+        DigitalOut EthernetUpLED;
+        DigitalOut RunningLED;
+
+        // State machine state
+        TCommsStates    eState;
+
+        // Ethernet Interface
+        EthernetNetIf   eth;
+        
+        // UDP Socket for comms
+        char            szServerName[50];
+        UDPSocket       ServerSocket;
+        Host            MyPort;
+        Host            ServerPort;
+        IpAddr          ServerAddr;
+        
+        // DNS lookup
+        DNSResolver     dnsService;
+        
+        // Host Details
+        
+        // Output buffers - word align this buffer
+        uint32_t        auiDataBuffer[(COMMS_DATABUFF_SIZE/4)+8];   // the buffer - defined as words to ensure alignment
+        uint8_t        *pucBuffDataPtr;     // buffer pointer - as a byte pointer
+        int             iBufferCount;       // byte count
+
+        // Incoming UDP Data
+        uint32_t        uiCommand;
+        uint32_t        uiNCO;
+        uint32_t        uiTestOsc;
+        bool            bGotCmnd;
+
+        // PPS Timer Event Counter
+        int             iPPSCount;
+    
+        // Send Poll Message timer
+        Timer           PollTimer;
+        Timer           CommandTimer;
+        
+        // Timer Capture Data - queue of 8 captures. [0] is the most recent
+        uint32_t        auiPPSCaptures[8];
+        uint32_t        auiLOscCaptures[8];
+
+        // Last GPS info        
+        TGPSController::TGPSData    LastGPSInfo;
+        
+        // data from the command packet
+        uint32_t        uiNCOPhaseInc;
+        uint32_t        uiTestModeInc;
+
+};
+
+// declare the Communications module
+extern TCommunications Comms;
+
+#endif
+
+//---------------------------------------------------------------------------
+//  END
+//---------------------------------------------------------------------------
+
diff -r 000000000000 -r 82ff15078322 global.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/global.h	Wed Jan 25 20:32:53 2012 +0000
@@ -0,0 +1,67 @@
+/*---------------------------------------------------------------------------
+
+    QRSS Receiver Application
+        
+    by Clayton ZL3TKA/VK1TKA
+    clayton@isnotcrazy.com
+
+    Header File for global definitions
+
+---------------------------------------------------------------------------*/
+#ifndef _GLOBAL_H
+#define _GLOBAL_H
+
+// Definitions
+
+// Size of data buffers (in samples)
+#define BUFFERSYS_SIZE          512
+
+// Number of buffers
+#define NUM_OF_BUFFERS          4
+
+// Number of co-efficients in the FIR filter
+#define DSP_FIR_COEFFICIENTS    511
+
+// ADC Clock (13.5MHz)
+#define ADC_CLOCK               13500000
+
+// Sample Rate (35156 SPS)
+#define SAMPLE_RATE             (ADC_CLOCK/384)
+
+// Decimation amount - ratio
+#define DECIMATION_RATIO        64
+
+// Size of LPF output per Buffer
+//  (BUFFERSYS_SIZE/DECIMATION_RATIO)
+#define LPF_OUTPUTS_SIZE        8
+
+// Decimation Rate (35156/64 = 549 SPS)
+#define DECIMATED_RATE          (SAMPLE_RATE/DECIMATION_RATIO)
+
+// Scale Factor rate of FIR filter result to output sample
+// 32 bit sample * 16 bit coefficient * 511 scaled down to 32 bits
+//  32+16+9 bits = 57. Reduce by 25
+#define FIR_SHIFT_FACTOR        25
+
+// First LO in the Softrock (10.125MHz)
+#define FIRST_LO                (ADC_CLOCK*3/4)
+
+// Test NCO freq - approx 15kHz
+#define TEST_NCO_FREQ           (15600)
+
+// Size of each sample set in bytes - size of TDataSample
+#define SAMPLE_SET_SIZE         (8)
+
+// QRSS System UDP Port
+#define QRSS_UDP_PORT           6595
+
+// comments
+
+// Macros
+
+#endif
+
+//---------------------------------------------------------------------------
+//  END
+//---------------------------------------------------------------------------
+
diff -r 000000000000 -r 82ff15078322 gps.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gps.cpp	Wed Jan 25 20:32:53 2012 +0000
@@ -0,0 +1,430 @@
+/*---------------------------------------------------------------------------
+
+    QRSS Receiver Application
+        
+    by Clayton ZL3TKA/VK1TKA
+    clayton@isnotcrazy.com
+
+    GPS Module
+
+---------------------------------------------------------------------------*/
+// include files
+
+#include "gps.h"
+#include "comms.h"
+
+// Definitions
+
+#define GPS_DEBUG   0
+
+// comments
+
+// Macros
+
+// Local Data
+
+// Global Data
+TGPSController GPSModule;
+
+
+// Function Prototypes
+
+//---------------------------------------------------------------------------
+//  TGPSController Class Methods
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+//
+//  Constructor
+//
+TGPSController::TGPSController() :
+        PPSInput( p30 ),
+        GPSPort( p28, p27 ),
+        GPSUpLED( LED3 ),
+        PPSEvent( p30 ),
+        bPulsed( false ),
+        uiPPSCapture( 0 ),
+        uiLOscCapture( 0 )
+{
+    // clear current and last line
+    szCurrentLine[0] = 0;
+    szLastLine[0] = 0;
+    bNewLine = false;
+}
+
+//---------------------------------------------------------------------------
+//
+//  Initialise routine
+//
+void TGPSController::Init()
+{
+    // Set up GPS port
+    GPSPort.baud( 4800 );
+
+    // capture 1PPS event    
+    PPSEvent.rise( this, &TGPSController::PPSPulse );
+
+    // Start timeout timer
+    GPSMsgTimeout.start();
+    GPSPulseTimeout.start();
+
+    // Set up timer hardware
+    LPC_PINCON->PINSEL0 |=  ( (0x3<<8) | (0x3<<10) );   // enable CAP2.0, CAP2.1
+    LPC_SC->PCONP |= 1 << 22;   // power up TIMER2 (PCONP[22])
+    LPC_SC->PCLKSEL1 &= ~(0x3<<12);
+    LPC_SC->PCLKSEL1 |=  (0x1<<12); // Timer2 PCLK = CCLK
+    LPC_TIM2->TCR = 0x2;        // reset timer
+    LPC_TIM2->CTCR = 0x0;       // timer mode
+    LPC_TIM2->PR = 0;           // no prescale
+    LPC_TIM2->MCR = 0x0;        // no match
+    LPC_TIM2->CCR = (1<<0) | (1<<3);    // Capture rising edges on both CAP2.0 & CAP2.1
+    LPC_TIM2->TCR = 1;          // start the timer
+}
+
+//---------------------------------------------------------------------------
+//
+//  Poll routine
+//
+void TGPSController::Poll()
+{
+    // Test for a 1PPS pulse
+    if ( bPulsed )
+    {   // 1PPS from the GPS unit
+        bPulsed = false;
+        GPSPulseTimeout.reset();
+
+        // flush out any old serial data
+        while ( GPSPort.readable() )
+            GPSPort.getc();
+        #if GPS_DEBUG>2
+         printf( "***1PPS***\r\n" );
+        #endif
+        // Record capture data to comms module
+        Comms.RecordPPSTimestamps( uiPPSCapture, uiLOscCapture, GPSRecord );
+    }
+
+    // Test for GPS serial port data
+    while ( GPSPort.readable() )
+    {
+        char cNextChar = GPSPort.getc();
+        #if GPS_DEBUG>3
+          printf( "%c", cNextChar );
+        #endif                            
+        if ( ParseData(cNextChar) )
+        {   // have a completed GPS sentence
+            GPSMsgTimeout.reset();
+            // analysis the sentence data
+            int iStatus = ProcessGPSData();
+            if ( iStatus==0 )
+            {   // good sentence
+                #if GPS_DEBUG>0
+                 printf( "Time: %d\r\n",   GPSRecord.iGPSTimeSeconds );
+                 printf( "Lat: %d\r\n",    GPSRecord.iGPSLatMicroDegrees );
+                 printf( "Long: %d\r\n",   GPSRecord.iGPSLongMicroDegrees );
+                 printf( "Alt: %d\r\n",    GPSRecord.iGPSAltitudeMeters );
+                 printf( "Sats: %d\r\n",   GPSRecord.iGPSSatellites );
+                 printf( "Qual: %d\r\n",   GPSRecord.iGPSQuality );
+                #endif
+            }
+        }
+    }
+
+    // Test for GPS timeout (no data)
+    if ( GPSMsgTimeout.read_ms()>GPS_MSGTIMEOUT )
+    {   // No GPS messages for a period
+        #if GPS_DEBUG>1
+          printf( "GPS Timeout - setting to offline\r\n" );
+        #endif                            
+        GPSRecord.iGPSQuality = 0;      // set quality to 0 - invalid data
+        GPSMsgTimeout.reset();
+        // Record invalid GPS status to comms module
+        Comms.RecordPPSTimestamps( 0, 0, GPSRecord );
+    }
+
+    // Test for GPS timeout (no 1PPS)
+    if ( GPSPulseTimeout.read_ms()>GPS_PULSETIMEOUT )
+    {   // No GPS pulse for a period
+        // we just forward data to Comms module with invalid capture data
+        Comms.RecordPPSTimestamps( 0, 0, GPSRecord );
+        GPSPulseTimeout.reset();
+    }
+
+}
+
+//---------------------------------------------------------------------------
+//
+//  Parse data from the GPS
+//      Return true if a completed valid sentence is received
+//
+#define EXPECT_CHAR(CC)     if (cChr==CC)iParseState++; else iParseState=0;ResetNumber()
+#define PARSE_NUMBER(NN)    if(cChr==','){NN=ParseNum;ResetNumber();iParseState++;break;}if (!ParseNumber(cChr))iParseState=0
+#define PARSE_CHARACTER(CH) if(cChr==','){CH=cCharacter;ResetNumber();iParseState++;break;}cCharacter=cChr
+//
+bool TGPSController::ParseData( char cChr )
+{
+    ucChecksum ^= cChr;
+    switch ( iParseState )
+    {
+      case 0:
+        if ( cChr=='$' )
+            iParseState++;
+        ucChecksum = 0;            
+        break;
+      case 1:       EXPECT_CHAR('G');               break;
+      case 2:       EXPECT_CHAR('P');               break;
+      case 3:       EXPECT_CHAR('G');               break;
+      case 4:       EXPECT_CHAR('G');               break;
+      case 5:       EXPECT_CHAR('A');               break;
+      case 6:       EXPECT_CHAR(',');               break;
+      case 7:       PARSE_NUMBER( GPSTime );        break;
+      case 8:       PARSE_NUMBER( GPSLatitude );    break;
+      case 9:       PARSE_CHARACTER( GPSLatNS );    break;
+      case 10:      PARSE_NUMBER( GPSLongitude );   break;
+      case 11:      PARSE_CHARACTER( GPSLongEW );   break;
+      case 12:      PARSE_NUMBER( GPSQuality );     break;
+      case 13:      PARSE_NUMBER( GPSSatellites );  break;
+      case 14:      PARSE_NUMBER( GPSDOP );         break;
+      case 15:      PARSE_NUMBER( GPSAltitude );    break;
+      case 16:      PARSE_CHARACTER( GPSAltType );  break;
+      case 17:      PARSE_NUMBER( GPSHeight );      break;
+      case 18:      PARSE_CHARACTER( GPSHeightType ); break;
+      case 19:      EXPECT_CHAR(',');   
+                    ucFinalChecksum = ucChecksum; 
+                    break;
+      case 20:      EXPECT_CHAR('*');               break;
+      case 21:      iParseState++;
+                    if ( (cChr>='0') && (cChr<='9') )
+                        ucMsgChecksum = (cChr-'0') << 4; 
+                    else if ( (cChr>='A') && (cChr<='F') )
+                        ucMsgChecksum = (cChr-'A'+10) << 4; 
+                    else
+                        iParseState = 0;
+                    break;
+      case 22:      iParseState++;
+                    if ( (cChr>='0') && (cChr<='9') )
+                        ucMsgChecksum |= (cChr-'0');
+                    else if ( (cChr>='A') && (cChr<='F') )
+                        ucMsgChecksum |= (cChr-'A'+10);
+                    else
+                        iParseState = 0;
+                    break;
+      case 23:      // don't care about char (should be a CR)
+                    // just check the results
+                    if ( ucMsgChecksum==ucFinalChecksum )
+                    {   // Checksum okay
+                        // reset
+                        iParseState = 0;
+                        // return valid message
+                        return true;
+                    }
+                    #if GPS_DEBUG>0
+                      else
+                          printf( "!GPS Check failed - got %02X wanted %02X\r\n", (int)ucMsgChecksum, (int)ucFinalChecksum );
+                    #endif                            
+                    // reset
+                    iParseState = 0;
+                    break;
+    }
+
+    #if GPS_DEBUG>2
+      // report parser state
+      printf( ":%d:", iParseState );
+    #endif                            
+
+    // GPS sentence note yet completed
+    return false;
+}
+
+//---------------------------------------------------------------------------
+//
+//  Parse a number character by character
+//      If character is invalid, returns false
+//
+bool TGPSController::ParseNumber( char cChar )
+{
+    // process digits
+    if ( (cChar>='0') && (cChar<='9') )
+    {
+        ParseNum.uiNumber = (ParseNum.uiNumber*10) + (cChar-'0');
+        ParseNum.iNumberLen++;
+        if ( ParseNum.iNumberDecimals>=0 )
+            ParseNum.iNumberDecimals++; 
+        return true;
+    }
+    if ( cChar=='.' )
+    {
+        if ( ParseNum.iNumberDecimals>=0 )
+            return false;   // a second decimal point!
+        ParseNum.iNumberDecimals = 0;
+        return true;
+    }
+    if ( cChar=='-' )
+    {
+        if ( ParseNum.iNumberLen>0 )
+            return false;   // '-' must be the first character
+        ParseNum.iNumberSign = -1;
+        return true;
+    }
+    // otherwise an invalid character
+    return false;
+}
+
+//---------------------------------------------------------------------------
+//
+//  Reset the number parser
+//
+void TGPSController::ResetNumber( )
+{
+    ParseNum.uiNumber = 0;
+    ParseNum.iNumberLen = 0;
+    ParseNum.iNumberSign = 1;
+    ParseNum.iNumberDecimals = -1;
+    cCharacter = 0;
+}
+
+
+//---------------------------------------------------------------------------
+//
+//  Process the data from the GPS message
+//      Returns 0 if all data is good, or an error code
+//
+int TGPSController::ProcessGPSData( )
+{
+    // check Quality
+    if ( GPSQuality.iNumberLen<1 )          return 10;
+    if ( GPSQuality.iNumberDecimals!=-1 )   return 11;
+    if ( GPSQuality.iNumberSign!=1 )        return 12;
+    // check Satellites
+    if ( GPSSatellites.iNumberLen<1 )       return 20;
+    if ( GPSSatellites.iNumberDecimals!=-1 ) return 21;
+    if ( GPSSatellites.iNumberSign!=1 )     return 22;
+    // Store sats and quality parameters
+    GPSRecord.iGPSSatellites = GPSSatellites.uiNumber;
+    GPSRecord.iGPSQuality = GPSQuality.uiNumber;
+    // Check quality level
+    if ( GPSQuality.uiNumber<1 )            return 100;     // no fix
+    // check Time
+    if ( GPSTime.iNumberLen<6 )            return 30;
+    if ( GPSTime.iNumberSign!=1 )           return 32;
+    // check Latitude
+    if ( GPSLatitude.iNumberLen!=7 )        return 40;
+    if ( GPSLatitude.iNumberDecimals!=3 )   return 41;
+    if ( GPSLatitude.iNumberSign!=1 )       return 42;
+    if ( (GPSLatNS!='N') && (GPSLatNS!='S') ) return 43;
+    // check Longitude
+    if ( GPSLongitude.iNumberLen!=8 )        return 50;
+    if ( GPSLongitude.iNumberDecimals!=3 )   return 51;
+    if ( GPSLongitude.iNumberSign!=1 )       return 52;
+    if ( (GPSLongEW!='E') && (GPSLongEW!='W') ) return 53;
+    // check Altitude
+    if ( GPSAltitude.iNumberLen<1 )         return 60;
+    // Don't care about DOPs and Height and Types
+    // Translate & Store parameters
+
+    // discard fractions of seconds
+    while ( (GPSTime.iNumberDecimals--)>0 )
+        GPSTime.uiNumber /= 10;
+
+    int32_t iHours = GPSTime.uiNumber/10000;
+    int32_t iMins = (GPSTime.uiNumber/100)%100;
+    int32_t iSecs = GPSTime.uiNumber%100;
+    GPSRecord.iGPSTimeSeconds = iSecs + (60*iMins) + (3600*iHours);
+
+    int32_t iDegrees = GPSLatitude.uiNumber / 100000;
+    int32_t iMilliMinutes = GPSLatitude.uiNumber % 100000;
+    GPSRecord.iGPSLatMicroDegrees = (iMilliMinutes * 100 / 6) + (iDegrees*1000000);
+    if ( GPSLatNS=='S' )
+        GPSRecord.iGPSLatMicroDegrees = -GPSRecord.iGPSLatMicroDegrees;
+
+    iDegrees = GPSLongitude.uiNumber / 100000;
+    iMilliMinutes = GPSLongitude.uiNumber % 100000;
+    GPSRecord.iGPSLongMicroDegrees = (iMilliMinutes * 100 / 6) + (iDegrees*1000000);
+    if ( GPSLongEW=='W' )
+        GPSRecord.iGPSLatMicroDegrees = -GPSRecord.iGPSLatMicroDegrees;
+
+    GPSRecord.iGPSAltitudeMeters = GPSAltitude.uiNumber * GPSAltitude.iNumberSign;
+    while ( (GPSAltitude.iNumberDecimals--)>0 )
+        GPSRecord.iGPSAltitudeMeters /= 10;
+    
+    return 0;
+}
+
+//---------------------------------------------------------------------------
+//
+//  PPS Event routine
+//
+void TGPSController::PPSPulse()
+{
+    // indicate we have pulsed
+    bPulsed = true;
+    
+    // capture timer capture registers
+    //  1PPP = CAP2.0
+    //  LOsc (/4096) = CAP2.1
+    uiPPSCapture = LPC_TIM2->CR0;
+    uiLOscCapture = LPC_TIM2->CR1;
+
+}
+
+/*
+GPS Messages:
+
+GGA - essential fix data which provide 3D location and accuracy data.
+
+ $GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
+
+Where:
+     GGA          Global Positioning System Fix Data
+     123519       Fix taken at 12:35:19 UTC
+     4807.038,N   Latitude 48 deg 07.038' N
+     01131.000,E  Longitude 11 deg 31.000' E
+     1            Fix quality: 0 = invalid
+                               1 = GPS fix (SPS)
+                               2 = DGPS fix
+                               3 = PPS fix
+                   4 = Real Time Kinematic
+                   5 = Float RTK
+                               6 = estimated (dead reckoning) (2.3 feature)
+                   7 = Manual input mode
+                   8 = Simulation mode
+     08           Number of satellites being tracked
+     0.9          Horizontal dilution of position
+     545.4,M      Altitude, Meters, above mean sea level
+     46.9,M       Height of geoid (mean sea level) above WGS84
+                      ellipsoid
+     (empty field) time in seconds since last DGPS update
+     (empty field) DGPS station ID number
+     *47          the checksum data, always begins with *
+
+
+VTG - Velocity made good. The gps receiver may use the LC prefix instead of GP if it is emulating Loran output.
+
+  $GPVTG,054.7,T,034.4,M,005.5,N,010.2,K*48
+
+where:
+        VTG          Track made good and ground speed
+        054.7,T      True track made good (degrees)
+        034.4,M      Magnetic track made good
+        005.5,N      Ground speed, knots
+        010.2,K      Ground speed, Kilometers per hour
+        *48          Checksum
+        
+        
+
+$GPGGA,,,,,,0,05,,,,,,,*63
+$GPGGA,,,,,,0,02,,,,,,,*64
+$GPGGA,,,,,,0,03,,,,,,,*65
+$GPGGA,120609.46,3515.405,S,14904.873,E,0,04,2.24,718,M,14,M,,*42
+ $GPVTG,000.0,T,346.7,M,0.000,N,0.000,K*48
+ $GPGGA,120610.46,3515.405,S,14904.873,E,1,04,2.24,718,M,14,M,,*4B
+ $GPVTG,000.0,T,346.7,M,0.000,N,0.000,K*48
+ $GPGGA,120611.46,3515.405,S,14904.873,E,1,04,2.24,718,M,14,M,,*4A
+ $GPVTG,000.0,T,346.7,M,0.000,N,0.000,K*48
+ $GPGGA,120612.46,3515.405,S,14904.873,E,1,04,2.24,718,M,14,M,,*49
+
+*/
+
+//---------------------------------------------------------------------------
+//  END
+//---------------------------------------------------------------------------
+
diff -r 000000000000 -r 82ff15078322 gps.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gps.h	Wed Jan 25 20:32:53 2012 +0000
@@ -0,0 +1,171 @@
+/*---------------------------------------------------------------------------
+
+    QRSS Receiver Application
+        
+    by Clayton ZL3TKA/VK1TKA
+    clayton@isnotcrazy.com
+
+    Header File for GPS Module
+
+---------------------------------------------------------------------------*/
+#ifndef _GPS_H
+#define _GPS_H
+
+#include "mbed.h"
+
+// Definitions
+
+#define GPS_FIELDLEN        20
+#define GPS_LINELENGTH      200
+#define GPS_MSGTIMEOUT      3000        // GPS message timeout (mSecs)
+#define GPS_PULSETIMEOUT    1500        // GPS pulse timeout (mSecs)
+
+// comments
+
+// Macros
+
+//
+// Classes
+//
+
+//---------------------------------------------------------------------------
+//
+//  GPS Module Class
+//
+class TGPSController
+{
+    // create/destroy
+    public:
+        TGPSController();
+        ~TGPSController() {}
+
+    // public type - GPS data
+    public:
+        typedef struct _gpsdata
+        {
+            int32_t     iGPSQuality;
+            int32_t     iGPSSatellites;
+            int32_t     iGPSTimeSeconds;
+            int32_t     iGPSLatMicroDegrees;
+            int32_t     iGPSLongMicroDegrees;
+            int32_t     iGPSAltitudeMeters;
+        } TGPSData;
+
+    // local type - for parsing message numbers
+    private:
+        typedef struct _parsenumber
+        {
+            uint32_t    uiNumber;
+            int         iNumberLen;
+            int         iNumberSign;
+            int         iNumberDecimals;
+        } TParsedNum;
+
+    // API
+    public:
+        // Initi8alise routine
+        void Init();
+
+        // Processing routine
+        void Poll();
+
+        // Return the last line from the GPS
+        const char * LastLine()
+            { return szLastLine; }
+        
+        // indicate a new last line has been received from the GPS unit
+        //  Self resetting
+        bool NewLine()
+            {
+                bool bRet = bNewLine;
+                bNewLine = false;
+                return bRet;
+            }
+
+        // Get GPS Data
+        //  Returns status value (0=offline)
+        int GPSData( TGPSData &GPSDat )
+            { GPSDat = GPSRecord;
+              return GPSDat.iGPSQuality; }
+
+    // Private methods
+    private:
+        // callback on 1PPS rising edge
+        void PPSPulse();
+
+        // Parse a number
+        bool ParseNumber( char cChr );
+        void ResetNumber();
+
+        // Parse data from the GPS
+        //  Return true if a completed valid sentence is received
+        bool ParseData( char cChr );
+
+        //  Process the data from the GPS message
+        //      Returns 0 if all data is good, or an error code
+        //      Call after a valid ParseData has occurred
+        int ProcessGPSData();
+
+    // data
+    private:
+        // 1PPS pin
+        DigitalIn   PPSInput;
+
+        // GPS Serial Port
+        Serial      GPSPort;
+        
+        // GPS Status LED
+        DigitalOut  GPSUpLED;
+
+        // Interrupt on 1PPS pulse
+        InterruptIn PPSEvent;        
+        
+        // 1PPS flag and captured timer registers
+        bool        bPulsed;
+        uint32_t    uiPPSCapture;
+        uint32_t    uiLOscCapture;
+
+        // GPS data timeout timer
+        Timer       GPSMsgTimeout;
+        Timer       GPSPulseTimeout;
+
+        // Parsing data and resulting values
+        int         iParseState;
+        TParsedNum  ParseNum;
+        char        cCharacter;
+        
+        // last line variables
+        char        szCurrentLine[GPS_LINELENGTH+1];
+        char        szLastLine[GPS_LINELENGTH+1];
+        bool        bNewLine;
+
+        // GPS message data - raw data from message
+        TParsedNum  GPSTime;
+        TParsedNum  GPSLatitude;
+        char        GPSLatNS;
+        TParsedNum  GPSLongitude;
+        char        GPSLongEW;
+        TParsedNum  GPSQuality;
+        TParsedNum  GPSSatellites;
+        TParsedNum  GPSDOP;
+        TParsedNum  GPSAltitude;
+        char        GPSAltType;
+        TParsedNum  GPSHeight;
+        char        GPSHeightType;
+        uint8_t     ucMsgChecksum;
+        uint8_t     ucFinalChecksum;
+        uint8_t     ucChecksum;
+
+        // Final GPS info (validated)        
+        TGPSData    GPSRecord;
+};
+
+// declare the GPS module
+extern TGPSController GPSModule;
+
+#endif
+
+//---------------------------------------------------------------------------
+//  END
+//---------------------------------------------------------------------------
+
diff -r 000000000000 -r 82ff15078322 main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Jan 25 20:32:53 2012 +0000
@@ -0,0 +1,212 @@
+/*---------------------------------------------------------------------------
+
+    QRSS Receiver Application
+        
+    by Clayton ZL3TKA/VK1TKA
+    clayton@isnotcrazy.com
+
+    main function
+
+---------------------------------------------------------------------------*/
+// include files
+
+#include "mbed.h"
+#include "global.h"
+#include "EthernetNetIf.h"
+#include "UDPSocket.h"
+#include "dnsresolve.h"
+#include "gps.h"
+#include "BufferSys.h"
+#include "I2S_Rx.h"
+#include "DSP.h"
+#include "comms.h"
+
+// Definitions
+
+// Macros
+
+// Local Data
+
+// Global Data
+
+// Serial port interface to the PC
+Serial pc( USBTX, USBRX );
+
+// LEDs
+DigitalOut OnLED( LED1 );
+
+// IO
+DigitalOut TestOscillator( p21 );
+#define TESTOSC_ON      0
+#define TESTOSC_OFF     1
+
+// The Buffer pool for audio data
+TBufferPool     BufferPool;
+
+// The array of buffers for the pool
+TBufferData BufferDataArray[NUM_OF_BUFFERS];
+
+// I2S Object
+TI2SReceiver    AudioInput( BufferPool );
+
+// Communications Object
+TCommunications Comms;
+
+
+// Function Prototypes
+
+//---------------------------------------------------------------------------
+//  MAIN
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+//
+//  Main start routine
+//      Just starts everything running
+//
+int main()
+{
+    TDSPProcessor   ADCBuffer;
+    uint32_t        uiCurrentTestmode = 0x1234;
+
+    // Set up IOs
+    OnLED = 1;
+    TestOscillator = TESTOSC_OFF;
+
+    // Set up PC port
+    pc.baud( 38400 );
+
+    // Report
+    printf( "\r\n\r\nQRSS_Rx Application running\r\n" );
+    printf( "Built " __DATE__ "   " __TIME__ "\r\n" );
+    printf( "System Core Clock = %ld\r\n", SystemCoreClock );
+
+    // Add array of buffers to the pool
+    pc.printf ("Setting up buffer pool with %d buffer of %d samples ...", NUM_OF_BUFFERS, BUFFERSYS_SIZE );
+    BufferPool.AddNewMsgsToPool( BufferDataArray, NUM_OF_BUFFERS );
+    printf (" OK\r\n");
+
+    // Set up audio receiver
+    pc.printf ("Initialise the I2S Receiver ...");
+    AudioInput.Init();
+    printf (" OK\r\n");
+
+    // Set up GPS
+    pc.printf ("Initialise GPS ...");
+    GPSModule.Init();
+    printf (" OK\r\n");
+
+    // Set up communications
+    pc.printf ("Initialise Communications ...");
+    Comms.Init();
+    Comms.SetServer( "192.168.0.15" );      // default QRSS Server Address (could be a DNS name)
+    printf (" OK\r\n");
+
+    ADCBuffer.NCOFrequency( TEST_NCO_FREQ );
+
+    // echo GPS data out the PC port
+    while(1) 
+    {
+        // Poll the sub-systems
+        Net::poll();
+        GPSModule.Poll();
+        Comms.Poll();
+
+        // Handle Comms Mode
+        if ( Comms.Running() )
+        {   // online comms
+            if ( !AudioInput.Running() )
+            {
+                printf( "Starting Processing\r\n" );
+                ADCBuffer.NCOPhaseInc( Comms.NCOPhaseInc() );
+                AudioInput.Start();
+            }
+            // process and output any received samples
+            if ( !AudioInput.Empty() )
+            {
+                // ADC buffer will be automatically released
+                AudioInput.Read( ADCBuffer );
+                // Mix the LO
+                ADCBuffer.MixLO();
+                // Filter the result
+                ADCBuffer.LPF();
+                // Output the data to the comms module
+                for ( int ii=0; ii<8; ii++ )
+                    Comms.SendSamples( ADCBuffer.Timestamp(), ADCBuffer.FilteredOutput(ii) );
+            }
+        }
+        else
+        {   // offline comms
+            if ( AudioInput.Running() )
+            {
+                AudioInput.Stop();
+                printf( "Stopping Processing\r\n" );
+            }
+            if ( !AudioInput.Empty() )
+            {   // discard messages
+                AudioInput.Read( ADCBuffer );
+                ADCBuffer.Release();
+            }
+        }
+
+        // Handle Test Modes
+        if ( Comms.TestMode()!=uiCurrentTestmode )
+        {
+            uiCurrentTestmode = Comms.TestMode();
+            if ( uiCurrentTestmode!=0 )
+            {   // enable test Osc
+                printf( "Turn ON Test Osc\r\n" );
+                TestOscillator = TESTOSC_ON;
+            }
+            else
+            {   // disable test Osc
+                printf( "Turn OFF Test Osc\r\n" );
+                TestOscillator = TESTOSC_OFF;
+            }
+        }
+
+        // Process Keystrokes - debug only
+        if( pc.readable() )
+        {
+            int iCharIn = pc.getc();
+            switch ( iCharIn )
+            {
+              case'1':
+                printf( "Turn on Test Osc\r\n" );
+                TestOscillator = TESTOSC_ON;
+                break;
+              case '2':
+                printf( "Turn off Test Osc\r\n" );
+                TestOscillator = TESTOSC_OFF;
+                break;
+              case '7':
+                printf( "AudioInput Start\r\n" );
+                AudioInput.Start();
+                break;
+              case '8':
+                printf( "AudioInput Stop\r\n" );
+                AudioInput.Stop();
+                break;
+              case '9':
+                AudioInput.Report();
+                break;
+              case 'x':
+                ADCBuffer.NCOFrequency( 15000 );
+                break;
+              case 'y':
+                ADCBuffer.NCOFrequency( -15000 );
+                break;
+              case 'z':
+                ADCBuffer.NCOFrequency( 15600 );
+                break;
+            }
+        }
+    }
+        
+}
+
+//---------------------------------------------------------------------------
+//  END
+//---------------------------------------------------------------------------
+
+
diff -r 000000000000 -r 82ff15078322 mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed Jan 25 20:32:53 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/63bcd7ba4912