timer.cc
//*************************************************************************
// MODULE : Timer - Module contains high level Timer class definition. *
// AUTHOR : Ron Chernich *
// PURPOSE: Provide body member functions of class to provide interrupt *
// service for timer events, delays, counts. *
// CAUTION: User defined Interrupt service routines require the *
// C/C++ stack probes be disabled on all routines which are or *
// may be used during service. Ensure the appropriate option *
// switch is set (or use MSC #pragma stack_check (off)). *
// HISTORY: *
// 21-JAN-93 First (MSC/C++ 7.00) version *
// 08-APR-93 Start/Stop added and GetTicks adjusted for 1mS (hah!) *
// 27-OCT-93 Smart pointer hiding added (mouse int, fn 16) *
// 30-OCT-93 Massive simplification through the PAL abstraction module *
// 04-FEB-94 "Tock" size changed to 32 bits *
//*************************************************************************
#include "timer.hh"
///////////////////
// NOTE: Because declaring a static class data member does "define" it,
// actual allocation of storage must take place elsewhere.. this is where.
//
UINT32 Timer::nTocks;
//////////////////////////////////////////////////////////////////////////
// The entire class member code for "Timer" is somewhat platform dependant
// so it is isolated here for convenience.
//
#if defined (_DOS_ENV) || defined (UNIX)
/////////////////
// Constructor for Timer class grabs the DOS 0x1C interrupt so that we can
// get called every 18.2 mS, thereabouts..
//
Timer::Timer () : mTicks(0L)
{
nTocks = 0;
nSenCnt = 0;
PalInitClk();
OldRTC = PalGetVec(_DOS_RTC);
PalSetVec(_DOS_RTC, (UINT32)NewRTC);
}
//////////////////////
// The destructor must replace the 0x1C vector..
//
Timer::~Timer ()
{
PalResetClk();
PalSetVec(_DOS_RTC, OldRTC);
}
/////////////////////
// This is the interrupt service routine. On each interrupt, a private
// count is incremented and the BIOS keyboard buffer is emptied by our
// keyboard class object. There as Yet Another Problem with Borland's
// compiler.. can't take the address of a private member as an ISR
// (needless to say, MSCV7 can), so I've made it a friend.
//
#pragma check_stack (off)
extern Kbd KbdIn;
void INTERRUPT NewRTC (__CPPARGS)
{
++Timer::nTocks;
KbdIn.KeyFill();
}
#pragma check_stack (on)
///////////////
// Prepare to track fine timing mechanism. This depwnds on the granularity
// of the implementation. A simple DOS solution (ie no bit-
// twiddling in assembler) will return deci-seconds (10 milli-seconds ticks).
//
// When is called, we store what reports as the current
// mS value. Requests for time used through our member will use
// this to get the number of mS since the timer was (re)started, add this to
// our accumulated "active" time, and return the result. When the timer is
// stopped, we calculate the total time we were active, and update our
// accumulated time.
//
void Timer::Start (void)
{
if (--nSenCnt < 0)
mofs = PalGetTime();
}
///////////////
// You can stop now (see explanation above)..
// The increment protector allows the Animator to stop and start the clock
// without danger regardless of whether it was running in the first place.
//
void Timer::Stop (void)
{
if (++nSenCnt == 0)
mTicks += PalGetTime() - mofs;
}
///////////////
// return 1 millisecond ticks (see explanation above).
// NOTE: Under DOS, this actually return then in blocks of ten!
//
UINT32 Timer::GetTicks (void)
{
return mTicks + PalGetTime() - mofs;
}
///////////////
// return count of 18 millisecond segments ("tocks") since RCOS was
// started. These are used in the supervisor where course timing delays
// are required. Under DOS, it's trivial - elsewhere, do what you must.
//
UINT32 Timer::GetTocks (void)
{
#ifdef _DOS_ENV
return Timer::nTocks;
#endif
#ifdef UNIX
return (mTicks + PalGetTime() - mofs ) * 18;
#endif
}
#endif
/********************************** eof **********************************/