home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
lan
/
netclk
/
srvclock.asm
< prev
next >
Wrap
Assembly Source File
|
1989-01-28
|
15KB
|
471 lines
TITLE SRVCLOCK.ASM
PAGE 60,132
;.RM150/
;
; Revised version of SRVCLOCK previously published in PC Magazine. Several
; changes have been made to the way a listen and send are coordinated.
; This version holds up better under heavy requests.
;
;
; Alan Queen (208) 384-9137
; Boise, ID 83712
; Last update: 03/18/88
CR EQU 0DH ;carriage return
LF EQU 0AH ;line feed
MAX_RETRY EQU 3 ;maximum times to retry on startup errors
LSN_BUFFER_LEN EQU 16 ;length of LSN buffer
;increase this if any nodes return
;a '"RECEIVE" command failed' when
;running NETCLOCK
CODE SEGMENT
ASSUME CS:CODE,DS:CODE,ES:CODE
ORG 0100H
ENTRY: JMP INITIALIZE
;-----------------------------------------------------------------------------
;Data to remain in resident portion below, startup data at end of program
;-----------------------------------------------------------------------------
OLDTIMER LABEL DWORD ;Old interrupt 1ch vector
OLD1CH DW 2 DUP (?) ;
LSN_TAIL_PTR DW 00 ;Pointer to most recent session added
LSN_HEAD_PTR DW 00 ;Pointer to session to be sent
LSN_BUFFER DB LSN_BUFFER_LEN dup(0) ;Circular buffer for session numbers
LSN_BUFFER_END LABEL WORD ;End of buffer
ALL_NAMES DB '* ' ;MCB_CALLNAME for any node on listen
CLOCK EQU $ ;Clock data area
YEAR DW 0000H
MONTH DB 00H
DAY DB 00H
HOURS DB 00H
MINUTES DB 00H
SECONDS DB 00H
HUNDREDTHS DB 00H
STATUS_FLAGS DB 0 ;Bit mapped flag
;Status_Flags byte used as follows:
;
; +----------- Listen needs reset (a listen has failed)
; UNUSED | +--------- ReSend is required (previous send failed)
; | | | | | | | +------- Timer called operation in process
; 0 0 0 0 0 0 0 0
;
;-----------------------------------------------------------------------------
; Message Control Blocks, This one for startup and listens
;-----------------------------------------------------------------------------
MCB EQU $ ;
MCB_COMMAND DB 00 ;The command to be performed
MCB_RETCODE DB 00 ;Command completion code
MCB_LSN DB 00 ;Local Session Number
MCB_NUM DB 00 ;Number of the name we are using
MCB_BUFFER@ DW 0000 ;Address of the buffer for data sent
DW 0000 ;and received (offset:segment format)
MCB_LENGTH DW 0000 ;Length of the buffer, updated by a receive
MCB_CALLNAME DB '* ' ;name we are calling (* = all)
MCB_NAME DB 'SRV_CLOCK ' ;Our name, (names are 16 bytes long )
MCB_RTO DB 10 ;Receive time out (5 seconds)
MCB_STO DB 10 ;Send time out (also 5 seconds)
MCB_POST@ DW 0000 ;Post at location for "no wait" commands
DW 0000 ;offset:segment format
MCB_LANA_NUM DB 00 ;Lan adapter number 00 for first 01 for second
MCB_CMD_CPLT DB 00 ;Command completion FFh during while in process
MCB_RESERVE DB 14 DUP(0) ;
;
; Second MCB for send and hang up operations, fields similar to above
;
MCB2 EQU $
MCB_COMMAND2 DB 00
MCB_RETCODE2 DB 00
MCB_LSN2 DB 00
MCB_NUM2 DB 00
MCB_BUFFER@2 DW 0000
DW 0000
MCB_LENGTH2 DW 0000
MCB_CALLNAME2 DB 16 dup(20h)
MCB_NAME2 DB 'SRV_CLOCK '
MCB_RTO2 DB 00
MCB_STO2 DB 00
MCB_POST@2 DW 0000
DW 0000
MCB_LANA_NUM2 DB 00
MCB_CMD_CPLT2 DB 00
MCB_RESERVE2 DB 14 DUP(0)
;------------------------------------------------------------------------------
;INTERRUPT 1CH HANDLING ROUTINE. Execution comes here every timer tick
;------------------------------------------------------------------------------
TIMER PROC NEAR
STI ;enable interrupts
PUSHF ;save the flags
CALL CS:DWORD PTR OLDTIMER ;and call original timer routine
TEST CS:STATUS_FLAGS,00000001B ;are we in a timer called procedure?
JNZ T4 ;exit if so
OR CS:STATUS_FLAGS,00000001B ;otherwise set the "in process" bit on
CALL EOI ;issue an end of interrupt to 8259 PIC
CMP CS:MCB_CMD_CPLT2,0FFH ;Hangup still in process
JE T2 ;if so check other flags
T1:
CALL CLOCKSEND ;do the CLOCKSEND procedure
T2:
TEST CS:STATUS_FLAGS,00000100B ;necessary to restart listen?
JZ T3 ;if not exit
CALL RESET_LISTEN ;if so do procedure
T3:
AND CS:STATUS_FLAGS,00001110B ;set the "in process" bit off
T4: ;
IRET ;Done - exit
TIMER ENDP
;------------------------------------------------------------------------------
; Issue end of Interrupt to 8259 PIC
;------------------------------------------------------------------------------
EOI PROC NEAR
PUSH AX
MOV AL,20H
OUT 20H,AL
POP AX
RET
EOI ENDP
;
;------------------------------------------------------------------------------
; Execution comes here when called by another node, completing the listen
;------------------------------------------------------------------------------
LISTEN PROC NEAR
MOV AX,ES ;Netbios restores ES
MOV DS,AX ;use it to set DS
CMP MCB_RETCODE,0 ;listen complete OK?
JNE L2 ;if not restart listen
MOV BX,LSN_TAIL_PTR ;get the tail pointer
INC BX ;add 1
CMP BX,OFFSET LSN_BUFFER_END ;at the end of the buffer?
JNE L1 ;if not proceed
SUB BX,LSN_BUFFER_LEN ;wrap to beginning if so
L1:
CMP BX,LSN_HEAD_PTR ;buffer full?
JE L2 ;if so we cannot respond
MOV LSN_TAIL_PTR,BX ;otherwise, set the tail ptr
MOV AL,MCB_LSN ;and move the session number
MOV BYTE PTR [BX],AL ;into the buffer
L2:
LEA SI,ALL_NAMES ;replace the callers name
LEA DI,MCB_CALLNAME ;with an asterick (meaning any)
MOV CX,16 ;
REPNZ MOVSB ;
MOV BX,OFFSET MCB ;Point BX to listen MCB block
INT 5CH ;Netbios call
CMP AL,0 ;immediate return OK?
JE L3 ;exit if so
OR STATUS_FLAGS,00000100B ;else flag that we need new listen
L3:
IRET
LISTEN ENDP
;------------------------------------------------------------------------------
; Execution comes here if reset listen bit set. Called from timer.
;------------------------------------------------------------------------------
RESET_LISTEN PROC NEAR
PUSH AX ;save registers used
PUSH BX
PUSH DS
PUSH ES
PUSH CS
POP AX
MOV DS,AX ;set data
MOV ES,AX ;and extra segments
MOV BX,OFFSET MCB ;Point ES:BX to listen MCB
INT 5CH ;Netbios call
CMP AL,0 ;command completed OK?
JNE RL1 ;if not exit, restart flag still set
AND STATUS_FLAGS,00001011B ;else set the restart bit off
RL1:
POP ES ;restore registers
POP DS
POP BX
POP AX
RET
RESET_LISTEN ENDP
;------------------------------------------------------------------------------
; send clock data to requesting node using a netbios send
;------------------------------------------------------------------------------
CLOCKSEND PROC NEAR
PUSH AX ;save registers used
PUSH BX
PUSH DS
PUSH ES
PUSH CS
POP AX
MOV DS,AX
MOV ES,AX
TEST STATUS_FLAGS,00000010B ;Check immediate resend flag
JNZ CS2 ;if needed resend same MCB2
MOV BX,LSN_HEAD_PTR ;Compare Head pointer to tail
CMP LSN_TAIL_PTR,BX ;pointer, if equal, we do not have
JE CS5 ;a requesting session. So exit.
;
INC BX ;we got the head ptr above, now add 1
CMP BX,OFFSET LSN_BUFFER_END ;are we at the end of the buffer?
JNE CS1 ;
SUB BX,LSN_BUFFER_LEN ;if so wrap
CS1: ;
MOV LSN_HEAD_PTR,BX ;update head pointer
MOV AL,BYTE PTR [BX] ;get session number in AL
MOV MCB_LSN2,AL ;move it to MCB2
CS2: ;
MOV MCB_COMMAND2,94H ;send "no wait" command
MOV MCB_POST@2,OFFSET HANGUP ;posting into HANGUP
MOV MCB_POST@2+2,CS ;proper segment
CALL GET_TIME
MOV BX,OFFSET MCB2 ;point ES:BX at MCB
INT 5CH ;netbios call
CMP AL,0 ;immediate completion OK?
JE CS4 ;exit with resend bit off
CMP AL,22H ;too many commands outstanding?
JE CS3 ;exit with resend bit on
CMP AL,21H ;interface too busy?
JE CS3 ;exit with resend on
JMP CS4 ;otherwise, we can't save it, move on
CS3: ;
OR STATUS_FLAGS,00000010B ;set resend bit on
JMP CS5 ;exit
CS4: ;
AND STATUS_FLAGS,00001101B ;set resend bit off
CS5: ;
POP ES ;restore registers
POP DS
POP BX
POP AX
RET
CLOCKSEND ENDP
;------------------------------------------------------------------------------
;Execution "posts" here on final completion of "no wait" send from CLOCKSEND above.
;------------------------------------------------------------------------------
HANGUP PROC NEAR
MOV AX,ES ;netbios restores ES
MOV DS,AX ;use to set DS
MOV MCB_POST@2,0 ;set post address off by
MOV MCB_POST@2+2,0 ;setting fields to zero
MOV MCB_COMMAND2,92H ;Hang up command 'no wait'
LEA BX,MCB2 ;Point ES:BX at MCB2
INT 5CH ;Netbios call
IRET ;return from interrupt
HANGUP ENDP
;------------------------------------------------------------------------------
; get date and time to send to requesting node WORKS ON AT or similar CMOS ONLY!
;------------------------------------------------------------------------------
GET_TIME PROC NEAR
XOR AX,AX ;clear AX
MOV AL,09 ;09 = Year
OUT 70H,AL ;Real time clock at 70H
IN AL,71H ;returns at 71H
CALL BCD2BIN ;convert to binary
ADD AX,76CH ;add 1900 decimal, only works
;until 1999
MOV YEAR,AX ;load buffer with year
XOR AX,AX
MOV AL,08 ;get month
OUT 70H,AL ;
IN AL,71H ;
CALL BCD2BIN ;
MOV MONTH,AL ;
XOR AX,AX ;
MOV AL,07 ;get date of month
OUT 70H,AL ;
IN AL,71H ;
CALL BCD2BIN ;
MOV DAY,AL ;
XOR AX,AX ;
MOV AL,04 ;get hours
OUT 70H,AL ;
IN AL,71H ;
CALL BCD2BIN ;
MOV HOURS,AL ;
XOR AX,AX
MOV AL,02 ;get minutes
OUT 70H,AL ;
IN AL,71H ;
CALL BCD2BIN ;
MOV MINUTES,AL ;
XOR AX,AX ;
MOV AL,00 ;get seconds
OUT 70H,AL ;
IN AL,71H ;
CALL BCD2BIN ;
MOV SECONDS,AL ;
RET
GET_TIME ENDP
;
;procedure to convert time as delivered from CMOS clock (binary coded decimal)
;to binary (as used by DOS function calls and NETCLOCK.EXE) (returns in AL)
;
BCD2BIN PROC NEAR
PUSH AX ;save contents
AND AL,0F0H ;clear out low nibble
SHR AL,1 ;divide by 16
SHR AL,1 ;so that hi nibble is
SHR AL,1 ;now in lo position
SHR AL,1 ;
MOV BL,AL ;hold in al
SHL AL,1 ;multiply by ten, two here
SHL AL,1 ;four
SHL AL,1 ;eight
ADD AL,BL ;nine
ADD AL,BL ;ten
POP BX ;get previous AX contents
AND BL,0FH ;clear out hi nibble
ADD AL,BL ;add to total
RET
BCD2BIN ENDP
PROG_ENDS EQU $
;------------------------------------------------------------------------------
;INITIALIZE prepares the program for residency.
;------------------------------------------------------------------------------
INITIALIZE PROC NEAR
;
; Check if interrupt 5C has a vector
;
PUSH ES ;save ES
MOV AH,35H ;get interrupt 5C vector
MOV AL,5CH
INT 21H
MOV AX,ES
POP ES ;get back ES
CMP AX,0 ;is segment 0
JNE ADD_NAME ;if not 0 some interface is present
LEA DX,NETBIOS_ERR ;else error message
JMP ERROR ;
;
;Add a name to the name table
;
ADD_NAME: MOV MCB_COMMAND,30H ;Command 30h adds a name
MOV BX,OFFSET MCB ;point ES:BX at MCB
INT 5CH ;call netbios
CMP MCB_RETCODE,0 ;check for success
JE SET_UP ;continue if OK
CMP MCB_RETCODE,0FBH ;else check for netbios loaded
JNE ADD1 ;
LEA DX,NETBIOS_ERR ;netbios error message
JMP ERROR ;
ADD1: ;
LEA DX,ADD_ERR ;write add error message
JMP ERROR ;name that was not successful
;
;Set up MCB's with fixed information, initialize circular buffer
;
SET_UP:
MOV MCB_BUFFER@2,OFFSET CLOCK ;buffer2 always points at clock data
MOV MCB_BUFFER@2+2,DS ;insure correct segment
MOV MCB_LENGTH2,8 ;clock takes 8 bytes
LEA AX,LSN_BUFFER ;Head and Tail pointers
MOV LSN_HEAD_PTR,AX ;start out pointing at the
MOV LSN_TAIL_PTR,AX ;beginning of the circular buffer
;
; do netbios listen with post set to procedure listen
;
MOV MCB_COMMAND,91H ;listen command to MCB
MOV MCB_POST@,OFFSET LISTEN ;set post at listen procedure
MOV MCB_POST@+2,CS ;CS in segment
MOV BX,OFFSET MCB ;point ES:BX to block
INT 5CH ;netbios call
CMP AL,0 ;check for good return
JE SET_VECTORS ;if good set int vectors
LISN_ERR_1: ;otherwise
MOV MCB_COMMAND,31H ;delete name command in MCB
INT 5CH ;netbios call
CMP AL,0 ;work OK?
JE LISN_ERR_2 ;if so exit with error msg
INC ERR_RETRY ;else increment retry count
CMP ERR_RETRY,MAX_RETRY ;are we to max retry
JL LISN_ERR_1 ;if not try again
LISN_ERR_2:
MOV DX,OFFSET LSN_ERR ;else write error
JMP ERROR ;
;
;save and replace the timer interrupt vector.
;
SET_VECTORS:
MOV AH,35H ;get interrupt 1ch vector
MOV AL,1CH
INT 21H
MOV OLD1CH,BX ;save it
MOV OLD1CH[2],ES
MOV AH,25H ;point it to timer
LEA DX,TIMER
INT 21H
;
;indicate success to user
;
LEA DX,SUCCESS
MOV AH,09H ;write error message to screen
INT 21H ;
;
;Terminate but remain resident in memory.
;
LEA DX,PROG_ENDS ;point DX to end of resident code
INT 27H ;Terminate Stay Resident
;
;Error routine in case we failed
;
ERROR:
MOV AH,09
INT 21H
INT 20H
INITIALIZE ENDP
;------------------------------------------------------------------------------
;Error messages and other non resident data
;------------------------------------------------------------------------------
ADD_ERR DB CR,LF,'"ADD NAME" COMMAND FAILED',CR,LF,'$'
LSN_ERR DB CR,LF,'"LISTEN" COMMAND FAILED',CR,LF,'$'
NAME_ERR DB CR,LF,'ILLEGAL OR MISSING NODE NAME ',CR,LF,'$'
NETBIOS_ERR DB CR,LF,'NETBIOS INTERFACE NOT PRESENT',CR,LF,'$'
SUCCESS DB CR,LF,'Server Clock Installed Successfully',CR,LF,'$'
ERR_RETRY DB 0
CODE ENDS
END ENTRY