//
//  Copyright © 2002, RESON Inc. All Rights Reserved.
//
//  No part of this file may be reproduced or transmitted in any form or by
//  any means, electronic or mechanical, including photocopy, recording, or
//  information storage or retrieval system, without permission in writing
//  from RESON Inc.
//
//  Filename:   7kRemoteControl.cpp
//
//  Project:    6046
//
//  Author(s):  W. Arcus
//
//  Purpose:    
//
//  Notes:      
//

#include "StdAfx.h"
#include "7kRemoteControl.h"

//////////////////////////////////////////////////////////////////////
// Internal module definitions.

#pragma pack( push, REMOTECONTROL7K_CPP_PACK, 1 )

typedef struct tagBOTTOMDETECTFILTERPARAMS
{
    float           m_fMinRange;
    float           m_fMaxRange;
    float           m_fMinDepth;
    float           m_fMaxDepth;
}
BOTTOMDETECTFILTERPARAMS;

typedef struct tagPROJECTORSTEERINGPARS
{
    float           m_fSteeringAngleX;
    float           m_fSteeringAngleY;
}
PROJECTORSTEERINGPARS;

typedef struct tagPERSISTENTFEEDHEADER
{
    unsigned long   m_ulIPAddress;
    unsigned short  m_unPort;
    unsigned short  m_unProtocolFlag;
    unsigned long   m_ulNumberOfRecords;
}
PERSISTENTFEEDHEADER;

#pragma pack( pop, REMOTECONTROL7K_CPP_PACK )


//////////////////////////////////////////////////////////////////////
// C7kRemoteControl class implementation.

using N7kSonarMessages::REMOTECONTROLRTH;

const unsigned long C7kRemoteControl::m_ulRecordType = 7500UL;

C7kRemoteControl::C7kRemoteControl( void )
                 :CGeneric7kRecordEncoder<REMOTECONTROLRTH>()
{
    m_ulTicketNumber = 0UL;
    memset( &m_sClientId, 0x00, sizeof( GUID ) );
}

C7kRemoteControl::~C7kRemoteControl( void )
{
    m_ulTicketNumber = 0UL;
}

bool C7kRemoteControl::SetClientId( const GUID &rsClientId )
{
    m_sClientId = rsClientId;

    return true;
}

bool C7kRemoteControl::VerifySystemResponse( void )
{
    return Encode( commandIdVerifySystemResponse );
}

bool C7kRemoteControl::PingEnable(  const bool              &rbEnable,
                                    const unsigned long     &rulDeviceId,
                                    const unsigned short    &runEnumerator )
{
    return Encode( (( rbEnable ) ? commandIdStartPinging : commandIdStopPinging ), NULL, 0, false, rulDeviceId, runEnumerator );
}

bool C7kRemoteControl::Shutdown( void )
{
    return Encode( commandIdShutdown );
}

bool C7kRemoteControl::Reboot( void )
{
    return Encode( commandIdReboot );
}

bool C7kRemoteControl::Calibrate( void )
{
    return Encode( commandIdCalibrate );
}

bool C7kRemoteControl::Range(   const float             &rfRangeInMeters,
                                const unsigned long     &rulDeviceId,
                                const unsigned short    &runEnumerator )
{
    return Encode(  commandIdRange,
                        reinterpret_cast<const BYTE *>( &rfRangeInMeters ),
                            sizeof( float ),
                                false,
                                    rulDeviceId,
                                        runEnumerator );
}

bool C7kRemoteControl::MaxPingRate( const float             &rfMaxPingsPerSecond,
                                    const unsigned long     &rulDeviceId,
                                    const unsigned short    &runEnumerator )
{
    return Encode(  commandIdMaxPingRate,
                        reinterpret_cast<const BYTE *>( &rfMaxPingsPerSecond ),
                            sizeof( float ),
                                false,
                                    rulDeviceId,
                                        runEnumerator );
}

bool C7kRemoteControl::TransmitPower(   const float             &rfdBReOneMicroPascal,
                                        const unsigned long     &rulDeviceId,
                                        const unsigned short    &runEnumerator )
{
    return Encode(  commandIdTransmitPower,
                        reinterpret_cast<const BYTE *>( &rfdBReOneMicroPascal ),
                            sizeof( float ),
                                false,
                                    rulDeviceId,
                                        runEnumerator );
}

bool C7kRemoteControl::PulseWidth(  const float             &rfTxPulseWidthInSeconds,
                                    const unsigned long     &rulDeviceId,
                                    const unsigned short    &runEnumerator )
{
    return Encode(  commandIdTransmitPulseWidth,
                        reinterpret_cast<const BYTE *>( &rfTxPulseWidthInSeconds ),
                            sizeof( float ),
                                false,
                                    rulDeviceId,
                                        runEnumerator );
}

bool C7kRemoteControl::PulseType(   const unsigned long     &rulPulseType,
                                    const unsigned long     &rulDeviceId,
                                    const unsigned short    &runEnumerator )
{
    return Encode(  commandIdTransmitPulseType,
                        reinterpret_cast<const BYTE *>( &rulPulseType ),
                            sizeof( unsigned long ),
                                false,
                                    rulDeviceId,
                                        runEnumerator );
}

bool C7kRemoteControl::ReceiverGain(    const float             &rfGainIndB,
                                        const unsigned long     &rulDeviceId,
                                        const unsigned short    &runEnumerator )
{
    return Encode(  commandIdReceiverGain,
                        reinterpret_cast<const BYTE *>( &rfGainIndB ),
                            sizeof( float ),
                                false,
                                    rulDeviceId,
                                        runEnumerator );
}

bool C7kRemoteControl::BottomDetectMethod(  const unsigned long     &rulBottomDetectMask,
                                            const unsigned long     &rulDeviceId,
                                            const unsigned short    &runEnumerator )
{
    return Encode(  commandIdBottomDetectionMethodMask,
                        reinterpret_cast<const BYTE *>( &rulBottomDetectMask ),
                            sizeof( unsigned long ),
                                false,
                                    rulDeviceId,
                                        runEnumerator );
}

bool C7kRemoteControl::BottomDetectionFilterInfo(   const float          &rfMinRange,
                                                    const float          &rfMaxRange,
                                                    const float          &rfMinDepth,
                                                    const float          &rfMaxDepth,
                                                    const unsigned long  &rulDeviceId,
                                                    const unsigned short &runEnumerator )
{
    BOTTOMDETECTFILTERPARAMS sParams = { rfMinRange, rfMaxRange, rfMinDepth, rfMaxDepth };

    return Encode(  commandIdBottomDetectionFilterInfo,
                        reinterpret_cast<const BYTE *>( &sParams ),
                            sizeof( BOTTOMDETECTFILTERPARAMS ),
                                false,
                                    rulDeviceId,
                                        runEnumerator );
}

bool C7kRemoteControl::ProjectorSelection(  const unsigned long     &rulProjectorMagicNumber,
                                            const unsigned long     &rulDeviceId,
                                            const unsigned short    &runEnumerator )
{
    return Encode(  commandIdProjectorSelection,
                        reinterpret_cast<const BYTE *>( &rulProjectorMagicNumber ),
                            sizeof( unsigned long ),
                                false,
                                    rulDeviceId,
                                        runEnumerator );
}

bool C7kRemoteControl::ProjectorStabilization(  const unsigned long     &rulProjectorMask,
                                                const unsigned long     &rulDeviceId,
                                                const unsigned short    &runEnumerator )
{
    return Encode(  commandIdProjectorStabilization,
                        reinterpret_cast<const BYTE *>( &rulProjectorMask ),
                            sizeof( unsigned long ),
                                false,
                                    rulDeviceId,
                                        runEnumerator );
}

bool C7kRemoteControl::TransmitterStabilization(    const unsigned long     &rulStabalizationMask,
                                                    const unsigned long     &rulDeviceId,
                                                    const unsigned short    &runEnumerator )
{
    return Encode(  commandIdTransmitterStabilization,
                        reinterpret_cast<const BYTE *>( &rulStabalizationMask ),
                            sizeof( unsigned long ),
                                false,
                                    rulDeviceId,
                                        runEnumerator );
}

bool C7kRemoteControl::AutoRange( const unsigned long &rulAutoRangeMask )
{
    return Encode(  commandIdAutoRange,
                        reinterpret_cast<const BYTE *>( &rulAutoRangeMask ),
                            sizeof( unsigned long ) );
}

bool C7kRemoteControl::SelectHydroPhone( const unsigned long &rulHydroPhoneMagicNumber )
{
    return Encode(  commandIdHydrophoneSelection,
                        reinterpret_cast<const BYTE *>( &rulHydroPhoneMagicNumber ),
                            sizeof( unsigned long ) );
}

bool C7kRemoteControl::ProjectorSteering( const float &rfSteeringAngleX,
                                          const float &rfSteeringAngleY )
{
    PROJECTORSTEERINGPARS sSteeringPars = { rfSteeringAngleX, rfSteeringAngleY };

    return Encode(  commandIdProjectorSteering,
                        reinterpret_cast<const BYTE *>( &sSteeringPars ),
                            sizeof( PROJECTORSTEERINGPARS ) );
}

bool C7kRemoteControl::ReceiverGainType( const unsigned long &rulReceiverGainType )
{
    return Encode( commandIdReceiverGainType,
                        reinterpret_cast<const BYTE *>( &rulReceiverGainType ),
                            sizeof( unsigned long ) );
}

bool C7kRemoteControl::TVGCoefficients( void )
{
#pragma CompileMessage_m( "TVG COEFFICIENTS ARE TBD." )

    // TBD. Just return a fail code for now.

    //return Encode( commandIdTVGCoefficients,
    //                    reinterpret_cast<const BYTE *>( &  ),
    //                        sizeof(  ) );

    return false;
}

bool C7kRemoteControl::AutoReceiverGain(    const unsigned long     &rulGainFlag,
                                            const unsigned long     &rulDeviceId,
                                            const unsigned short    &runEnumerator )
{
    return Encode( commandIdAutoReceiverGain,
                        reinterpret_cast<const BYTE *>( &rulGainFlag ),
                            sizeof( unsigned long ),
                                false,
                                    rulDeviceId,
                                        runEnumerator );
}

bool C7kRemoteControl::RequestSingleRecord( const unsigned long   &rulRecordType,
                                            const unsigned long   &rulDeviceId,
                                            const unsigned short  &runEnumerator )
{
    return Encode(  commandIdSingleRecordRequest,
                        reinterpret_cast<const BYTE *>( &rulRecordType ),
                            sizeof( unsigned long ),
                                false,
                                    rulDeviceId,
                                        runEnumerator );
}

bool C7kRemoteControl::VolatileDataFeed(    const unsigned long     &rulNumberOfRecords,
                                            const unsigned long     *paulRecordNumbers,
                                            const unsigned long     &rulDeviceId,
                                            const unsigned short    &runEnumerator )
{
    bool bSuccess = false;

    if ( rulNumberOfRecords == 0UL )
    {
        bSuccess = true;            // Nothing to do.
    }
    else if ( paulRecordNumbers == NULL )
    {
        bSuccess = false;
    }
    else
    {
        bSuccess = Encode(  commandIdVolatileDataFeed,
                                reinterpret_cast<const BYTE *>( paulRecordNumbers ),
                                    sizeof( unsigned long ) * rulNumberOfRecords,
                                        false,
                                            rulDeviceId,
                                                runEnumerator );
    }

    return bSuccess;
}

bool C7kRemoteControl::VolatileDataFeed(    const unsigned long     &rulBeginRecordId,
                                            const unsigned long     &rulEndRecordId,
                                            const unsigned long     &rulDeviceId,
                                            const unsigned short    &runEnumerator )
{
    unsigned long ulRange[] = { rulBeginRecordId, rulEndRecordId };

    return Encode ( commandIdVolatileDataFeedRange,
                        reinterpret_cast<const BYTE *>( &ulRange[ 0 ] ),
                            sizeof( ulRange ),
                                false,
                                    rulDeviceId,
                                        runEnumerator );
}

bool C7kRemoteControl::DisableVolatileDataFeed( const unsigned long     &rulDeviceId,
                                                const unsigned short    &runEnumerator )
{
    return Encode( commandIdStopVolatileDataFeed, NULL, 0UL, false, rulDeviceId, runEnumerator );
}

bool C7kRemoteControl::PersistentDataFeed(  const bool              &rbEnable,
                                            const unsigned long     &rulIPAddress,
                                            const unsigned short    &runPort,
                                            const unsigned short    &runProtocolFlag,
                                            const unsigned long     &rulNumberOfRecords,
                                            const unsigned long     *paulRecordNumbers,
                                            const unsigned long     &rulDeviceId,
                                            const unsigned short    &runEnumerator )
{
    bool bSuccess = false;

    if ( rbEnable )
    {
        if ( rulNumberOfRecords == 0UL )
        {
            bSuccess = true;            // Nothing to do.
        }
        else if ( paulRecordNumbers == NULL )
        {
            bSuccess = false;
        }
        else
        {
            const unsigned long ulDynamicMemorySize = rulNumberOfRecords * sizeof( unsigned long );
            const unsigned long ulTotalMemorySize   = sizeof( PERSISTENTFEEDHEADER ) + ulDynamicMemorySize;

            BYTE *pbyContiguousMemory = NULL;

            __TRY
            {
                pbyContiguousMemory = new BYTE [ ulTotalMemorySize ];
                
                if ( pbyContiguousMemory != NULL )
                {
                    memset( pbyContiguousMemory, 0x00, ulTotalMemorySize );

                    PERSISTENTFEEDHEADER *psHeader = reinterpret_cast<PERSISTENTFEEDHEADER *>( pbyContiguousMemory );

                    psHeader->m_ulIPAddress       = rulIPAddress;
                    psHeader->m_unPort            = runPort;
                    psHeader->m_unProtocolFlag    = runProtocolFlag;
                    psHeader->m_ulNumberOfRecords = rulNumberOfRecords;

                    memcpy( pbyContiguousMemory + sizeof( PERSISTENTFEEDHEADER ), paulRecordNumbers, ulDynamicMemorySize );

                    bSuccess = Encode(  commandIdPersistentDataFeed,
                                            pbyContiguousMemory,
                                                ulTotalMemorySize,
                                                    false,
                                                        rulDeviceId,
                                                            runEnumerator );
                }
            }
            __FINALLY
            {
                if ( pbyContiguousMemory != NULL )
                {
                    delete [] pbyContiguousMemory;
                    pbyContiguousMemory = NULL;
                }
            }
            __ENDFINALLY
        }
    }
    else
    {
        bSuccess = Encode( commandIdStopPersistentDataFeed, NULL, 0UL, false, rulDeviceId, runEnumerator );
    }

    return bSuccess;
}

bool C7kRemoteControl::LoadSystemDefaults( void )
{
    return Encode( commandIdLoadParametersSystem );
}

bool C7kRemoteControl::LoadDeviceDefaults( const unsigned long   &rulDeviceId,
                                           const unsigned short  &runEnumerator )
{
    return Encode( commandIdLoadParametersDevice,
                       NULL,
                           0UL,
                               false,
                                   rulDeviceId,
                                       runEnumerator );
}

unsigned long C7kRemoteControl::RecordType( void )
{
    return m_ulRecordType;
}

///////////////////////////////////////////////////////////////////////////////
// C7kRemoteControl's internal helpers (private).

bool C7kRemoteControl::Encode(  const unsigned long    &rulCommandId,
                                const BYTE             *pbyRecordData,
                                const unsigned long    &rulRecordDataBytes,
                                const bool             &rbUseChecksum,
                                const unsigned long    &rulDeviceId,
                                const unsigned short   &runSystemEnumerator )
{
    bool bSuccess = false;

    try
    {
        REMOTECONTROLRTH sRTH   = { 0 };
        sRTH.m_ulCommandId      = rulCommandId;
        sRTH.m_ulTicket         = m_ulTicketNumber;

        ::memcpy( &(sRTH.m_ucTrackingNumber[ 0 ]), &m_sClientId, sizeof( GUID ) );
            
        // Increment the ticket number but wrap one below the max value for an unsigned long.

        m_ulTicketNumber = ( m_ulTicketNumber % ( ULONG_MAX - 1UL ) ) + 1UL;

        if ( CGeneric7kRecordEncoder<REMOTECONTROLRTH>::Encode( m_ulRecordType, &sRTH, pbyRecordData, rulRecordDataBytes, rbUseChecksum ) )
        {
            // Now adjust the device id and enumerator; 7k Center is addressed w/ Device Id 7000.

            RECORDHEADER7K *psRTH = reinterpret_cast<RECORDHEADER7K *>( static_cast<BYTE *>( *static_cast<CGeneric7kRecordEncoder<REMOTECONTROLRTH> *>( this ) ) );

            psRTH->m_ulDeviceId         = rulDeviceId;
            psRTH->m_unSystemEnumerator = runSystemEnumerator;

            //const unsigned long ulCommand = *reinterpret_cast<unsigned long *>( const_cast<BYTE *>( pbyRecordData ));
            //TRACE( _T( "C7kRemoteControl::Encode(), Cmd: %lu, Ticket: %lu, Rec: %lu\n" ), sRTH.m_ulCommandId, sRTH.m_ulTicket, ulCommand );

            bSuccess = true;
        }
    }
    catch ( ... )
    {
        bSuccess = false;
        TRACE( _T( "C7kRemoteControl::Encode(), unspecified exception caught\n" ) );
    }

    return bSuccess;
}
