home *** CD-ROM | disk | FTP | other *** search
- ;* ALARM.ASM - A simple memory-resident program that beeps the speaker
- ;* at a prearranged time. Can be loaded more than once for multiple
- ;* alarm settings. During installation, ALARM establishes a handler
- ;* for the timer interrupt (interrupt 08). It then terminates through
- ;* the Terminate-and-Stay-Resident function (function 31h). After the
- ;* alarm sounds, the resident portion of the program retires by setting
- ;* a flag that prevents further processing in the handler.
- ;*
- ;* NOTE: You must assemble this program as a .COM file, either as a PWB
- ;* build option or with the ML /AT switch.
-
- .MODEL tiny, pascal, os_dos
- .STACK
-
- .CODE
-
- ORG 5Dh ; Location of time argument in PSP,
- CountDown LABEL WORD ; converted to number of 5-second
- ; intervals to elapse
- .STARTUP
- jmp Install ; Jump over data and resident code
-
- ; Data must be in code segment so it won't be thrown away with Install code.
-
- OldTimer DWORD ? ; Address of original timer routine
- tick_91 BYTE 91 ; Counts 91 clock ticks (5 seconds)
- TimerActiveFlag BYTE 0 ; Active flag for timer handler
-
- ;* NewTimer - Handler routine for timer interrupt (interrupt 08).
- ;* Decrements CountDown every 5 seconds. No other action is taken
- ;* until CountDown reaches 0, at which time the speaker sounds.
-
- NewTimer PROC FAR
-
- .IF cs:TimerActiveFlag != 0 ; If timer busy or retired:
- jmp cs:OldTimer ; Jump to original timer routine
- .ENDIF
- inc cs:TimerActiveFlag ; Set active flag
- pushf ; Simulate interrupt by pushing flags,
- call cs:OldTimer ; then far-calling original routine
- sti ; Enable interrupts
- push ds ; Preserve DS register
- push cs ; Point DS to current segment for
- pop ds ; further memory access
- dec tick_91 ; Count down for 91 ticks
- .IF zero? ; If 91 ticks have elapsed:
- mov tick_91, 91 ; Reset secondary counter and
- dec CountDown ; subtract one 5-second interval
- .IF zero? ; If CountDown drained:
- call Sound ; Sound speaker
- inc TimerActiveFlag ; Alarm has sounded, set flag
- .ENDIF
- .ENDIF
-
- dec TimerActiveFlag ; Decrement active flag
- pop ds ; Recover DS
- iret ; Return from interrupt handler
-
- NewTimer ENDP
-
-
- ;* Sound - Sounds speaker with the following tone and duration:
-
- BEEP_TONE EQU 440 ; Beep tone in hertz
- BEEP_DURATION EQU 6 ; Number of clocks during beep,
- ; where 18 clocks = approx 1 second
-
- Sound PROC USES ax bx cx dx es ; Save registers used in this routine
- mov al, 0B6h ; Initialize channel 2 of
- out 43h, al ; timer chip
- mov dx, 12h ; Divide 1,193,180 hertz
- mov ax, 34DCh ; (clock frequency) by
- mov bx, BEEP_TONE ; desired frequency
- div bx ; Result is timer clock count
- out 42h, al ; Low byte of count to timer
- mov al, ah
- out 42h, al ; High byte of count to timer
- in al, 61h ; Read value from port 61h
- or al, 3 ; Set first two bits
- out 61h, al ; Turn speaker on
-
- ; Pause for specified number of clock ticks
-
- mov dx, BEEP_DURATION ; Beep duration in clock ticks
- sub cx, cx ; CX:DX = tick count for pause
- mov es, cx ; Point ES to low memory data
- add dx, es:[46Ch] ; Add current tick count to CX:DX
- adc cx, es:[46Eh] ; Result is target count in CX:DX
- .REPEAT
- mov bx, es:[46Ch] ; Now repeatedly poll clock
- mov ax, es:[46Eh] ; count until the target
- sub bx, dx ; time is reached
- sbb ax, cx
- .UNTIL !carry?
-
- in al, 61h ; When time elapses, get port value
- xor al, 3 ; Kill bits 0-1 to turn
- out 61h, al ; speaker off
- ret
-
- Sound ENDP
-
-
-
- ;* Install - Converts ASCII argument to valid binary number, replaces
- ;* NewTimer as the interrupt handler for the timer, then makes program
- ;* memory-resident by exiting through function 31h.
- ;*
- ;* This procedure marks the end of the TSR's resident section and the
- ;* beginning of the installation section. When ALARM terminates through
- ;* function 31h, the above code and data remain resident in memory. The
- ;* memory occupied by the following code is returned to DOS.
-
-
- Install PROC
-
- ; Time argument is in hhmm military format. Convert ASCII digits to
- ; number of minutes since midnight, then convert current time to number
- ; of minutes since midnight. Difference is number of minutes to elapse
- ; until alarm sounds. Convert to seconds-to-elapse, divide by 5 seconds,
- ; and store result in word CountDown.
-
- DEFAULT_TIME EQU 3600 ; Default alarm setting = 1 hour
- ; (in seconds) from present time
- mov ax, DEFAULT_TIME
- cwd ; DX:AX = default time in seconds
- .IF BYTE PTR CountDown != ' ';If not blank argument:
- xor CountDown[0], '00' ; Convert 4 bytes of ASCII
- xor CountDown[2], '00' ; argument to binary
-
- mov al, 10 ; Multiply 1st hour digit by 10
- mul BYTE PTR CountDown[0] ; and add to 2nd hour digit
- add al, BYTE PTR CountDown[1]
- mov bh, al ; BH = hour for alarm to go off
- mov al, 10 ; Repeat procedure for minutes
- mul BYTE PTR CountDown[2] ; Multiply 1st minute digit by 10
- add al, BYTE PTR CountDown[3] ; and add to 2nd minute digit
- mov bl, al ; BL = minute for alarm to go off
- mov ah, 2Ch ; Request function 2Ch
- int 21h ; Get Time (CX = current hour/min)
- mov dl, dh
- sub dh, dh
- push dx ; Save DX = current seconds
-
- mov al, 60 ; Multiply current hour by 60
- mul ch ; to convert to minutes
- sub ch, ch
- add cx, ax ; Add current minutes to result
- ; CX = minutes since midnight
- mov al, 60 ; Multiply alarm hour by 60
- mul bh ; to convert to minutes
- sub bh, bh
- add ax, bx ; AX = number of minutes since
- ; midnight for alarm setting
- sub ax, cx ; AX = time in minutes to elapse
- ; before alarm sounds
- .IF carry? ; If alarm time is tomorrow:
- add ax, 24 * 60 ; Add minutes in a day
- .ENDIF
-
- mov bx, 60
- mul bx ; DX:AX = minutes-to-elapse-times-60
- pop bx ; Recover current seconds
- sub ax, bx ; DX:AX = seconds to elapse before
- sbb dx, 0 ; alarm activates
- .IF carry? ; If negative:
- mov ax, 5 ; Assume 5 seconds
- cwd
- .ENDIF
- .ENDIF
-
- mov bx, 5 ; Divide result by 5 seconds
- div bx ; AX = number of 5-second intervals
- mov CountDown, ax ; to elapse before alarm sounds
-
- mov ax, 3508h ; Request function 35h
- int 21h ; Get Vector for timer (interrupt 08)
- mov WORD PTR OldTimer[0], bx; Store address of original
- mov WORD PTR OldTimer[2], es; timer interrupt
- mov ax, 2508h ; Request function 25h
- mov dx, OFFSET NewTimer ; DS:DX points to new timer handler
- int 21h ; Set Vector with address of NewTimer
-
- mov dx, OFFSET Install ; DX = bytes in resident section
- mov cl, 4
- shr dx, cl ; Convert to number of paragraphs
- inc dx ; plus one
- mov ax, 3100h ; Request function 31h, error code=0
- int 21h ; Terminate-and-Stay-Resident
-
- Install ENDP
-
- END
-