/***************************************************************************
**
**    $Header:   D:/ECB2S/SRC/LOG/SPATIME.CPP   1.2.1.4   17 Apr 1997 16:00:10   ZJRD  $
**
**    $Log:   D:/ECB2S/SRC/LOG/SPATIME.CPP  $
** 
**    Rev 1.2.1.4   17 Apr 1997 16:00:10   ZJRD
** No change.
** 
**    Rev 1.2.1.3   16 Apr 1997 10:33:00   ZJRD
** No change.
** 
**    Rev 1.2.1.2   10 Apr 1997 15:42:34   ZJRD
** No change.
** 
**    Rev 1.2.1.1   03 Apr 1997 15:21:18   ZJRD
** No change.
** 
**    Rev 1.2.1.0   28 Mar 1997 10:25:30   ZJRD
** easy pack sld 2.09d
** 
**    Rev 1.1   19 Mar 1997 11:35:26   ZJRD
** No change.
** 
**    Rev 1.0   12 Mar 1997 14:49:58   ZJRD
** Initial revision.
** 
**    Rev 1.7.1.0.1.0   11 Nov 1996 12:59:22   ZJRD
** EasyPack/SLD Version 2.01
** 
**    Rev 1.7.1.4   09 Sep 1996 13:18:04   ZJRD
** No change.
** 
**    Rev 1.7.1.3   05 Sep 1996 11:29:36   ZJRD
** EasyPack/SLD Version 1.9e
** 
**    Rev 1.7.1.2   02 Sep 1996 09:56:40   ZJRD
** EasyPack/SLD Version 1.9d
** 
**    Rev 1.7.1.1   28 Aug 1996 15:52:30   ZJRD
** EasyPack/SLD Version 1.9b
** 
**    Rev 1.7.1.0   12 Aug 1996 10:55:58   ZJRD
** EasyPack/SLD Version 1.98
** 
**    Rev 1.7   11 Jun 1996 10:26:16   ZJRD
** EasyPack/SLD Version 1.97
** 
**    Rev 1.5   05 Jun 1996 14:54:02   ZJRD
** EasyPack/SLD Version 1.96
** 
**    Rev 1.4   29 May 1996 09:29:28   ZJRD
** EasyPack/SLD Version 1.95
** 
**    Rev 1.3   16 May 1996 09:06:46   ZJRD
** EasyPack/SLD Version 1.94
** 
**    Rev 1.2   10 May 1996 09:09:46   ZJRD
** EasyPack/SLD Version 1.93
** 
**    Rev 1.1   02 May 1996 10:26:22   ZJRD
** EasyPack/SLD Version 1.92
** 
**    Rev 1.1   18 Apr 1996 12:54:14   Shirley
** EasyPack/SLD Version 1.91
** 
**    Rev 1.0   12 Apr 1996 10:36:18   Shirley
** Initial revision.
** 
****************************************************************************/

/////////////////////////////////////////////////////////////////////////////
//
//  File name: SPATIME.CPP
//
//  Description: The implementation file fore class: CSpaExecutionTimePage.
//
//  Author: Chen Jun
//
//  Date: 03/21/96
//
//  Modification:
//      1. 03/21/96, Initial version of the class: CSpaExecutionTimeDlg.
//      2. 03/29/96, CSpaExecutionTimePage with CPropertyPage.
//
//  Copyright (C) 1996 Microtek International. All rights reserved.
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "resource.h"

#include "spagrp.h"
#include "spauser.h"
#include "spabp.h"

#include "cpust.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// External variables.
extern char szAppPath[_MAX_PATH+1];

STATUS AbiSpaBpSet(SPABPSETINFO spaBpSetInfor);

STATUS AbiGetOneReg(int iRegId, UINT* uRegValue);
STATUS AbiGetTimerCount(TIMER_COUNT *pTimerCount);
int GetPCBank(void);

STATUS AbiGo(FLAG runFlag, ADDR fromAddr, ADDR tillAddr);
STATUS AbiAbort();
STATUS AbiClrAllBp();
void RestoreAllConfig(void);

/////////////////////////////////////////////////////////////////////////////
// CSpaExecutionTimePage dialog

CSpaExecutionTimePage::CSpaExecutionTimePage()
	: CPropertyPage(CSpaExecutionTimePage::IDD),
    m_uTimerID(0), m_cdwMaxTime(4000000000), m_cnMaxCount(40000000),
    m_bStop(TRUE), m_nWhichModule(module0), m_nWhichBtn(btnStart)
{
	//{{AFX_DATA_INIT(CSpaExecutionTimePage)
	m_strRange1 = _T("");
	m_dwCount1 = 0;
	m_dwCount2 = 0;
	m_dwCount3 = 0;
	m_dwCount4 = 0;
	m_dwCount5 = 0;
	m_dwCount6 = 0;
	m_dwCount7 = 0;
	m_dwCount8 = 0;
	m_dwCount9 = 0;
	m_dwCount10 = 0;
	m_dwTotal = 0;
	m_strRange0 = _T("");
	m_dwLongPane = 0;
	m_dwShortPane = 0;
	m_strUnitLong = _T("us");
	m_strUnitShort = _T("us");
	//}}AFX_DATA_INIT

	m_nCountPer1 = 0;
	m_nCountPer2 = 0;
	m_nCountPer3 = 0;
	m_nCountPer4 = 0;
	m_nCountPer5 = 0;
	m_nCountPer6 = 0;
	m_nCountPer7 = 0;
	m_nCountPer8 = 0;
	m_nCountPer9 = 0;
	m_nCountPer10 = 0;
	
	m_dwTime = 0;
	m_dwLong = 0;
	m_dwShort = 0;
}

void CSpaExecutionTimePage::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CSpaExecutionTimePage)
	DDX_Control(pDX, IDC_EDIT_SPA_DEFINE_BP, m_editBp);
	DDX_Control(pDX, IDC_BUTTON_SPA_BP, m_btnBp);
	DDX_Control(pDX, IDC_BUTTON_SPA_TIME_RESTART, m_btnRestart);
	DDX_Control(pDX, IDC_EDIT_SPA_TIME_SHORT, m_editShort);
	DDX_Control(pDX, IDC_EDIT_SPA_TIME_LONG, m_editLong);
	DDX_Control(pDX, IDC_STATIC_SPA_TIME_COUNTBAR1, m_staticCountBar1);
	DDX_Control(pDX, IDC_STATIC_SPA_TIME_COUNTBAR2, m_staticCountBar2);
	DDX_Control(pDX, IDC_STATIC_SPA_TIME_COUNTBAR3, m_staticCountBar3);
	DDX_Control(pDX, IDC_STATIC_SPA_TIME_COUNTBAR4, m_staticCountBar4);
	DDX_Control(pDX, IDC_STATIC_SPA_TIME_COUNTBAR5, m_staticCountBar5);
	DDX_Control(pDX, IDC_STATIC_SPA_TIME_COUNTBAR6, m_staticCountBar6);
	DDX_Control(pDX, IDC_STATIC_SPA_TIME_COUNTBAR7, m_staticCountBar7);
	DDX_Control(pDX, IDC_STATIC_SPA_TIME_COUNTBAR8, m_staticCountBar8);
	DDX_Control(pDX, IDC_STATIC_SPA_TIME_COUNTBAR9, m_staticCountBar9);
	DDX_Control(pDX, IDC_STATIC_SPA_TIME_COUNTBAR10, m_staticCountBar10);
	DDX_Control(pDX, IDC_BUTTON_SPA_TIME_EDIT, m_btnEdit);
	DDX_Control(pDX, IDC_BUTTON_SPA_TIME_STOP, m_btnStop);
	DDX_Control(pDX, IDC_BUTTON_SPA_TIME_START, m_btnStart);
	DDX_Control(pDX, IDC_COMBO_SPA_TIME_RANGE1, m_comboRange1);
	DDX_CBString(pDX, IDC_COMBO_SPA_TIME_RANGE1, m_strRange1);
	DDV_MaxChars(pDX, m_strRange1, 80);
	DDX_Text(pDX, IDC_EDIT_SPA_TIME_COUNT1, m_dwCount1);
	DDX_Text(pDX, IDC_EDIT_SPA_TIME_COUNT2, m_dwCount2);
	DDX_Text(pDX, IDC_EDIT_SPA_TIME_COUNT3, m_dwCount3);
	DDX_Text(pDX, IDC_EDIT_SPA_TIME_COUNT4, m_dwCount4);
	DDX_Text(pDX, IDC_EDIT_SPA_TIME_COUNT5, m_dwCount5);
	DDX_Text(pDX, IDC_EDIT_SPA_TIME_COUNT6, m_dwCount6);
	DDX_Text(pDX, IDC_EDIT_SPA_TIME_COUNT7, m_dwCount7);
	DDX_Text(pDX, IDC_EDIT_SPA_TIME_COUNT8, m_dwCount8);
	DDX_Text(pDX, IDC_EDIT_SPA_TIME_COUNT9, m_dwCount9);
	DDX_Text(pDX, IDC_EDIT_SPA_TIME_COUNT10, m_dwCount10);
	DDX_Text(pDX, IDC_EDIT_SPA_TIME_TOTAL, m_dwTotal);
	DDX_Text(pDX, IDC_EDIT_SPA_DEFINE_BP, m_strRange0);
	DDV_MaxChars(pDX, m_strRange0, 80);
	DDX_Text(pDX, IDC_EDIT_SPA_TIME_LONG, m_dwLongPane);
	DDX_Text(pDX, IDC_EDIT_SPA_TIME_SHORT, m_dwShortPane);
	DDX_Text(pDX, IDC_STATIC_SPA_UNIT_LONG, m_strUnitLong);
	DDX_Text(pDX, IDC_STATIC_SPA_UNIT_SHORT, m_strUnitShort);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CSpaExecutionTimePage, CPropertyPage)
	//{{AFX_MSG_MAP(CSpaExecutionTimePage)
	ON_BN_CLICKED(ID_HELP, OnHelp)
	ON_BN_CLICKED(IDC_BUTTON_SPA_TIME_EDIT, OnButtonSpaTimeEdit)
	ON_BN_CLICKED(IDC_BUTTON_SPA_TIME_START, OnButtonSpaTimeStart)
	ON_BN_CLICKED(IDC_BUTTON_SPA_TIME_STOP, OnButtonSpaTimeStop)
	ON_WM_SHOWWINDOW()
	ON_WM_TIMER()
	ON_BN_CLICKED(IDC_BUTTON_SPA_TIME_RESTART, OnButtonSpaTimeRestart)
	ON_BN_CLICKED(IDC_BUTTON_SPA_BP, OnButtonSpaBp)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CSpaExecutionTimePage common routines

void CSpaExecutionTimePage::CheckInputSyntax(void)
{
	// Check empty.
	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
	if ( m_strRange1.IsEmpty() ) {
		pSheet->m_nErrorID = pSheet->errInput;
		return;
	}
}

void CSpaExecutionTimePage::RedrawBar(void)
{
	// Update count bar.
	for ( int i(1); i <= 10; i++ ) {
		UpdateCountBar(i);
	}
}

void CSpaExecutionTimePage::UpdateBar(void)
{
	// Get entry data.
	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
	int nRet = GetEntryData();
	
	// Ignore when running.
	if ( running == nRet ) {
		return;
	}

	// When failuer has been detected.
	if ( failure == nRet ) {
		// Stop timer action.
		StopTimerAction();

		// Prompt.
		pSheet->m_nErrorID = pSheet->errRange;
		pSheet->DisplayErrorMessage();
		return;
	}

	// Update count bar.
	UpdateUnit();
	UpdateData(FALSE);
	for ( int i(1); i <= 10; i++ ) {
		UpdateCountBar(i);
	}
	
	// Kill timer if Stop.
	if ( stop == nRet ) {
		StopTimerAction();
		return;
	}
	
	// Continue to go when pause.
	if ( pause == nRet ) {
		// Go Till End.
		::ADDR FromAddr, TillAddr;
		memset(&FromAddr, 0, sizeof(FromAddr));

		TillAddr.addrType = m_EntryInfo.goArgument.addrTo.addrType;
		TillAddr.addr = m_EntryInfo.goArgument.addrTo.addr;

		if ( ::ICE_OK != ::AbiGo(0, FromAddr, TillAddr) ) {
			StopTimerAction();
			pSheet->m_nErrorID = pSheet->errAbi;
			pSheet->DisplayErrorMessage();
			return;
		}
	}
}

void CSpaExecutionTimePage::UpdateUnit()
{
	// Change time & unit of LONG.
	if ( m_dwLong >= 0 && m_dwLong < 1000 ) {
		m_dwLongPane = m_dwLong;
		m_strUnitLong = _T("us");
	}
	else if ( m_dwLong >= 1000 && m_dwLong < 1000000 ) {
		m_dwLongPane = m_dwLong / 1000;
		m_strUnitLong = _T("ms");
	}
	else if ( m_dwLong >= 1000000 && m_dwLong <= 4000000000 ) {
		m_dwLongPane = m_dwLong / 1000000;
		m_strUnitLong = _T("s");
	}
	else {
		ASSERT(FALSE);
	}
		
	// Change time & unit of SHORT.
	if ( m_dwShort >= 0 && m_dwShort < 1000 ) {
		m_dwShortPane = m_dwShort;
		m_strUnitShort = _T("us");
	}
	else if ( m_dwShort >= 1000 && m_dwShort < 1000000 ) {
		m_dwShortPane = m_dwShort / 1000;
		m_strUnitShort = _T("ms");
	}
	else if ( m_dwShort >= 1000000 && m_dwShort <= 1000000000 ) {
		m_dwShortPane = m_dwShort / 1000000;
		m_strUnitShort = _T("s");
	}
	else {
		ASSERT(FALSE);
	}
}

void CSpaExecutionTimePage::StopTimerAction(void)
{
	// Kill timer.
	if ( 0 != m_uTimerID ) {
		KillTimer(m_uTimerID);
		m_uTimerID = 0;
	}

	// Grayed some controls.
	m_bStop = TRUE;
	DisableControl();
}

void CSpaExecutionTimePage::UpdateCountBar(int nWhich, BOOL bRedraw)
{
	// Assign a static control.
	CWnd* pWnd;
	int nPercent;
	switch ( nWhich ) {
		case 1:
			pWnd = &m_staticCountBar1;
			nPercent = m_nCountPer1;
			break;
		case 2:
			pWnd = &m_staticCountBar2;
			nPercent = m_nCountPer2;
			break;
		case 3:
			pWnd = &m_staticCountBar3;
			nPercent = m_nCountPer3;
			break;
		case 4:
			pWnd = &m_staticCountBar4;
			nPercent = m_nCountPer4;
			break;
		case 5:
			pWnd = &m_staticCountBar5;
			nPercent = m_nCountPer5;
			break;
		case 6:
			pWnd = &m_staticCountBar6;
			nPercent = m_nCountPer6;
			break;
		case 7:
			pWnd = &m_staticCountBar7;
			nPercent = m_nCountPer7;
			break;
		case 8:
			pWnd = &m_staticCountBar8;
			nPercent = m_nCountPer8;
			break;
		case 9:
			pWnd = &m_staticCountBar9;
			nPercent = m_nCountPer9;
			break;
		case 10:
			pWnd = &m_staticCountBar10;
			nPercent = m_nCountPer10;
			break;
		default:
			ASSERT(FALSE);
			return;
	}

	// No change.
	if ( 0 == nPercent && bRedraw ) {
		return;
	}

	// Update timer bar.
	CDC* pDC = pWnd->GetDC();

	CBrush brushGray(RGB(192,192,192));
	CBrush* pBrushOld = pDC->SelectObject(&brushGray);
	CRect rect;
	pWnd->GetClientRect(rect);
	rect.left += 1;
	rect.top += 1;
	rect.right -= 1;
	rect.bottom -= 1;
	pDC->FillRect(rect, &brushGray);
	pDC->SelectObject(pBrushOld);
	
	if ( bRedraw ) {
		CBrush brushRed(RGB(255,0,0));
		pBrushOld = pDC->SelectObject(&brushRed);
		rect.right = rect.right * nPercent / 100;
		rect.right =  rect.right <= rect.left ? rect.left + 1 : rect.right;
		pDC->FillRect(rect, &brushRed);
		pDC->SelectObject(pBrushOld);

		// Set percentage.
		CString strPer;
		strPer.Format("%d %%", nPercent);
		pDC->SetTextColor(RGB(0,0,0));
		pDC->SetBkMode(TRANSPARENT);
		pWnd->GetClientRect(rect);
		pDC->TextOut(rect.Width()/2-12, 2, strPer);
	}

	pWnd->ReleaseDC(pDC);
}

void CSpaExecutionTimePage::DisableControl(void)
{
	// Enable / disable buttons.
	m_btnRestart.EnableWindow(m_bStop);
	m_btnStart.EnableWindow(m_bStop);
	m_btnEdit.EnableWindow(m_bStop);
	m_btnBp.EnableWindow(m_bStop);
	m_editBp.EnableWindow(m_bStop);

	m_btnStop.EnableWindow(!m_bStop);
	
	// Enable combo boxes.
	m_comboRange1.EnableWindow(m_bStop);

	// Enable ESC to cancel this page.
	SetFocus();
}

void CSpaExecutionTimePage::GetExecuteRange()
{
	// Get start address.
	char szPC[33+1];
	UINT uPC;
	CString strPC;
	int nBank;

	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();

	switch ( m_nWhichBtn ) {
		case btnStart:
			// Get the current PC bank
			nBank = ::GetPCBank();
			if ( ::SPACE_PROGRAME == nBank ) {
				strPC = "P:";
			}
			else {
				itoa(nBank-::SPACE_BANK1, szPC, 10);
				strPC = 'P';
				strPC += szPC;
				strPC += ':';
			}
			// Get the current PC
			::AbiGetOneReg(0, &uPC);
			ultoa(uPC, szPC, 16);
			strPC += szPC;
			break;
		case btnRestart:
			// Get the old PC bank
			if ( ::SPACE_PROGRAME == pSheet->m_nBank ) {
				strPC = "P:";
			}
			else {
				itoa(pSheet->m_nBank-::SPACE_BANK1, szPC, 10);
				strPC = 'P';
				strPC += szPC;
				strPC += ':';
			}
			// Get the old PC
			ultoa(pSheet->m_uPC, szPC, 16);
			strPC += szPC;
			break;
		default:
			ASSERT(FALSE);
			return;
	}
	
	// Get the end BP.
	pSheet->m_strStart = strPC;
	pSheet->m_strEnd = m_strRange0;
}

BOOL CSpaExecutionTimePage::SetEntryData(void)
{
	// Initial when restart.
	memset(&m_EntryInfo, 0, sizeof(m_EntryInfo));
	memset(&m_Addr, 0, sizeof(m_Addr));

	// Convert input data.
	::ADDRESS Addr;
	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
	pSheet->EmptyBuffer();

	// Convert execution range.
	GetExecuteRange();
	if ( pSheet->m_strStart.IsEmpty() ) {
		pSheet->m_nErrorID = pSheet->errInput;
		pSheet->DisplayErrorMessage();
		return FALSE;
	}

	if ( pSheet->m_strEnd.IsEmpty() ) {
		if ( !pSheet->IsValidAddr(pSheet->m_strStart) ) {
			pSheet->m_nErrorID = pSheet->errInput;
			pSheet->DisplayErrorMessage();
			return FALSE;
		}
		else {
			::AdrShellToAddr(pSheet->m_strStart, Addr, ::SPACE_PROGRAME);
			m_EntryInfo.goArgument.addrFrom.addr = (WORD&)(Addr.adrAddress);
			m_EntryInfo.goArgument.addrFrom.addrType = (FLAG&)Addr.adrSpace;
			m_EntryInfo.goArgument.addrTo.addrType = ::MEM_UNDEFINED;
		}
	}
	else {
		if ( !pSheet->IsValidAddr(pSheet->m_strStart) ||
			 !pSheet->IsValidAddr(pSheet->m_strEnd) ) {
			pSheet->m_nErrorID = pSheet->errInput;
			pSheet->DisplayErrorMessage();
			return FALSE;
		}
		else {
			::AdrShellToAddr(pSheet->m_strStart, Addr, ::SPACE_PROGRAME);
			m_EntryInfo.goArgument.addrFrom.addr = (WORD&)(Addr.adrAddress);
			m_EntryInfo.goArgument.addrFrom.addrType = (FLAG&)Addr.adrSpace;
			::AdrShellToAddr(pSheet->m_strEnd, Addr, ::SPACE_PROGRAME);
			m_EntryInfo.goArgument.addrTo.addr = (WORD&)(Addr.adrAddress);
			m_EntryInfo.goArgument.addrTo.addrType = (FLAG&)Addr.adrSpace;
		}
	}
	
	// Convert Module 1 range.
	pSheet->EmptyBuffer();
	ReadRecord(entryRange, m_strRange1);
	if ( pSheet->m_strStart.IsEmpty() ) {
		pSheet->m_nErrorID = pSheet->errInput;
		pSheet->DisplayErrorMessage();
		return FALSE;
	}
	else {
		if ( !pSheet->IsValidAddr(pSheet->m_strStart) ||
			 !pSheet->IsValidAddr(pSheet->m_strEnd) ) {
			pSheet->m_nErrorID = pSheet->errInput;
			pSheet->DisplayErrorMessage();
			return FALSE;
		}
		else {
			::AdrShellToAddr(pSheet->m_strStart, Addr, ::SPACE_PROGRAME);
			m_Addr[0].addrType = (FLAG&)Addr.adrSpace;
			m_Addr[0].addr = (unsigned short&)(Addr.adrAddress);
			m_EntryInfo.usAddr[m_EntryInfo.uchNumber] = m_Addr[0].addr;
			m_EntryInfo.bType[m_EntryInfo.uchNumber++] = m_Addr[0].addrType;

			::AdrShellToAddr(pSheet->m_strEnd, Addr, ::SPACE_PROGRAME);
			m_Addr[1].addrType = (FLAG&)Addr.adrSpace;
			m_Addr[1].addr = (unsigned short&)(Addr.adrAddress);
			m_EntryInfo.usAddr[m_EntryInfo.uchNumber] = m_Addr[1].addr;
			m_EntryInfo.bType[m_EntryInfo.uchNumber++] = m_Addr[1].addrType;
		}
	}
	
	// Call ABI routine.
	if ( ::ICE_OK != ::AbiSpaBpSet(m_EntryInfo) ) {
		pSheet->m_nErrorID = pSheet->errAbi;
		pSheet->DisplayErrorMessage();
		return FALSE;
	}

	return TRUE;
}

BOOL CSpaExecutionTimePage::GetEntryData(void)
{
	// Call ABI routine.
	UINT uPC;

	int nStatus = ::AbiGetOneReg(0, &uPC);

	// EP Running.
	if ( ::ICE_EP_RUNNING == nStatus ) {
		return running;
	}

	// Till end.
	if ( ::GetPCBank() == m_EntryInfo.goArgument.addrTo.addrType &&
		 uPC == m_EntryInfo.goArgument.addrTo.addr ) {
		if ( module1 == m_nWhichModule ) {
			::TIMER_COUNT Timer;
			if ( ::ICE_OK == ::AbiGetTimerCount(&Timer) ) {
				unsigned long ul = Timer.ulLowCount;
				m_dwTime = ( 0 == ul ) ? m_cdwMaxTime : ul;
				AssignTimeCount();
			}
			else {
				return failure;
			}
		}

		if ( !CalcResult() ) {
			return failure;
		}
		else {
			return stop;
		}
	}

	// Pause.
	if ( uPC == m_Addr[0].addr && ::GetPCBank() == m_Addr[0].addrType ) {
		m_nWhichModule = module1;
	}
	else if ( uPC == m_Addr[1].addr && ::GetPCBank() == m_Addr[1].addrType ) {
		if ( module1 == m_nWhichModule ) {
			::TIMER_COUNT Timer;
			if ( ::ICE_OK == ::AbiGetTimerCount(&Timer) ) {
				unsigned long ul = Timer.ulLowCount;
				m_dwTime = ( 0 == ul ) ? m_cdwMaxTime : ul;
				AssignTimeCount();
			}
			else {
				return failure;
			}
		}
		m_nWhichModule = module0;
	}
	else {
//	    ASSERT(FALSE);	// Assertion will be caused by HALT.
//		return failure;
		return stop;
	}

	// Calculate result.
	if ( !CalcResult() ) {
		return failure;
	}

	return pause;
}

void CSpaExecutionTimePage::AssignTimeCount(void)
{
	// Assign the time count according to the time paragraph.
	if ( m_dwTime >= 0 && m_dwTime <= 10 ) {
		m_dwCount1++;
	}
	else if ( m_dwTime > 10 && m_dwTime <= 100 ) {
		m_dwCount2++;
	}
	else if ( m_dwTime > 100 && m_dwTime <= 1000 ) {
		m_dwCount3++;
	}
	else if ( m_dwTime > 1000 && m_dwTime <= 10000 ) {
		m_dwCount4++;
	}
	else if ( m_dwTime > 10000 && m_dwTime <= 100000 ) {
		m_dwCount5++;
	}
	else if ( m_dwTime > 100000 && m_dwTime <= 1000000 ) {
		m_dwCount6++;
	}
	else if ( m_dwTime > 1000000 && m_dwTime <= 10000000 ) {
		m_dwCount7++;
	}
	else if ( m_dwTime > 10000000 && m_dwTime <= 100000000 ) {
		m_dwCount8++;
	}
	else if ( m_dwTime > 100000000 && m_dwTime <= 1000000000 ) {
		m_dwCount9++;
	}
	else {
		m_dwCount10++;
	}

	if ( 0 == m_dwShort ) {
		m_dwShort = m_dwTime;
	}
	else {
		m_dwShort = min(m_dwTime, m_dwShort);
	}
	m_dwLong = max(m_dwTime, m_dwLong);
}

BOOL CSpaExecutionTimePage::CalcResult(void)
{
	// Calculate the count.
	if ( !CalcCount() ) {
		return FALSE;
	}

/*
	// Calculate the longest & shortest.
	if ( !CalcLimit() ) {
		return FALSE;
	}
*/

	return TRUE;
}

BOOL CSpaExecutionTimePage::CalcCount(void)
{
	// Adjust count range.
	if ( m_dwCount1 > m_cnMaxCount || 
		 m_dwCount2 > m_cnMaxCount || 
		 m_dwCount3 > m_cnMaxCount ||
		 m_dwCount4 > m_cnMaxCount ||
		 m_dwCount5 > m_cnMaxCount ||
		 m_dwCount6 > m_cnMaxCount ||
		 m_dwCount7 > m_cnMaxCount ||
		 m_dwCount8 > m_cnMaxCount ||
		 m_dwCount9 > m_cnMaxCount ||
		 m_dwCount10 > m_cnMaxCount ) {
		return FALSE;
	}

	m_dwTotal = m_dwCount1 + m_dwCount2 + m_dwCount3 + m_dwCount4 + m_dwCount5 +
			   m_dwCount6 + m_dwCount7 + m_dwCount8 + m_dwCount9 + m_dwCount10;
	if ( m_dwTotal > m_cnMaxCount * 100 ) {
		return FALSE;
	}

	// Calculate the count percentage.
	if ( 0 == m_dwTotal ) {
		m_nCountPer1 = 0;
		m_nCountPer2 = 0;
		m_nCountPer3 = 0;
		m_nCountPer4 = 0;
		m_nCountPer5 = 0;
		m_nCountPer6 = 0;
		m_nCountPer7 = 0;
		m_nCountPer8 = 0;
		m_nCountPer9 = 0;
		m_nCountPer10 = 0;
	}
	else {
		m_nCountPer1 = int(m_dwCount1 * 100 / m_dwTotal);
		m_nCountPer2 = int(m_dwCount2 * 100 / m_dwTotal);
		m_nCountPer3 = int(m_dwCount3 * 100 / m_dwTotal);
		m_nCountPer4 = int(m_dwCount4 * 100 / m_dwTotal);
		m_nCountPer5 = int(m_dwCount5 * 100 / m_dwTotal);
		m_nCountPer6 = int(m_dwCount6 * 100 / m_dwTotal);
		m_nCountPer7 = int(m_dwCount7 * 100 / m_dwTotal);
		m_nCountPer8 = int(m_dwCount8 * 100 / m_dwTotal);
		m_nCountPer9 = int(m_dwCount9 * 100 / m_dwTotal);
		m_nCountPer10 = int(m_dwCount10 * 100 / m_dwTotal);
	}

	if ( m_nCountPer1 < 0 || 
		 m_nCountPer2 < 0 || 
		 m_nCountPer3 < 0 ||
		 m_nCountPer4 < 0 ||
		 m_nCountPer5 < 0 ||
		 m_nCountPer6 < 0 ||
		 m_nCountPer7 < 0 ||
		 m_nCountPer8 < 0 ||
		 m_nCountPer9 < 0 ||
		 m_nCountPer10 < 0 ) {
		return FALSE;
	}

	if ( m_nCountPer1 > 100 || 
		 m_nCountPer2 > 100 || 
		 m_nCountPer3 > 100 || 
		 m_nCountPer4 > 100 || 
		 m_nCountPer5 > 100 || 
		 m_nCountPer6 > 100 || 
		 m_nCountPer7 > 100 || 
		 m_nCountPer8 > 100 || 
		 m_nCountPer9 > 100 || 
		 m_nCountPer10 > 100 ) {
		return FALSE;
	}

	if ( 0 == m_nCountPer1 && 0 != m_dwCount1 ) {
		m_nCountPer1 = 1;
	}
	if ( 0 == m_nCountPer2 && 0 != m_dwCount2 ) {
		m_nCountPer2 = 1;
	}
	if ( 0 == m_nCountPer3 && 0 != m_dwCount3 ) {
		m_nCountPer3 = 1;
	}
	if ( 0 == m_nCountPer4 && 0 != m_dwCount4 ) {
		m_nCountPer4 = 1;
	}
	if ( 0 == m_nCountPer5 && 0 != m_dwCount5 ) {
		m_nCountPer5 = 1;
	}
	if ( 0 == m_nCountPer6 && 0 != m_dwCount6 ) {
		m_nCountPer6 = 1;
	}
	if ( 0 == m_nCountPer7 && 0 != m_dwCount7 ) {
		m_nCountPer7 = 1;
	}
	if ( 0 == m_nCountPer8 && 0 != m_dwCount8 ) {
		m_nCountPer8 = 1;
	}
	if ( 0 == m_nCountPer9 && 0 != m_dwCount9 ) {
		m_nCountPer9 = 1;
	}
	if ( 0 == m_nCountPer10 && 0 != m_dwCount10 ) {
		m_nCountPer10 = 1;
	}

	return TRUE;
}

BOOL CSpaExecutionTimePage::CalcLimit(void)
{
/*
	// Get the shortest duration.
	if ( m_dwCount1 > 0 ) {
		m_strShort = " ~ 10us";
	}
	else if ( m_dwCount2 > 0 ) {
		m_strShort = "10us ~ 100us";
	}
	else if ( m_dwCount3 > 0 ) {
		m_strShort = "100us ~ 1ms";
	}
	else if ( m_dwCount4 > 0 ) {
		m_strShort = "1ms ~ 10ms";
	}
	else if ( m_dwCount5 > 0 ) {
		m_strShort = "10ms ~ 100ms";
	}
	else if ( m_dwCount6 > 0 ) {
		m_strShort = "100ms ~ 1s";
	}
	else if ( m_dwCount7 > 0 ) {
		m_strShort = "1s ~ 10s";
	}
	else if ( m_dwCount8 > 0 ) {
		m_strShort = "10s ~ 100s";
	}
	else if ( m_dwCount9 > 0 ) {
		m_strShort = "100s ~ 1000s";
	}
	else if ( m_dwCount10 > 0 ) {
		m_strShort = "1000s ~ ";
	}
	else {
		return TRUE;
	}
		
	// Get the longest duration.
	if ( m_dwCount10 > 0 ) {
		m_strLong = "1000s ~ ";
	}
	else if ( m_dwCount9 > 0 ) {
		m_strLong = "100s ~ 1000s";
	}
	else if ( m_dwCount8 > 0 ) {
		m_strLong = "10s ~ 100s";
	}
	else if ( m_dwCount7 > 0 ) {
		m_strLong = "1s ~ 10s";
	}
	else if ( m_dwCount6 > 0 ) {
		m_strLong = "100ms ~ 1s";
	}
	else if ( m_dwCount5 > 0 ) {
		m_strLong = "10ms ~ 100ms";
	}
	else if ( m_dwCount4 > 0 ) {
		m_strLong = "1ms ~ 10ms";
	}
	else if ( m_dwCount3 > 0 ) {
		m_strLong = "100us ~ 1ms";
	}
	else if ( m_dwCount2 > 0 ) {
		m_strLong = "10us ~ 100us";
	}
	else if ( m_dwCount1 > 0 ) {
		m_strLong = " ~ 10us";
	}

    // Update data.
	m_editShort.SetWindowText(m_strShort);
	m_editLong.SetWindowText(m_strLong);
*/
		
	return TRUE;
}

void CSpaExecutionTimePage::UpdateCombo(void)
{
	// Remove all from the combo boxes.
	m_comboRange1.ResetContent();
	
	// Clear all of the edit control.
	m_strRange1 = _T("");

	// Read user defined name.
	ReadRecord(entryRange, combo1);

/*
	// Add an empty string to the combo boxes.
	m_comboRange1.AddString("");
*/

	// Select the default setting.
	int nCount = m_comboRange1.GetCount();
	if ( CB_ERR != nCount && nCount > 0 ) {
		m_comboRange1.GetLBText(0, m_strRange1);
	}
}

void CSpaExecutionTimePage::ReadRecord(int nWhichFile, int nWhichCombo)
{
	// Read from the record file.
	CString strFile(::szAppPath);
	switch ( nWhichFile ) {
//		case executionRange:
//			strFile += "SPA\\execute.dbf";
//			break;
		case entryRange:
			strFile += "SPA\\entry.dbf";
			break;
		default:
			ASSERT(FALSE);
			return;
	}

	// Assign the open flag.
    CFileStatus status;
	if ( !CFile::GetStatus(strFile, status) ) {
		return;
	}

	// Open the record file.
	UINT nOpenFlag = CFile::modeRead | CFile::typeText;
	CStdioFile* fp = new CStdioFile(strFile, nOpenFlag);
	
	// Read from the record file.
	int nMax = defineLen+startLen+endLen;
	char* pszLine = new char[nMax+4];
	while ( fp->ReadString(pszLine, nMax) ) {
		// Split string.
		char* p = pszLine;
		while ( *p ) {
			if ( '\n' == *p ) {
				*p = NULL;
				break;
			}
			p++;
		}
		CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
		pSheet->EmptyBuffer();
		pSheet->SplitRecord(CString(pszLine));
		CString strDefine(pSheet->m_strDefine);
		if ( pSheet->m_strEnd.IsEmpty() ) {
			continue;
		}
		switch ( nWhichCombo ) {
			case combo1:
				m_comboRange1.AddString(strDefine);
				break;
			default:
				ASSERT(FALSE);
				break;
		}
	}
	delete []pszLine;
	
	// Close the record file.
	fp->Close();
	delete fp;
}

void CSpaExecutionTimePage::ReadRecord(int nWhichFile, const CString& strDefine)
{
	// Read from the record file.
	CString strFile(::szAppPath);
	switch ( nWhichFile ) {
//		case executionRange:
//			strFile += "SPA\\execute.dbf";
//			break;
		case entryRange:
			strFile += "SPA\\entry.dbf";
			break;
		default:
			ASSERT(FALSE);
			return;
	}

	// Assign the open flag.
    CFileStatus status;
	if ( !CFile::GetStatus(strFile, status) ) {
		return;
	}

	// Open the record file.
	UINT nOpenFlag = CFile::modeRead | CFile::typeText;
	CStdioFile* fp = new CStdioFile(strFile, nOpenFlag);
	
	// Read from the record file.
	int nMax = defineLen+startLen+endLen;
	char* pszLine = new char[nMax+4];
	while ( fp->ReadString(pszLine, nMax) ) {
		// Split string.
		char* p = pszLine;
		while ( *p ) {
			if ( '\n' == *p ) {
				*p = NULL;
				break;
			}
			p++;
		}
		CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
		pSheet->SplitRecord(CString(pszLine));
		if ( !pSheet->m_strEnd.IsEmpty() && 
			 strDefine == pSheet->m_strDefine ) {
			break;
		}
		pSheet->EmptyBuffer();
	}
	delete []pszLine;
		
	// Close the record file.
	fp->Close();
	delete fp;
}

void CSpaExecutionTimePage::ClearResult(void)
{
	// Initial the result variables.
	m_dwCount1 = 0;
	m_dwCount2 = 0;
	m_dwCount3 = 0;
	m_dwCount4 = 0;
	m_dwCount5 = 0;
	m_dwCount6 = 0;
	m_dwCount7 = 0;
	m_dwCount8 = 0;
	m_dwCount9 = 0;
	m_dwCount10 = 0;

	m_dwTotal = 0;

	m_nCountPer1 = 0;
	m_nCountPer2 = 0;
	m_nCountPer3 = 0;
	m_nCountPer4 = 0;
	m_nCountPer5 = 0;
	m_nCountPer6 = 0;
	m_nCountPer7 = 0;
	m_nCountPer8 = 0;
	m_nCountPer9 = 0;
	m_nCountPer10 = 0;
	
	m_dwTime = 0;
	m_dwLong = 0;
	m_dwShort = 0;

	m_strUnitLong = _T("us");
	m_strUnitShort = _T("us");

	// Update count bar.
	for ( int i(1); i <= 10; i++ ) {
		UpdateCountBar(i, FALSE);
	}
}

/////////////////////////////////////////////////////////////////////////////
// CSpaExecutionTimePage message handlers

BOOL CSpaExecutionTimePage::OnKillActive()
{
	// TODO: Add your message handler code here

	// Disabled when running.
	if ( !m_bStop ) {
		return FALSE;
	}

	return CPropertyPage::OnKillActive();
}

BOOL CSpaExecutionTimePage::OnSetActive()
{
	// TODO: Add your message handler code here

	// Set the help ID.
	m_nIDHelp = IDD_SPA_TIME;

	// Set timer to update the graph bar.
 	m_uTimerID = SetTimer(tmEvent, tmElapse, NULL);

	return CPropertyPage::OnSetActive();
}

void CSpaExecutionTimePage::OnHelp()
{
	// TODO: Add your control notification handler code here
	
	// Active the dialog Help function.
	OnCommandHelp(0, 0);
}

void CSpaExecutionTimePage::OnButtonSpaTimeEdit()
{
	// TODO: Add your control notification handler code here
	
	// Open the user defined dialog.
	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
	CSpaUserDefineDlg dlg(pSheet);
	dlg.DoModal();

	// Update current selection.
	BeginWaitCursor();

	UpdateData();

	UpdateCombo();

	UpdateData(FALSE);

	EndWaitCursor();
}

void CSpaExecutionTimePage::OnButtonSpaTimeStart()
{
	// TODO: Add your control notification handler code here
	
	// Clear current result.
	UpdateData();
    if ( btnRestart == m_nWhichBtn ) {
		ClearResult();
	}

    // Check the control syntax.
	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
    CheckInputSyntax();
    if ( pSheet->errOK != pSheet->m_nErrorID ) {
		pSheet->DisplayErrorMessage();
    	return;
    }

	// Set entry data.
    if ( !SetEntryData() ) {
    	return;
    }

	// Grayed the some controls.
	m_bStop = FALSE;
	DisableControl();
	
	// Set timer.
	if ( 0 != m_uTimerID ) {
		// If outstanding timer, kill it.
		KillTimer(m_uTimerID);
	}
 	// Set a timer for 200 milliseconds.
 	m_uTimerID = SetTimer(tmEvent, tmElapse, NULL);
	if ( 0 == m_uTimerID ) {
		pSheet->m_nErrorID = pSheet->errTimer;
		pSheet->DisplayErrorMessage();
		return;
	}

    UpdateData(FALSE);
}

void CSpaExecutionTimePage::OnButtonSpaTimeStop()
{
	// TODO: Add your control notification handler code here
	
	// Kill one-shot timer.
	if ( 0 != m_uTimerID ) {
		KillTimer(m_uTimerID);
		m_uTimerID = 0;
	
		// Abort EP.
		AbiAbort();

		// Update graph bar.
		UpdateBar();
	}
    
	// Grayed some controls.
	m_bStop = TRUE;
	DisableControl();
}

void CSpaExecutionTimePage::OnOK()
{
	// TODO: Add extra cleanup here

	// Don't close the sheet.
	((CSpaGroupSheet*)GetParent())->SetModeless(TRUE);
}
	
void CSpaExecutionTimePage::OnCancel()
{
	// TODO: Add extra cleanup here
	
	// Kill one-shot timer.
	if ( 0 != m_uTimerID ) {
		KillTimer(m_uTimerID);
	}

	// Restore HW configuration.
	BeginWaitCursor();

	::AbiAbort();
	::AbiClrAllBp();
	::RestoreAllConfig();

	EndWaitCursor();


	// Close the whole group.
	((CSpaGroupSheet*)GetParent())->SetModeless(FALSE);
	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
	if ( pSheet->IsKindOf(RUNTIME_CLASS(CSpaGroupSheet)) ) {
		pSheet->EndDialog(IDCANCEL);
	}
	else {
		CPropertyPage::OnCancel();
	}
}

void CSpaExecutionTimePage::OnShowWindow(BOOL bShow, UINT nStatus)
{
	CPropertyPage::OnShowWindow(bShow, nStatus);
	
	// TODO: Add your message handler code here
	
	// The window is being shown.
	if ( TRUE == bShow ) {
		// Grayed some controls.
		m_bStop = TRUE;
		DisableControl();
		
		// Update current selection.
		BeginWaitCursor();
	
		UpdateData();
	
		UpdateCombo();

		UpdateData(FALSE);
	
		EndWaitCursor();
	}
}

void CSpaExecutionTimePage::OnTimer(UINT nIDEvent)
{
	// TODO: Add your message handler code here and/or call default
	
	// Added by John.
	if(!(GetXviewAppJohn()->m_bCanTimer)) return; //the abi communication is on

	// Not our timer.
	if ( m_uTimerID != nIDEvent ) {
		CPropertyPage::OnTimer(nIDEvent);
		return;
	}
    
	// Update graph bar.
	if ( !m_bStop ) {
		UpdateBar();
	}
	else {
		// Kill the timer.
		KillTimer(m_uTimerID);
		m_uTimerID = 0;

		// Update count bar.
		for ( int i(1); i <= 10; i++ ) {
			UpdateCountBar(i);
		}
	}
}

void CSpaExecutionTimePage::OnButtonSpaTimeRestart() 
{
	// TODO: Add your control notification handler code here

	// As same as OnStart.
    m_nWhichBtn = btnRestart;
	OnButtonSpaTimeStart();
	m_nWhichBtn = btnStart;
}

void CSpaExecutionTimePage::OnButtonSpaBp() 
{
	// TODO: Add your control notification handler code here
	
	// Open the BP set dialog.
	UpdateData();

	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
	CSpaBpSetDlg dlg(pSheet);
	if ( IDOK == dlg.DoModal() ) {
		m_strRange0 = dlg.m_strBp;
	}

	UpdateData(FALSE);
}
