// Timers.cpp : implementation file
//
#include "stdafx.h"
#include "PICCPC.h"
#include "Timers.h"
#include <math.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CTimers property page
IMPLEMENT_DYNCREATE(CTimers, CPropertyPage)
CTimers::CTimers() : CPropertyPage(CTimers::IDD)
{
//{{AFX_DATA_INIT(CTimers)
m_iWDTTimeout = -1;
m_dwT0Freq = 32768;
m_dDesiredOverflow = 0.0;
//}}AFX_DATA_INIT
}
CTimers::~CTimers()
{
}
void CTimers::DoDataExchange(CDataExchange* pDX)
{
CPropertyPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CTimers)
DDX_Control(pDX, IDC_T0_RESOLUTION, m_cT0Resolution);
DDX_CBIndex(pDX, IDC_WDTTIMEOUTS, m_iWDTTimeout);
DDX_Text(pDX, IDC_T0CKI_FREQ, m_dwT0Freq);
DDV_MinMaxDWord(pDX, m_dwT0Freq, 1, 1000000000);
DDX_Text(pDX, IDC_T0_COUNTER, m_dDesiredOverflow);
DDX_Control(pDX, IDC_T0CKI_OVERFLOW, m_sInfo);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CTimers, CPropertyPage)
//{{AFX_MSG_MAP(CTimers)
ON_BN_CLICKED(IDC_T0CS1, OnT0cs1)
ON_BN_CLICKED(IDC_T0CS2, OnT0cs2)
ON_BN_CLICKED(IDC_T0CS3, OnT0cs3)
ON_EN_CHANGE(IDC_T0CKI_FREQ, OnChangeT0ckiFreq)
ON_BN_CLICKED(IDC_T0_USEPRESCALER, OnT0Useprescaler)
ON_CBN_SELCHANGE(IDC_T0_RESOLUTION, OnSelchangeT0Resolution)
ON_CBN_EDITCHANGE(IDC_WDTTIMEOUTS, OnEditchangeWdttimeouts)
ON_EN_CHANGE(IDC_T0_COUNTER, OnChangeT0Counter)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
CTimers::UpdateT0CKIFreq( BOOL bEnable ) {
CString s;
s.Format( "%u", PICInfo.dwT0Freq );
SetDlgItemText( IDC_T0CKI_FREQ, s );
GetDlgItem(IDC_T0CKI_FREQ)->EnableWindow( bEnable );
}
CTimers::UpdateT0ResolutionList() {
CString s;
int k = 1;
double fv;
if ( PICInfo.sfr.OPTION&0x20 ) {
fv = GetT0ExtResolution()*1e3;
}
else {
fv = m_dT0MCUResolution*1e3;
}
m_cT0Resolution.ResetContent();
if ( !(PICInfo.sfr.OPTION&0x08) ) { //prescaler is asigned to TMR0
((CComboBox*)GetDlgItem(IDC_WDTTIMEOUTS))->SetCurSel( 0 );
((CComboBox*)GetDlgItem(IDC_WDTTIMEOUTS))->EnableWindow( FALSE );
for ( int i=1;i<9;i++ ) {
fv *= (k*2);
s.Format( "%G", fv );
m_cT0Resolution.AddString( s );
}
m_cT0Resolution.SetCurSel( PICInfo.sfr.OPTION&0x07 );
OnSelchangeT0Resolution();
}
else { //prescaler is asigned to WDT
((CComboBox*)GetDlgItem(IDC_WDTTIMEOUTS))->EnableWindow();
s.Format( "%G", fv );
m_cT0Resolution.AddString( s );
m_cT0Resolution.SetCurSel( 0 );
((CComboBox*)GetDlgItem(IDC_WDTTIMEOUTS))->SetCurSel( PICInfo.sfr.OPTION&0x07 );
}
}
double CTimers::GetT0ExtResolution() {
if ( !UpdateData() )
return 0.0;
return 1.0/m_dwT0Freq;
}
/////////////////////////////////////////////////////////////////////////////
// CTimers message handlers
CTimers::UpdateOPTION( BYTE mask, BYTE value ) {
PICInfo.sfr.OPTION &= mask;
PICInfo.sfr.OPTION |= value;
}
BOOL CTimers::OnKillActive()
{
if ( !CPropertyPage::OnKillActive() )
return FALSE;
if ( PICInfo.sfr.OPTION&0x08 ) {
UpdateOPTION( 0xF8, ((CComboBox*)GetDlgItem(IDC_WDTTIMEOUTS))->GetCurSel() );
}
else {
UpdateOPTION( 0xF8, ((CComboBox*)GetDlgItem(IDC_T0_RESOLUTION))->GetCurSel() );
}
PICInfo.sfr.INTCON &= 0xDF;
PICInfo.sfr.INTCON |= (IsDlgButtonChecked(IDC_T0_INTEN)<<5);
return TRUE;
}
BOOL CTimers::OnSetActive()
{
// update timer0
m_dT0MCUResolution = PICInfo.dInstructionTime;
CheckDlgButton( IDC_T0_INTEN, PICInfo.sfr.INTCON&0x20 );
CheckDlgButton( IDC_T0_USEPRESCALER, !(PICInfo.sfr.OPTION&0x08) );
switch( PICInfo.sfr.OPTION&0x30 ) {
case 0x30:
CheckRadioButton( IDC_T0CS1, IDC_T0CS3, IDC_T0CS2 );
OnT0cs2();
break;
case 0x20:
CheckRadioButton( IDC_T0CS1, IDC_T0CS3, IDC_T0CS3 );
OnT0cs3();
break;
default:
CheckRadioButton( IDC_T0CS1, IDC_T0CS3, IDC_T0CS1 );
OnT0cs1();
}
return CPropertyPage::OnSetActive();
}
void CTimers::OnT0cs1()
{
PICInfo.sfr.OPTION &= 0xDF;
PICInfo.dwT0Freq = PICInfo.dwOSCFrequency>>2;
UpdateT0CKIFreq( FALSE );
UpdateT0ResolutionList();
}
void CTimers::OnT0cs2()
{
PICInfo.sfr.OPTION |= 0x30;
PICInfo.dwT0Freq = m_dwT0Freq;
UpdateT0CKIFreq( TRUE );
UpdateT0ResolutionList();
}
void CTimers::OnT0cs3()
{
PICInfo.sfr.OPTION |= 0x20;
PICInfo.sfr.OPTION &= 0xEF;
PICInfo.dwT0Freq = m_dwT0Freq;
UpdateT0CKIFreq( TRUE );
UpdateT0ResolutionList();
}
void CTimers::OnChangeT0ckiFreq()
{
if ( !UpdateData() )
return;
PICInfo.dwT0Freq = m_dwT0Freq;
UpdateT0ResolutionList();
UpdateT0Interrupt();
}
void CTimers::OnT0Useprescaler()
{
if ( IsDlgButtonChecked(IDC_T0_USEPRESCALER) ) {
PICInfo.sfr.OPTION &= 0xF7;
}
else {
PICInfo.sfr.OPTION |= 0x08;
}
UpdateT0ResolutionList();
}
void CTimers::OnSelchangeT0Resolution()
{
UpdateT0Interrupt();
UpdateOPTION( 0xF8, ((CComboBox*)GetDlgItem(IDC_T0_RESOLUTION))->GetCurSel() );
}
void CTimers::OnEditchangeWdttimeouts()
{
UpdateOPTION( 0xF8, ((CComboBox*)GetDlgItem(IDC_WDTTIMEOUTS))->GetCurSel() );
}
void CTimers::OnChangeT0Counter()
{
if ( !UpdateData() )
return;
UpdateT0Interrupt();
CheckDlgButton( IDC_T0_INTEN, 1 );
}
void CTimers::UpdateT0Interrupt() {
if ( !UpdateData() )
return;
if ( m_dDesiredOverflow < PICInfo.dInstructionTime*50000.0 && m_dDesiredOverflow != 0.0 ) {
m_dDesiredOverflow = PICInfo.dInstructionTime*50000.0;
UpdateData( FALSE );
}
PICInfo.dwT0Offset = 0;
PICInfo.dwT0Counter = 0;
CString s;
GetDlgItemText( IDC_T0_RESOLUTION, s );
double fv = atof( s );
DWORD tmp = (DWORD)(m_dDesiredOverflow/fv);
m_dDesiredOverflow = tmp*fv;
for ( unsigned int i=MAXBYTE+1;i>0;i-- ) {
double y = fv*i;
double f = fmod( m_dDesiredOverflow, y );
double x = fabs(f-y);
if ( f == 0.0 || x<1e-13 ) {
PICInfo.dwT0Offset = MAXBYTE - i + 1;
PICInfo.dwT0Counter = (DWORD)(m_dDesiredOverflow/(fv*i));
if ( !PICInfo.dwT0Counter )
PICInfo.dwT0Counter = 1;
s.Format( "Interrupt every/total:\t%fms, %fms\n"
"Timer offset:\t\t%u\n"
"Timer counter:\t\t%u",
i*fv,
((256-PICInfo.dwT0Offset)*fv)*PICInfo.dwT0Counter,
PICInfo.dwT0Offset,
PICInfo.dwT0Counter );
m_sInfo.SetWindowText( s );
break;
}
}
}