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

comms.cpp

Committer:
claytong
Date:
2012-01-25
Revision:
0:82ff15078322

File content as of revision 0:82ff15078322:

/*---------------------------------------------------------------------------

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