//
//  Copyright © 2003, 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:   CircBuffer.cpp
//
//  Project:    6046
//
//  Author(s):  W. Arcus
//
//  Purpose:    Test program to prototype and debug working model of new 6046 MMF
//              to allow large buffer exchange. Uses a circular buffer contrivance.
//
//  Notes:      
//

#include "StdAfx.h"
#include "CircBuffer.h"
#include "MMF6046.h"

#ifdef _DEBUG
#pragma comment( lib, "..\\..\\Components\\NetUtils\\Debug\\NetUtils.lib" )
#else
#pragma comment( lib, "..\\..\\Components\\NetUtils\\Release\\NetUtils.lib" )
#endif

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

///////////////////////////////////////////////////////////////////////////////
// Internal objects and definitions.

CWinApp theApp;

using std::auto_ptr;

void Test1( const unsigned long    &rulCount,
            RECORDHEADER           &rsHeader,
            CSWMRG                 *pGuard,
            auto_ptr<CMMF6046>     &rpMMF );

void Test2( const unsigned long    &rulCount,
            RECORDHEADER           &rsHeader,
            CSWMRG                 *pGuard,
            auto_ptr<CMMF6046>     &rpMMF );


///////////////////////////////////////////////////////////////////////////////
// Main implementation.

int _tmain( int argc, TCHAR* argv[], TCHAR* envp[] )
{
    DBG_UNREFERENCED_PARAMETER( argc );
    DBG_UNREFERENCED_PARAMETER( argv );
    DBG_UNREFERENCED_PARAMETER( envp );

    int iReturnCode = 0;

    auto_ptr<CMMF6046> pMMF( NULL );

    try
    {
        if ( ! ::AfxWinInit( ::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0 ) )
        {
            printf( "Can't initialize MFC\n" );
        }

        pMMF = auto_ptr<CMMF6046>( new CMMF6046 );
        ASSERT( pMMF.get() != NULL );

        if ( ! pMMF->IsInitialized() )
        {
            throw _T( "pMMF->IsInitialized() is false" );
        }

        if ( ! pMMF->InitializeMMFContents() )
        {
            throw _T( "pMMF->InitializeMMFContents() is false" );
        }

        RECORDHEADER    sHeader       = { 0 };
        sHeader.m_iSensorIndex        = 0UL;
        sHeader.m_ulRecordSizeInBytes = sizeof( RECORDHEADER );

        CSWMRG *pGuard = pMMF->GetDataGuard();
        ASSERT( pGuard != NULL );

#if 0
        Test1( 256UL, sHeader, pGuard, pMMF );
#else
        Test2( 4096UL, sHeader, pGuard, pMMF );
#endif

        pGuard = NULL;

        iReturnCode = 0;
    }
    catch( LPCTSTR lpszErrorMsg )
    {
        iReturnCode = 1;
        printf( "CircBuffer: %s.\n", static_cast<const char *>( lpszErrorMsg ) );
    }
    catch ( ... )
    {
        iReturnCode = 2;
        printf( "CircBuffer: Unspecified exception caught.\n" );
    }

    ASSERT( pMMF.get() != NULL );

    if ( pMMF.get() != NULL )
    {
        delete ( pMMF.release() );
        pMMF = auto_ptr<CMMF6046>( NULL );
    }

    if ( iReturnCode == 0 )
    {
        printf( "Done... successfull\n" );
    }

    return iReturnCode;
}

void Test1( const unsigned long &rulCount,
            RECORDHEADER        &rsHeader,
            CSWMRG              *pGuard,
            auto_ptr<CMMF6046>  &rpMMF )
{
    RECORDHEADER   *psRecord      = NULL;
    bool            bReadStatus   = false;
    unsigned long   ulNextToRead  = 0UL;
    unsigned long   ulRecordSize  = 0UL;

    for ( unsigned long ulRecord = 0UL; ulRecord < rulCount; ulRecord++ )
    {
        rsHeader.m_ulMillisecondTimestamp = GetTickCount();
        rsHeader.m_ulRecordCounter        = ulRecord;

        if ( ! rpMMF->Write( &rsHeader, sizeof( RECORDHEADER ) ) )
        {
            printf( "Error writing record %lu\n", ulRecord );
            throw _T( "Record write error" );
        }

        bReadStatus = false;

        pGuard->WaitToRead();

        try
        {
            bReadStatus = rpMMF->Read( ulNextToRead, ulRecordSize, psRecord );

            if ( bReadStatus )
            {
                printf( "%4lu\b\b\b\b", psRecord->m_ulRecordCounter );
            }
        }
        catch ( ... )
        {
            bReadStatus = false;
        }

        pGuard->DoneReading();

        if ( ! bReadStatus )
        {
            printf( "Error reading record %lu from MMF\n", ulRecord );
            return;
        }

        Sleep( 5 );
    }

    printf( "\n" ); 
}

void Test2( const unsigned long &rulCount,
            RECORDHEADER        &rsHeader,
            CSWMRG              *pGuard,
            auto_ptr<CMMF6046>  &rpMMF )
{
    RECORDHEADER   *psRecord      = NULL;
    bool            bReadStatus   = false;
    unsigned long   ulNextToRead  = 0UL;
    unsigned long   ulRecordSize  = 0UL;

    const unsigned long ulMaxRecordSize = ( 2 * 128 + 64 ) * 1024;     // Record is 2.5 cells; 320k.

    BYTE *pbyLongRecord = new BYTE [ ulMaxRecordSize ];
    ASSERT( pbyLongRecord != NULL );

    // Get formatted pointers to the cell boundaries.

    RECORDHEADER * const psHeader1 = reinterpret_cast<RECORDHEADER *>( pbyLongRecord );
    RECORDHEADER * const psHeader2 = reinterpret_cast<RECORDHEADER *>( pbyLongRecord + ( 1 * 128 * 1024 ) );
    RECORDHEADER * const psHeader3 = reinterpret_cast<RECORDHEADER *>( pbyLongRecord + ( 2 * 128 * 1024 ) );

    for ( unsigned long ulRecord = 0UL; ulRecord < rulCount; ulRecord++ )
    {
        // Complete this header.

        rsHeader.m_ulMillisecondTimestamp = GetTickCount();
        rsHeader.m_ulRecordCounter        = ulRecord;

        // Copy header to two cell boundaries.

        memcpy( psHeader1, &rsHeader, sizeof( RECORDHEADER ) );
        memcpy( psHeader2, &rsHeader, sizeof( RECORDHEADER ) );
        memcpy( psHeader3, &rsHeader, sizeof( RECORDHEADER ) );

        // Write the record to the MMF.

        if ( rpMMF->Write( psHeader1, ulMaxRecordSize ) )
        {
//            printf( "Writing record size: %lu, counter: %lu\n", ulMaxRecordSize, psHeader1->m_ulRecordCounter );
        }
        else
        {
            printf( "Error writing record %lu\n", ulRecord );
            throw _T( "Record write error" );
        }

#if 1
        // Read back the headers from the MMF. Remember: we get a pointer to the first cell in the sequence 
        // directly in the shared memory and therefore we need to synchonize access externally to the read
        // operation in a multithreaded environment.

        bReadStatus = false;

        pGuard->WaitToRead();

        try
        {
            bReadStatus = rpMMF->Read( ulNextToRead, ulRecordSize, psRecord );

            RECORDHEADER * const psRead1 = psRecord;
            RECORDHEADER * const psRead2 = reinterpret_cast<RECORDHEADER *>( (reinterpret_cast<BYTE*>( psRecord )) + ( 1 * 128 * 1024 ) );
            RECORDHEADER * const psRead3 = reinterpret_cast<RECORDHEADER *>( (reinterpret_cast<BYTE*>( psRecord )) + ( 2 * 128 * 1024 ) );

            if ( bReadStatus )
            {
                printf( "Size: %lu, Counters : %lu, %lu, %lu\n",    ulRecordSize, 
                                                                    psRead1->m_ulRecordCounter,
                                                                    psRead2->m_ulRecordCounter,
                                                                    psRead3->m_ulRecordCounter );
            }
        }
        catch ( ... )
        {
            bReadStatus = false;
        }

        pGuard->DoneReading();

        if ( ! bReadStatus )
        {
            printf( "Error reading record %lu from MMF\n", ulRecord );
            return;
        }
#endif

        //Sleep( 10 );
    }
}

