www.pudn.com > DalsaNetlink.rar > CyDiagnosticPage.cpp


// CyDiagnosticPage.cpp : implementation file 
// 
 
#include "stdafx.h" 
#include "CyApp.h" 
#include "CyDiagnosticPage.h" 
#include "CyDiagnosticInfoDlg.h" 
 
#include  
#include  
 
#include  
#include  
#include  
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
// DiagnosticThread 
///////////////////////////////////////////////////////////////////////////// 
 
#define GRAB_QUEUE_SIZE      4 
 
class DiagnosticThread : public CyThread 
{ 
public: 
    DiagnosticThread( CyGrabber&    aGrabber, 
                      unsigned long aBufferSize, 
                      unsigned long aBufferCount ) 
        : mGrabber( aGrabber ) 
        , mStopEvent( false, false ) 
        , mGrabSemaphore( GRAB_QUEUE_SIZE, GRAB_QUEUE_SIZE ) 
        , mJobQueueSemaphore( 0, aBufferCount ) 
    { 
        aBufferCount += GRAB_QUEUE_SIZE; 
 
        // create the buffers 
        mProcThread = new ProcessingThread( *this ); 
 
        for ( unsigned long i = 0; i < ( aBufferCount ); ++i ) 
            mFreeBuffers.push_back( new CySimpleBuffer( new unsigned char[ aBufferSize ], aBufferSize, i ) ); 
 
        StartThread(); 
    } 
 
    virtual ~DiagnosticThread() 
    { 
        StopThread(); 
        mStopEvent.Signal(); 
        WaitUntilSignaled(); 
 
        while ( mFreeBuffers.size() > 0 ) 
        { 
            delete mFreeBuffers.front(); 
            mFreeBuffers.pop_front(); 
        } 
 
        delete mProcThread; 
        mProcThread = NULL; 
    } 
 
    CyResult Grab( unsigned long aFlags ) 
    { 
        CySimpleBuffer* lBuffer; 
 
        { 
            CyLockScope lLS( mFreeBuffersGate ); 
            if ( mFreeBuffers.empty() ) 
            { 
                Sleep( 1 ); 
                return CY_RESULT_NOT_FOUND; 
            } 
            lBuffer = mFreeBuffers.front(); 
        } 
 
        CyResult lResult = mGrabber.Grab( CyChannel( 0 ), *lBuffer, CyGrabber::FLAG_NO_WAIT ); 
        if ( lResult == CY_RESULT_OK ) 
        { 
            mFreeBuffers.pop_front(); 
            mQueuedBuffers.push_back( lBuffer ); 
        } 
 
        return lResult; 
    } 
 
    // 
    // Add a job to the job queue 
    // 
    void AddJob( CySimpleBuffer* aBuffer ) 
    { 
        CyAssert( aBuffer != NULL ); 
 
 
        CyLockScope lLS( mJobQueueGate ); 
 
        mJobQueue.push_back( aBuffer ); 
        mJobQueueSemaphore.Release(); 
    } 
 
 
    // 
    // Get a job from the job queue 
    // 
    bool GetJob( CySimpleBuffer** aBuffer, unsigned long aTimeout ) 
    { 
        CyAssert( aBuffer != NULL ); 
        CyAssert( *aBuffer == NULL ); 
        CyAssert( aTimeout > 0 ); 
        *aBuffer = NULL; 
        bool lResult = false; 
 
        if ( mJobQueueSemaphore.WaitUntilSignaled( aTimeout ) == CY_RESULT_OK ) 
        { 
            CyLockScope lLS( mJobQueueGate ); 
 
            if ( !mJobQueue.empty() ) 
            { 
                *aBuffer = mJobQueue.front(); 
                mJobQueue.pop_front(); 
            } 
 
            lResult = true; 
        } 
 
        return lResult; 
    } 
 
 
    // 
    // Returns a job to the acquisition thread 
    // The buffer will simply be placed in the free buffer list 
    // 
    void JobFinished( CySimpleBuffer* aBuffer ) 
    { 
        CyAssert( aBuffer ); 
        CyLockScope lLS( mFreeBuffersGate ); 
 
        mFreeBuffers.push_back( aBuffer ); 
    } 
 
 
    virtual CyResult Run() 
    { 
        SetPriority( TIME_CRITICAL ); 
        CySimpleBuffer* lBuffer; 
        CyResult lResult; 
        unsigned int lIndex; 
        bool lRun = true; 
        unsigned long lFlags = CyGrabber::FLAG_NO_WAIT; 
         
        // Start the continuous mode 
        mGrabber.StartContinuous( CyChannel( 0 ), true, 0 ); 
 
        while ( lRun ) 
        { 
            // Prepare the events 
            CySynchro::Vector lEvents; 
            lEvents.AddSynchro( mStopEvent ); 
            lEvents.AddSynchro( mGrabSemaphore ); 
 
            // Just queue the first buffer, it is the next one to be ready anyway 
            if ( mQueuedBuffers.size() > 0 ) 
                lEvents.AddSynchro( mQueuedBuffers[ 0 ]->GetCompletionEvent() ); 
 
            lResult = CySynchro::WaitUntilSignaled( lEvents ); 
            lIndex = lResult - CySynchro::OBJECT_0; 
            switch ( lIndex ) 
            { 
                default: 
                    CyAssert( false ); 
                case 0: 
                    lRun = false; 
                    break; 
 
                case 1: 
                    if ( Grab( lFlags ) != CY_RESULT_OK ) 
                    { 
                        lFlags = CyGrabber::FLAG_NO_WAIT; 
                        mGrabSemaphore.Release( 1 ); 
                    } 
                    else 
                        lFlags = CyGrabber::FLAG_NO_WAIT | CyGrabber::FLAG_NO_FLUSH; 
                    break; 
 
                case 2: 
                    lBuffer = mQueuedBuffers.front(); 
                    mQueuedBuffers.pop_front(); 
 
                    // Queue the next buffer right away 
                    if ( Grab( lFlags ) != CY_RESULT_OK ) 
                    { 
                        lFlags = CyGrabber::FLAG_NO_WAIT; 
                        mGrabSemaphore.Release( 1 ); 
                    } 
                    else 
                        lFlags = CyGrabber::FLAG_NO_WAIT | CyGrabber::FLAG_NO_FLUSH; 
 
                    // Give the queue to the processing thread 
                    // We want the grabbing thread to do as little as possible 
                    // So we give the job to another thread. 
                    AddJob( lBuffer ); 
                    break; 
            } 
        } 
 
        // Stop the continuous mode 
        mGrabber.GetDevice().AbortReceiveData( CyChannel( 0 ) ); 
        CyThread::Sleep( 1000 ); 
        mGrabber.StopContinuous( CyChannel( 0 ) ); 
 
        return CY_RESULT_OK; 
    } 
 
// stats 
public: 
    CyGate mStatsGate; 
    std::map< CyResult, unsigned long > 
        mErrorCounts; 
 
    struct Stats 
    { 
        unsigned long   mCount; 
        unsigned long   mFrameOverrun; 
        unsigned long   mGrabberFIFOOverrun; 
        unsigned long   mImageDropped; 
        unsigned long   mPartialLineMissing; 
        unsigned long   mFullLineMissing; 
        unsigned long   mExpectedResendCount; 
        unsigned long   mIgnoredPacketCount; 
        unsigned long   mLostPacketCount; 
        unsigned long   mResendRequestCount; 
        unsigned long   mStartPacketCount; 
        unsigned long   mUnexpectedResendCount; 
 
        Stats() 
            : mCount( 0 ) 
            , mFrameOverrun( 0 ) 
            , mGrabberFIFOOverrun( 0 ) 
            , mImageDropped( 0 ) 
            , mPartialLineMissing( 0 ) 
            , mFullLineMissing( 0 ) 
            , mExpectedResendCount( 0 ) 
            , mIgnoredPacketCount( 0 ) 
            , mLostPacketCount( 0 ) 
            , mResendRequestCount( 0 ) 
            , mStartPacketCount( 0 ) 
            , mUnexpectedResendCount( 0 ) 
        { 
        } 
    }; 
 
    Stats   mGoodStats; 
    Stats   mBadStats; 
 
    std::deque mMissedID; 
 
private: 
    class ProcessingThread : public CyThread 
    { 
        public: 
            ProcessingThread( DiagnosticThread& aThread ) 
                : mThread( aThread ) 
            { 
                StartThread(); 
            } 
 
            virtual ~ProcessingThread() 
            { 
                StopThread(); 
                WaitUntilSignaled(); 
            } 
 
            virtual CyResult Run() 
            { 
                Stats * lStats; 
                bool lFirst = true; 
                unsigned long lCurrentID = 0; 
                unsigned long lPreviousID = 0; 
                CySimpleBuffer* lBuffer = 0; 
                unsigned long i; 
 
 
                //  
                // Run loop 
                // 
                CyResult lResult; 
                while ( !IsStopping() ) 
                { 
                    // Get a job from the acquisition thread 
                    lBuffer = NULL; 
                    if ( !mThread.GetJob( &lBuffer, 1000 ) ) 
                        continue; 
 
                    CyLockScope lLS( mThread.mStatsGate ); 
                    lResult = lBuffer->GetCompletionEvent().GetResult(); 
                    if ( lResult == CY_RESULT_OK ) 
                        lStats = &mThread.mGoodStats; 
                    else 
                    { 
                        mThread.mErrorCounts[ lResult ] = mThread.mErrorCounts[ lResult ] + 1; 
                        lStats = &mThread.mBadStats; 
                    } 
 
                    lStats->mCount                  += 1; 
                    lStats->mFrameOverrun           += lBuffer->GetSharedMemory().GetImageStatus().mFrameOverrun; 
                    lStats->mGrabberFIFOOverrun     += lBuffer->GetSharedMemory().GetImageStatus().mGrabberFIFOOverrun; 
                    lStats->mImageDropped           += lBuffer->GetSharedMemory().GetImageStatus().mImageDropped; 
                    lStats->mPartialLineMissing     += lBuffer->GetSharedMemory().GetImageStatus().mPartialLineMissing; 
                    lStats->mFullLineMissing        += lBuffer->GetSharedMemory().GetImageStatus().mFullLineMissing; 
                    lStats->mExpectedResendCount    += lBuffer->GetSharedMemory().GetExpectedResendCount(); 
                    lStats->mIgnoredPacketCount     += lBuffer->GetSharedMemory().GetIgnoredPacketCount(); 
                    lStats->mLostPacketCount        += lBuffer->GetSharedMemory().GetLostPacketCount(); 
                    lStats->mResendRequestCount     += lBuffer->GetSharedMemory().GetResendRequestCount(); 
                    lStats->mStartPacketCount       += lBuffer->GetSharedMemory().GetStartPacketCount(); 
                    lStats->mUnexpectedResendCount  += lBuffer->GetSharedMemory().GetUnexpectedResendCount(); 
                    lCurrentID = lBuffer->GetSharedMemory().GetImageID(); 
 
                    if ( !lFirst ) 
                    { 
                        if ( ( lCurrentID != 0 ) && ( lPreviousID != 0xffff ) ) 
                        { 
                            for ( i = lPreviousID + 1; i < lCurrentID; ++i ) 
                                mThread.mMissedID.push_back( i ); 
                        } 
                    } 
                    lFirst = false; 
                    lPreviousID = lCurrentID; 
 
                    // Release the job back to the acquisition thread 
                    if ( lBuffer != NULL ) 
                        mThread.JobFinished( lBuffer ); 
                    lBuffer = NULL; 
                } 
 
                return CY_RESULT_OK; 
            } 
 
        private: 
            DiagnosticThread& mThread; 
    }; 
 
private: 
    CyGrabber&                  mGrabber; 
    CyEvent                     mStopEvent; 
    CySemaphore                 mGrabSemaphore; 
 
    CyGate                      mFreeBuffersGate; 
    std::deque mFreeBuffers; 
 
    std::deque mQueuedBuffers; 
 
    // Processing queue.  Data processors will use the GetJob and JobFinished 
    // methods to get jobs 
    std::deque mJobQueue; 
    CyGate                      mJobQueueGate; 
    CySemaphore                 mJobQueueSemaphore; 
 
    // Job processing thread 
    ProcessingThread*           mProcThread; 
}; 
 
 
///////////////////////////////////////////////////////////////////////////// 
// CyDiagnosticPage property page 
 
IMPLEMENT_DYNCREATE(CyDiagnosticPage, CPropertyPage) 
 
CyDiagnosticPage::CyDiagnosticPage() 
    : CPropertyPage(CyDiagnosticPage::IDD) 
    , mThread( NULL ) 
{ 
	//{{AFX_DATA_INIT(CyDiagnosticPage) 
	mBadItem1 = _T(""); 
	mBadItem10 = _T(""); 
	mBadItem11 = _T(""); 
	mBadItem12 = _T(""); 
	mBadItem2 = _T(""); 
	mBadItem3 = _T(""); 
	mBadItem4 = _T(""); 
	mBadItem5 = _T(""); 
	mBadItem6 = _T(""); 
	mBadItem7 = _T(""); 
	mBadItem8 = _T(""); 
	mBadItem9 = _T(""); 
	mErrorTypes = _T(""); 
	mMissedID = _T(""); 
	//}}AFX_DATA_INIT 
} 
 
CyDiagnosticPage::~CyDiagnosticPage() 
{ 
} 
 
void CyDiagnosticPage::DoDataExchange(CDataExchange* pDX) 
{ 
	CPropertyPage::DoDataExchange(pDX); 
	//{{AFX_DATA_MAP(CyDiagnosticPage) 
	DDX_Control(pDX, IDC_SHOW_MISSED_ID, mShowMissedIDButton); 
	DDX_Control(pDX, IDC_SHOW_ERROR_COUNTS, mShowErrorCountsButton); 
	DDX_Control(pDX, IDC_DIAG_START_STOP, mStartStopButton); 
	DDX_Control(pDX, IDC_DIAG_SAVE, mSaveButton); 
	DDX_Text(pDX, IDC_BAD_ITEM1, mBadItem1); 
	DDX_Text(pDX, IDC_BAD_ITEM10, mBadItem10); 
	DDX_Text(pDX, IDC_BAD_ITEM11, mBadItem11); 
	DDX_Text(pDX, IDC_BAD_ITEM12, mBadItem12); 
	DDX_Text(pDX, IDC_BAD_ITEM2, mBadItem2); 
	DDX_Text(pDX, IDC_BAD_ITEM3, mBadItem3); 
	DDX_Text(pDX, IDC_BAD_ITEM4, mBadItem4); 
	DDX_Text(pDX, IDC_BAD_ITEM5, mBadItem5); 
	DDX_Text(pDX, IDC_BAD_ITEM6, mBadItem6); 
	DDX_Text(pDX, IDC_BAD_ITEM7, mBadItem7); 
	DDX_Text(pDX, IDC_BAD_ITEM8, mBadItem8); 
	DDX_Text(pDX, IDC_BAD_ITEM9, mBadItem9); 
	DDX_Text(pDX, IDC_GOOD_ITEM1, mGoodItem1); 
	DDX_Text(pDX, IDC_GOOD_ITEM10, mGoodItem10); 
	DDX_Text(pDX, IDC_GOOD_ITEM11, mGoodItem11); 
	DDX_Text(pDX, IDC_GOOD_ITEM12, mGoodItem12); 
	DDX_Text(pDX, IDC_GOOD_ITEM2, mGoodItem2); 
	DDX_Text(pDX, IDC_GOOD_ITEM3, mGoodItem3); 
	DDX_Text(pDX, IDC_GOOD_ITEM4, mGoodItem4); 
	DDX_Text(pDX, IDC_GOOD_ITEM5, mGoodItem5); 
	DDX_Text(pDX, IDC_GOOD_ITEM6, mGoodItem6); 
	DDX_Text(pDX, IDC_GOOD_ITEM7, mGoodItem7); 
	DDX_Text(pDX, IDC_GOOD_ITEM8, mGoodItem8); 
	DDX_Text(pDX, IDC_GOOD_ITEM9, mGoodItem9); 
	DDX_Text(pDX, IDC_ERROR_TYPES, mErrorTypes); 
	DDX_Text(pDX, IDC_MISSED_ID, mMissedID); 
	//}}AFX_DATA_MAP 
} 
 
 
BEGIN_MESSAGE_MAP(CyDiagnosticPage, CPropertyPage) 
	//{{AFX_MSG_MAP(CyDiagnosticPage) 
	ON_WM_TIMER() 
	ON_BN_CLICKED(IDC_DIAG_SAVE, OnDiagSave) 
	ON_BN_CLICKED(IDC_DIAG_START_STOP, OnDiagStartStop) 
	ON_BN_CLICKED(IDC_SHOW_ERROR_COUNTS, OnShowErrorCounts) 
	ON_BN_CLICKED(IDC_SHOW_MISSED_ID, OnShowMissedId) 
	ON_WM_DESTROY() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CyDiagnosticPage message handlers 
 
BOOL CyDiagnosticPage::OnSetActive()  
{ 
    CyCameraInterface& lCamera = reinterpret_cast( AfxGetApp() )->GetCamera(); 
    CyDisplayEx& lDisplay = reinterpret_cast( AfxGetApp() )->GetDisplay(); 
    CyImageBuffer& lBuffer = reinterpret_cast( AfxGetApp() )->GetBuffer( 0 ); 
    bool lRunning = false; 
    unsigned int i; 
 
    if ( lBuffer.GetCapacity() <= 1 ) 
    { 
        MessageBox( "Please set-up the buffer by testing the acquisition first!" ); 
        reinterpret_cast( GetParent() )->SetActivePage( 0 ); 
        return FALSE; 
    } 
 
    // Check if the display is running 
    for ( i = 0; ( !lRunning ) && ( i < lDisplay.GetSubDisplayCount() ); ++i ) 
    { 
        if ( lDisplay.IsDisplaying( i ) ) 
            lRunning = true; 
    } 
 
    // Check if the grabber is running 
    for ( i = 0; ( !lRunning ) && ( i < lCamera.GetGrabber().GetDevice().GetChannelCount() ); ++i ) 
    { 
        if ( lCamera.GetGrabber().IsStarted( CyChannel( i ) ) ) 
            lRunning = true; 
    } 
 
    if ( lRunning ) 
    { 
        MessageBox( "You must stop any display or acquisition before using the diagnotic tool!" ); 
        reinterpret_cast( GetParent() )->SetActivePage( 0 ); 
        return FALSE; 
    } 
    else 
        return CPropertyPage::OnSetActive(); 
} 
 
BOOL CyDiagnosticPage::OnKillActive()  
{ 
	if ( mThread != 0 ) 
        OnDiagStartStop(); 
 
	return CPropertyPage::OnKillActive(); 
} 
 
BOOL CyDiagnosticPage::OnInitDialog()  
{ 
	CPropertyPage::OnInitDialog(); 
		 
	return TRUE;  // return TRUE unless you set the focus to a control 
	              // EXCEPTION: OCX Property Pages should return FALSE 
} 
 
void CyDiagnosticPage::OnTimer(UINT nIDEvent)  
{ 
    CString lTemp; 
	if ( nIDEvent == 1 ) 
    { 
        DiagnosticThread * lThread = reinterpret_cast< DiagnosticThread* >( mThread ); 
        CyLockScope lLS( lThread->mStatsGate ); 
 
        mBadItem1.Format( "%lu", lThread->mBadStats.mCount ); 
        mBadItem2.Format( "%lu", lThread->mBadStats.mFrameOverrun ); 
        mBadItem3.Format( "%lu", lThread->mBadStats.mGrabberFIFOOverrun ); 
        mBadItem4.Format( "%lu", lThread->mBadStats.mImageDropped ); 
        mBadItem5.Format( "%lu", lThread->mBadStats.mPartialLineMissing ); 
        mBadItem6.Format( "%lu", lThread->mBadStats.mFullLineMissing ); 
        mBadItem7.Format( "%lu", lThread->mBadStats.mExpectedResendCount ); 
        mBadItem8.Format( "%lu", lThread->mBadStats.mIgnoredPacketCount ); 
        mBadItem9.Format( "%lu", lThread->mBadStats.mLostPacketCount ); 
        mBadItem10.Format( "%lu",lThread->mBadStats.mResendRequestCount ); 
        mBadItem11.Format( "%lu",lThread->mBadStats.mStartPacketCount ); 
        mBadItem12.Format( "%lu",lThread->mBadStats.mUnexpectedResendCount ); 
 
        mGoodItem1.Format( "%lu", lThread->mGoodStats.mCount ); 
        mGoodItem2.Format( "%lu", lThread->mGoodStats.mFrameOverrun ); 
        mGoodItem3.Format( "%lu", lThread->mGoodStats.mGrabberFIFOOverrun ); 
        mGoodItem4.Format( "%lu", lThread->mGoodStats.mImageDropped ); 
        mGoodItem5.Format( "%lu", lThread->mGoodStats.mPartialLineMissing ); 
        mGoodItem6.Format( "%lu", lThread->mGoodStats.mFullLineMissing ); 
        mGoodItem7.Format( "%lu", lThread->mGoodStats.mExpectedResendCount ); 
        mGoodItem8.Format( "%lu", lThread->mGoodStats.mIgnoredPacketCount ); 
        mGoodItem9.Format( "%lu", lThread->mGoodStats.mLostPacketCount ); 
        mGoodItem10.Format( "%lu",lThread->mGoodStats.mResendRequestCount ); 
        mGoodItem11.Format( "%lu",lThread->mGoodStats.mStartPacketCount ); 
        mGoodItem12.Format( "%lu",lThread->mGoodStats.mUnexpectedResendCount ); 
 
        mErrorTypes.Format( "%lu", lThread->mErrorCounts.size() ); 
        mMissedID.Format( "%lu", lThread->mMissedID.size() ); 
        
        UpdateData( FALSE ); 
    } 
	 
	CPropertyPage::OnTimer(nIDEvent); 
} 
 
void CyDiagnosticPage::OnDiagSave()  
{ 
	CFileDialog	lDialog( false, "txt", NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "Text Files (*.txt)|*.txt|All files (*.*)|*.*||" ); 
	if ( lDialog.DoModal() == IDOK ) 
    { 
        FILE* lFile = fopen( lDialog.GetPathName(), "wt" ); 
        if ( lFile == NULL ) 
        { 
            MessageBox( "Could not create file!" ); 
            return; 
        } 
 
        DiagnosticThread * lThread = reinterpret_cast< DiagnosticThread* >( mThread ); 
        CyLockScope lLS( lThread->mStatsGate ); 
 
        fprintf( lFile, 
                 "Good images: %lu\n" 
                 "\t FrameOverrun         : %lu\n" 
                 "\t GrabberFIFOOverrun   : %lu\n" 
                 "\t ImageDropped         : %lu\n" 
                 "\t PartialLineMissing   : %lu\n" 
                 "\t FullLineMissing      : %lu\n" 
                 "\t ExpectedResendCount  : %lu\n" 
                 "\t IgnoredPacketCount   : %lu\n" 
                 "\t LostPacketCount      : %lu\n" 
                 "\t ResendRequestCount   : %lu\n" 
                 "\t StartPacketCount     : %lu\n" 
                 "\t UnexpectedResendCount: %lu\n", 
                lThread->mGoodStats.mCount, 
                lThread->mGoodStats.mFrameOverrun, 
                lThread->mGoodStats.mGrabberFIFOOverrun, 
                lThread->mGoodStats.mImageDropped, 
                lThread->mGoodStats.mPartialLineMissing, 
                lThread->mGoodStats.mFullLineMissing, 
                lThread->mGoodStats.mExpectedResendCount, 
                lThread->mGoodStats.mIgnoredPacketCount, 
                lThread->mGoodStats.mLostPacketCount, 
                lThread->mGoodStats.mResendRequestCount, 
                lThread->mGoodStats.mStartPacketCount, 
                lThread->mGoodStats.mUnexpectedResendCount ); 
        fprintf( lFile, "\n" ); 
 
        fprintf( lFile, 
                 "Bad images: %lu\n" 
                 "\t FrameOverrun         : %lu\n" 
                 "\t GrabberFIFOOverrun   : %lu\n" 
                 "\t ImageDropped         : %lu\n" 
                 "\t PartialLineMissing   : %lu\n" 
                 "\t FullLineMissing      : %lu\n" 
                 "\t ExpectedResendCount  : %lu\n" 
                 "\t IgnoredPacketCount   : %lu\n" 
                 "\t LostPacketCount      : %lu\n" 
                 "\t ResendRequestCount   : %lu\n" 
                 "\t StartPacketCount     : %lu\n" 
                 "\t UnexpectedResendCount: %lu\n", 
                lThread->mBadStats.mCount, 
                lThread->mBadStats.mFrameOverrun, 
                lThread->mBadStats.mGrabberFIFOOverrun, 
                lThread->mBadStats.mImageDropped, 
                lThread->mBadStats.mPartialLineMissing, 
                lThread->mBadStats.mFullLineMissing, 
                lThread->mBadStats.mExpectedResendCount, 
                lThread->mBadStats.mIgnoredPacketCount, 
                lThread->mBadStats.mLostPacketCount, 
                lThread->mBadStats.mResendRequestCount, 
                lThread->mBadStats.mStartPacketCount, 
                lThread->mBadStats.mUnexpectedResendCount ); 
        fprintf( lFile, "\n" ); 
 
        std::map< CyResult, unsigned long >::const_iterator lItr1; 
        for ( lItr1 = lThread->mErrorCounts.begin(); lItr1 != lThread->mErrorCounts.end(); ++lItr1 ) 
        { 
            if ( lItr1 == lThread->mErrorCounts.begin() ) 
                fprintf( lFile, "Encountered errors:\n" ); 
 
            fprintf( lFile, "\t%s: %lu\n", CoyoteStatusMessage( CyResult( lItr1->first ) ), lItr1->second ); 
        } 
        fprintf( lFile, "\n" ); 
 
        std::deque::const_iterator lItr2; 
        for ( lItr2 = lThread->mMissedID.begin(); lItr2 != lThread->mMissedID.end(); ++lItr2 ) 
        { 
            if ( lItr2 == lThread->mMissedID.begin() ) 
                fprintf( lFile, "Missed Image IDs:\n" ); 
 
            fprintf( lFile, "\t%lu\n", *lItr2 ); 
        } 
        fprintf( lFile, "\n" ); 
 
 
        fclose( lFile ); 
    } 
} 
 
void CyDiagnosticPage::OnDiagStartStop()  
{ 
    if ( mThread == 0 ) 
    { 
        CyGrabber& lGrabber = reinterpret_cast( AfxGetApp() )->GetGrabber(); 
        CyImageBuffer& lBuffer = reinterpret_cast( AfxGetApp() )->GetBuffer( 0 ); 
 
        // check the size of the image. 
        unsigned long lBufferCount = lBuffer.GetQueueSize(); 
 
        // check the image size, if it is smaller  
        unsigned long lMaxFrameRate = static_cast( ceil( 100000000.0 / static_cast( lBuffer.GetCapacity() ) ) ); 
        lMaxFrameRate /= 192; 
        if ( lBufferCount < lMaxFrameRate ) 
            lBufferCount = lMaxFrameRate; 
 
        // Start the thread 
        mThread = new DiagnosticThread( lGrabber, lBuffer.GetCapacity(), lBufferCount ); 
        mStartStopButton.SetWindowText( "Stop" ); 
 
        SetTimer( 1, 500, NULL ); 
        mShowErrorCountsButton.EnableWindow( TRUE ); 
        mShowMissedIDButton.EnableWindow( TRUE ); 
        mSaveButton.EnableWindow( TRUE ); 
    } 
 
    else 
    { 
        mShowErrorCountsButton.EnableWindow( FALSE ); 
        mShowMissedIDButton.EnableWindow( FALSE ); 
        mSaveButton.EnableWindow( FALSE ); 
        KillTimer( 1 ); 
        delete mThread; 
        mThread = NULL; 
        mStartStopButton.SetWindowText( "Start" ); 
    } 
} 
 
void CyDiagnosticPage::OnShowErrorCounts()  
{ 
    DiagnosticThread * lThread = reinterpret_cast< DiagnosticThread* >( mThread ); 
    CyDiagnosticInfoDlg lDlg; 
    CyDiagnosticInfoDlg::Column lCol1, lCol2; 
 
    lCol1.mHeader = "Error type"; 
    lCol1.mWidth  = 250; 
    lCol2.mHeader = "Count"; 
    lCol2.mWidth  = 75; 
  
    { 
        CyLockScope lLS( lThread->mStatsGate ); 
        CString lTemp; 
 
        std::map< CyResult, unsigned long >::const_iterator lItr; 
        for ( lItr = lThread->mErrorCounts.begin(); lItr != lThread->mErrorCounts.end(); ++lItr ) 
        { 
            lCol1.mItems.push_back( CoyoteStatusMessage( CyResult( lItr->first ) ) ); 
            lTemp.Format( "%lu", lItr->second ); 
            lCol2.mItems.push_back( (LPCTSTR) lTemp ); 
        } 
    } 
 
    lDlg.mData.push_back( lCol1 ); 
    lDlg.mData.push_back( lCol2 ); 
 
    lDlg.DoModal(); 
} 
 
void CyDiagnosticPage::OnShowMissedId()  
{ 
    DiagnosticThread * lThread = reinterpret_cast< DiagnosticThread* >( mThread ); 
    CyDiagnosticInfoDlg lDlg; 
    CyDiagnosticInfoDlg::Column lCol1; 
 
    lCol1.mHeader = "Missed Image ID"; 
    lCol1.mWidth  = 100; 
  
    { 
        CyLockScope lLS( lThread->mStatsGate ); 
        CString lTemp; 
 
        std::deque::const_iterator lItr; 
        for ( lItr = lThread->mMissedID.begin(); lItr != lThread->mMissedID.end(); ++lItr ) 
        { 
            lTemp.Format( "%lu", *lItr ); 
            lCol1.mItems.push_back( (LPCTSTR) lTemp ); 
        } 
    } 
 
    lDlg.mData.push_back( lCol1 ); 
 
    lDlg.DoModal(); 
} 
 
void CyDiagnosticPage::OnDestroy()  
{ 
    if ( mThread != NULL ) 
        OnDiagStartStop(); 
 
	CPropertyPage::OnDestroy(); 
}