[Back to TSR SWAG index] [Back to Main SWAG index] [Original]
{
> I would like to include a clock in my current project which will be
> updated once a minute. Instead of constantly checking the computer's clock
> and waiting for it to change, I would like to use an interrupt.
This one has even a hot key handler. If you want to update it once per
minute, bump a counter within the interrupt 1Ch handler till it reaches the
value 60*18.2. Then refresh the screen.
}
Program Clock;
{$G+,R-,S-,M 1024, 0, 0 }
uses
Dos;
Const
x = 71; { x location on screen }
y = 1; { y location on screen }
Keyboard = 9; { Hardware keyboard interrupt }
TimerTick = $1C; { Gets called 18.2 / second }
VideoOffset = 160 * (y - 1) + 2 * x;{ Offset in display memory }
yellow = 14;
blue = 1;
attribute = blue * 16 + yellow; { Clock colours }
VideoBase : Word = $B800; { Segment of display memory }
ActiveFlag : ShortInt = -1; { 0: on, -1: off }
Var
OrgInt9, { Saved interrupt 9 vector }
OrgInt1Ch : Pointer; { Saved interrupt 1Ch vector }
VideoMode : Byte absolute $0000:$0449;
{ Display a string using Dos services (avoid WriteLn, save memory) }
Procedure DisplayString(s : String); Assembler;
ASM
PUSH DS
XOR CX, CX
LDS SI, s
LODSB
MOV CL, AL
JCXZ @EmptyString
CLD
@NextChar:
LODSB
XCHG AX, DX
MOV AH, 2
INT 21h
LOOP @NextChar
@EmptyString:
POP DS
end;
{ Returns True if a real time clock could be found }
Function HasRTClock : Boolean; Assembler;
ASM
XOR AL, AL
MOV AH, 2
INT 1Ah
JC @NoRTClock
INC AX
@NoRTCLock:
end;
{ Release Dos environment }
Procedure ReleaseEnvironment; Assembler;
ASM
MOV ES, [PrefixSeg]
MOV ES, ES:[002Ch]
MOV AH, 49h
INT 21h
end;
{ INT 9 handler intercepting Alt-F11 }
Procedure ToggleClock; Interrupt; Assembler;
Const
F11 = $57; { 'F11' make code }
BiosSeg = $40; { Segment of BIOS data area }
AltMask = $08; { Bitmask of Alt key }
KbdFlags = $17; { Byte showing keyboard status }
ASM
STI
IN AL, 60h
{ F11 pressed? }
CMP AL, F11
JNE @PassThru
{ Alt-key pressed? }
PUSH BiosSeg
POP ES
MOV AL, ES:[KbdFlags]
AND AL, AltMask
CMP AL, AltMask
JNE @PassThru
{ Flip status flag, force EOI and leave routine }
NOT [ActiveFlag]
IN AL, 61h
MOV AH, AL
OR AL, 80h
OUT 61h, AL
MOV AL, AH
OUT 61h, AL
CLI
MOV AL, 20h
OUT 20h, AL
STI
JMP @Exit
@PassThru:
CLI
PUSHF
CALL DWord Ptr [OrgInt9]
@Exit:
end; { ToggleClock }
{ Convert a packed BCD byte to ASCII character }
Procedure Digit; Assembler;
ASM
PUSH AX
CALL @HiNibble
POP AX
CALL @LoNibble
RETN
@HiNibble:
SHR AL, 4
JMP @MakeAscii
@LoNibble:
AND AL, 0Fh
@MakeAscii:
OR AL, '0'
STOSW
end;
{ INT 1Ch handler that displays a clock on the right hand side of the screen }
Procedure DisplayClock; Interrupt; Assembler;
ASM
CMP [ActiveFlag], 0
JNE @Exit
CLD
MOV AH, 2
INT 1Ah
MOV ES, [VideoBase]
MOV DI, VideoOffset
MOV AH, attribute
MOV AL, CH
CALL Digit
MOV AL, ':'
STOSW
MOV AL, CL
CALL Digit
MOV AL, ':'
STOSW
MOV AL, DH
CALL Digit
PUSHF
CALL DWord Ptr [OrgInt1Ch]
@Exit:
end;
Begin
If VideoMode = 7 Then
VideoBase := $B000;
GetIntVec(TimerTick, OrgInt1Ch);
SetIntVec(TimerTick, @DisplayClock);
GetIntVec(Keyboard, OrgInt9);
SetIntVec(Keyboard, @ToggleClock);
SwapVectors;
ReleaseEnvironment;
DisplayString('CLOCK installed. <Alt-F11> toggles on/off');
Keep(0);
end.
[Back to TSR SWAG index] [Back to Main SWAG index] [Original]