home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
SIMTEL
/
CPMUG
/
CPMUG006.ARK
/
MODEM.ASM
< prev
next >
Wrap
Assembly Source File
|
1984-04-29
|
12KB
|
646 lines
;MODEM ROUTINE - SEND, RECV, COMPUTER, TERMINAL
; * * * * * * * * * * * * * * * * * * * *
;SENSE SWITCH CONTROLS: *
; *
; A12 UP TO DISPLAY INCOMING DATA *
; A13 UP TO DISPLAY OUTGOING DATA *
; * * * * * * * * * * * * * * * * * * * *
;
;09/23/77 FIRST WRITTEN BY WARD CHRISTENSEN
;09/25/77 FIRST TESTING COMPLETE
;09/26/77 ADD ERROR$LIMIT EQU
;10/01/77 CHANGE EXIT$CHAR FROM CTL-C TO
; CTL-E FOR USE W/TIMESHARING COMPUTERS
;10/10/77 CORRECT TO SEND ANY LENGTH FILE
;
MODEM$CTL$PORT EQU 4
MODEM$SEND$MASK EQU 2
SEND$READY EQU 2 ;VALUE WHEN READY
MODEM$RECV$MASK EQU 1
RECV$READY EQU 1 ;BIT ON WHEN READY
MODEM$DATA$PORT EQU 5
KEY$CTL$PORT EQU 0 ;KEYBOARD STATUS
KEY$READY$MASK EQU 2
KEY$READY EQU 2 ;VALUE WHEN KEYBOARD READY
KEY$DATA$PORT EQU 1
INIT$REQD EQU 1 ;MODEM INIT. REQ'D?
INIT$CHAR$1 EQU 3 ;FIRST INIT CHAR TO CTL PORT
INIT$CHAR$2 EQU 15H ;2ND INIT CHAR TO CTL PORT
ERROR$LIMIT EQU 10 ;MAX ALLOWABLE ERRORS
EXIT$CHAR EQU 'E'-40H ;CHAR TO EXIT FROM T OR C
ORG 100H
CALL START ;GO PRINT ID
DB 'MODEM PROGRAM AS OF '
DB '10/10/77',13,10,'$'
;FLAG FOR GENERATING TEST CODE TO USE KEYBOARD
;TO ECHO ACK/NAK WHILE TESTING:
TEST EQU 0 ;GENERATE TEST CODE
;
;DEFINE ASCII CHARACTERS USED
SOH EQU 1
EOT EQU 4
ACK EQU 6
NAK EQU 15H
LF EQU 10
CR EQU 13
;
START POP D ;GET ID MESSAGE
MVI C,PRINT
CALL BDOS ;PRINT ID MESSAGE
;INIT PRIVATE STACK
LXI H,0 ;HL=0
DAD SP ;HL=STACK FROM CP/M
SHLD STACK ;..SAVE IT
LXI SP,STACK ;SP=MY STACK
;
CALL INIT$PORT
;GOBBLE UP GARBAGE CHARS FROM THE LINE
MVI B,1 ;TIMEOUT DELAY
CALL RECV
MVI B,1
CALL RECV
;
LDA FCB+1 ;GET OPTION (S R C T)
PUSH PSW ;SAVE OPTION
CALL MOVE$FCB ;MOVE FROM 6C TO 5C
POP PSW ;GET OPTION
CPI 'S'
JZ SEND$FILE
CPI 'R'
JZ RECV$FILE
CPI 'C'
JZ COMPUTER
CPI 'T'
JZ TERMINAL
;INVALID OPTION
CALL ERXIT ;EXIT W/ERROR
DB '++INVALID OPTION ON MODEM COMMAND - ',CR,LF
DB 'MUST BE ONE OF THE FOLLOWING:',CR,LF
DB 'MODEM SEND FILENAME',CR,LF
DB 'MODEM RECV FILENAME',CR,LF
DB 'MODEM COMPUTER',CR,LF
DB 'MODEM TERMINAL',CR,LF
DB ' ABBREV. ALLOWED: S R C T$'
;
;****************COMPUTER****************
;
;TERMINAL-TERMINAL W/ECHO SENT BY THIS PROGRAM
;'EXIT$CHAR' TYPED TO RE-BOOT
;IF ONE COMPUTER IS IN COMPUTER MODE,
;THE OTHER SHOULD BE IN TERMINAL MODE.
;AT NO TIME SHOULD BOTH BE IN COMPUTER
;MODE BECAUSE LINE ERRORS WILL BE PING-PONGED
;BACK AND FORTH AD INFINITUM.
COMPUTER:
IN MODEM$CTL$PORT
ANI MODEM$RECV$MASK
CPI RECV$READY
JZ LINE$CHAR
;NOTHING FROM LINE, CHECK KEYBOARD
MVI C,CONST ;CHECK STATUS
CALL BDOS
ORA A ;READY?
JZ COMPUTER ;..NO
MVI C,RDCON
CALL BDOS ;GET CHAR
CPI EXIT$CHAR ;END?
JZ EXIT ;YES, EXIT
OUT MODEM$DATA$PORT ;SEND CHAR
JMP COMPUTER
;GOT CHAR FROM LINE
LINE$CHAR:
IN MODEM$DATA$PORT
OUT MODEM$DATA$PORT ;ECHO
CALL TYPE ;TYPE IT
JMP COMPUTER
;
;**************TERMINAL****************
;
;SEE NOTES UNDER 'COMPUTER'
;
TERMINAL:
IN KEY$CTL$PORT
ANI KEY$READY$MASK
CPI KEY$READY
JNZ TRECV ;NOTHING FROM KEYBOARD
IN KEY$DATA$PORT
ANI 7FH
CPI EXIT$CHAR ;TIME TO END?
JZ EXIT
OUT MODEM$DATA$PORT
TRECV IN MODEM$CTL$PORT
ANI MODEM$RECV$MASK
CPI RECV$READY
JNZ TERMINAL
IN MODEM$DATA$PORT
CALL TYPE
JMP TERMINAL
;INIT SERIAL PORT
INIT$PORT:
LXI D,MSG$BAUD
CALL PRINT$MESSAGE
IF INIT$REQD
MVI A,INIT$CHAR$1
OUT MODEM$CTL$PORT
MVI A,INIT$CHAR$2
OUT MODEM$CTL$PORT
ENDIF
;GET THE SPEED
XRA A ;GET A ZERO
CALL SEND ;SEND A CHAR
XRA A ;GET ZERO
CALL SEND ;SEND AGAIN
;WAIT, TIMING TO DETERMINE BAUD RATE
LXI B,0 ;INIT COUNT
INIT$WAIT:
IN MODEM$CTL$PORT
ANI MODEM$SEND$MASK
CPI SEND$READY
JZ INIT$WAIT$END
DCR C
JNZ INIT$WAIT
DCR B
JNZ INIT$WAIT
CALL ERXIT
DB '++TIME OUT DETERMINING BAUD RATE$'
INIT$WAIT$END:
MOV A,B ;GET COUNT
CPI 0F5H ;110 BAUD = F0,
JC BAUD$110 ;300 BAUD = FA
;BAUD RATE 300
LXI D,MSG$300
INIT$PRINT:
CALL PRINT$MESSAGE
RET ;FROM INIT$PORT
BAUD$110:
LXI D,MSG$110
JMP INIT$PRINT
MSG$BAUD DB 'BAUD RATE IS $'
MSG$110 DB '110',CR,LF,'$'
MSG$300 DB '300',CR,LF,'$'
;MOVE FCB (SECOND OPERAND ON COMMAND)
; TO NORMAL FCB LOCATION
MOVE$FCB:
LXI H,FCB
LXI D,FCB+16
MVI B,16
MOVE$LOOP:
LDAX D
MOV M,A
INX D
INX H
DCR B
JNZ MOVE$LOOP
XRA A ;GET 0
STA FCB+32 ;ZERO RECORD #
RET
;
;*****************SEND FILE***************
;
SEND$FILE:
CALL OPEN$FILE ;OPEN THE FILE
LXI D,OPENM
CALL PRINT$MESSAGE
SENDB XRA A ;GET A ZERO
STA ERRCT ;ZERO ERROR COUNT
;READ SECTOR, SEND IT
CALL READ$SECTOR
LDA SECTNO ;INCR SECT NO.
INR A
STA SECTNO
;SEND OR REPEAT SECTOR
REPTB LXI D,SECTMSG
CALL PRINT$MESSAGE
LDA SECTNO
CALL HEXO
CALL CRLF
MVI A,SOH
CALL SEND
LDA SECTNO
CALL SEND
LDA SECTNO
CMA
CALL SEND
MVI C,0 ;INIT CKSUM
LXI H,80H
SENDC MOV A,M
CALL SEND
INX H
MOV A,H
CPI 1 ;DONE WITH SECTOR?
JNZ SENDC
;SECTOR SENT, SEND CKSUM
MOV A,C ;GET CKSUM
CALL SEND
;GET ACK ON SECTOR
MVI B,4 ;WAIT 4 SECONDS MAX
CALL RECV
JNC SNTO ;NO TIMEOUT
;TIMED OUT WAITING FOR ACK
CALL TOUT ;PRINT 'TIMEOUT', ERRCT
DATERR LDA ERRCT
INR A
STA ERRCT
CPI ERROR$LIMIT
JC REPTB ;REPEAT SECTOR
;SECTOR SEND NO GOOD AFTER 10 TRIES
CALL ERXIT
DB 'CAN''T SEND SECTOR '
DB '- ABORTING',13,10,'$'
SECTMSG DB 'SENDING SECTOR $'
;NO TIMEOUT SENDING SECTOR
SNTO CPI ACK ;ACK RECIEVED?
JZ SENDB ;..YES, SEND NEXT SECT
;ACK NOT RECIEVED
CALL HEXO ;TYPE CHR IN HEX
LXI D,ERR1
CALL PRINT$MESSAGE
JMP DATERR ;GO TO DATA ERROR
ERR1 DB 'H RECEIVED, NOT ACK',13,10,'$'
OPENM DB 'FILE OPEN',13,10,'$'
;
;**************RECEIVE FILE****************
;
RECV$FILE:
CALL ERASE$OLD$FILE
CALL MAKE$NEW$FILE
RECV$LOOP:
XRA A ;GET 0
STA ERRCT ;INIT ERROR COUNT
RECV$HDR:
LXI D,RMSG
CALL PRINT$MESSAGE
LDA SECTNO
INR A
CALL HEXO
CALL CRLF
MVI B,5 ;5 SEC TIMEOUT
CALL RECV
JNC RHNTO ;NO TIMEOUT
RECV$HDR$TIMEOUT:
CALL TOUT ;PRINT TIMEOUT
RECV$SECT$ERR:
;PURGE THE LINE OF INPUT CHARS
MVI B,1 ;1 SEC W/NO CHARS
CALL RECV
JNC RECV$SECT$ERR ;LOOP UNTIL SENDER DONE
MVI A,NAK
CALL SEND ;SEND NAK
LDA ERRCT
INR A
STA ERRCT
CPI ERROR$LIMIT
JC RECV$HDR
CALL ERXIT
DB '++UNABLE TO GET VALID HEADER',0DH,0AH,'$'
RMSG DB 'WAITING FOR SECTOR #$'
;GOT CHAR - MUST BE SOH
RHNTO CPI SOH
JZ GOT$SOH
ORA A ;00 FROM SPEED CHECK?
JZ RECV$HDR
CPI EOT
JZ GOT$EOT
;DIDN'T GET SOH -
CALL HEXO
LXI D,ERRSOH
CALL PRINT$MESSAGE
JMP RECV$SECT$ERR
ERRSOH DB 'H RECEIVED, NOT SOH',0DH,0AH,'$'
GOT$SOH:
MVI B,1
CALL RECV
JC RECV$HDR$TIMEOUT
MOV D,A ;D=BLK #
MVI B,1
CALL RECV ;GET CMA'D SECT #
JC RECV$HDR$TIMEOUT
CMA
CMP D ;GOOD SECTOR #?
IF TEST
JMP RECV$SECTOR
ENDIF
JZ RECV$SECTOR
;GOT BAD SECTOR #
LXI D,ERR2
CALL PRINT$MESSAGE
JMP RECV$SECT$ERR
ERR2 DB '++BAD SECTOR # IN HDR',0DH,0AH,'$'
;
RECV$SECTOR:
MOV A,D ;GET SECTOR #
STA RECVD$SECT$NO
MVI C,0 ;INIT CKSUM
LXI H,80H ;POINT TO BUFFER
RECV$CHAR:
MVI B,1 ;1 SEC TIMEOUT
CALL RECV ;GET CHAR
JC RECV$HDR$TIMEOUT
MOV M,A ;STORE CHAR
INR L ;DONE?
JNZ RECV$CHAR
;VERIFY CHECKSUM
MOV D,C ;SAVE CHECKSUM
MVI B,1 ;TIMEOUT
CALL RECV ;GET CHECKSUM
JC RECV$HDR$TIMEOUT
CMP D ;CHECK
JNZ RECV$CKSUM$ERR
;
;GOT A SECTOR, WRITE IF = 1+PREV SECTOR
;
LDA RECVD$SECT$NO
MOV B,A ;SAVE IT
LDA SECTNO ;GET PREV
INR A ;CALC NEXT SECTOR #
CMP B ;MATCH?
JNZ DO$ACK
;GOT NEW SECTOR - WRITE IT
LXI D,FCB
MVI C,WRITE
CALL BDOS
ORA A
JNZ WRITE$ERROR
LDA RECVD$SECT$NO
STA SECTNO ;UPDATE SECTOR #
DO$ACK MVI A,ACK
CALL SEND
JMP RECV$LOOP
;
WRITE$ERROR:
CALL ERXIT
DB '++ERROR WRITING FILE',0DH,0AH,'$'
;
RECV$CKSUM$ERR:
LXI D,ERR3
CALL PRINT$MESSAGE
JMP RECV$SECT$ERR
ERR3 DB '++BAD CKSUM ON SECTOR'
DB 0DH,0AH,'$'
;
GOT$EOT:
MVI A,ACK ;ACK THE EOT
CALL SEND
LXI D,FCB
MVI C,CLOSE
CALL BDOS
INR A
JNZ XFER$CPLT
CALL ERXIT
DB '++ERROR CLOSING FILE$'
;
ERASE$OLD$FILE:
LXI D,FCB
MVI C,SRCHF ;SEE IF IT EXISTS
CALL BDOS
INR A ;FOUND?
RZ ;NO, RETURN
LXI D,EXIST
CALL PRINT$MESSAGE
MVI C,RDCON
CALL BDOS
CPI 'Y'
JNZ 0 ;REBOOT IF NOT ERASE
CALL CRLF
;ERASE OLD FILE
LXI D,FCB
MVI C,ERASE
CALL BDOS
RET
EXIST DB '++FILE EXISTS, TYPE Y TO ERASE:$'
;
MAKE$NEW$FILE:
LXI D,FCB
MVI C,MAKE
CALL BDOS
INR A ;FF=BAD
RNZ ;OPEN OK
;DIRECTORY FULL - CAN'T MAKE FILE
CALL ERXIT
DB '++ERROR - CAN''T MAKE FILE',0DH,0AH
DB '++DIRECTORY MUST BE FULL',0DH,0AH,'$'
;
; S U B R O U T I N E S
;
;OPEN FILE
OPEN$FILE LXI D,FCB
MVI C,OPEN
CALL BDOS
INR A ;OPEN OK?
RNZ ;GOOD OPEN
CALL ERXIT
DB 'CAN''T OPEN FILE$'
; - - - - - - - - - - - - - - -
PRINT$MESSAGE:
MVI C,PRINT
JMP BDOS ;PRINT MESSAGE, RETURN
; - - - - - - - - - - - - - - -
;EXIT PRINTING MESSAGE FOLLOWING 'CALL ERXIT'
ERXIT POP D ;GET MESSAGE
CALL PRINT$MESSAGE ;PRINT IT
EXIT LHLD STACK ;GET ORIGINAL STACK
SPHL ;RESTORE IT
RET ;--EXIT-- TO CP/M
; - - - - - - - - - - - - - - -
;MODEM RECV
RECV PUSH D ;SAVE
MSEC LXI D,0BBBBH ;1 SEC DCR COUNT
IF NOT TEST
MWTI IN MODEM$CTL$PORT
ANI MODEM$RECV$MASK
CPI RECV$READY
JZ MCHAR ;GOT CHAR
ENDIF
IF TEST
MWTI IN KEY$CTL$PORT ;READ KEYBOARD
ANI KEY$READY$MASK
CPI KEY$READY
JZ MCHAR
ENDIF
DCR E ;COUNT DOWN
JNZ MWTI ;FOR TIMEOUT
DCR D
JNZ MWTI
DCR B ;DCR # OF SECONDS
JNZ MSEC
;MODEM TIMED OUT RECEIVING
POP D ;RESTORE D,E
STC ;CARRY SHOWS TIMEOUT
RET
;GOT MODEM CHAR
IF NOT TEST
MCHAR IN MODEM$DATA$PORT
ENDIF
IF TEST
MCHAR IN KEY$DATA$PORT
ANI 7FH ;DEL PARITY FROM KEYBOAREAD
ENDIF
POP D ;RESTORE DE
;CALC CHECKSUM
PUSH PSW
ADD C
MOV C,A
;CHECK IF MONITORING INPUT
IN 0FFH
ANI 10H
JZ NO$MON$INPUT
POP PSW
PUSH PSW
CALL SHOW ;CHAR RECEIVED
NO$MON$INPUT:
POP PSW
;TURN OFF CARRY TO SHOW NO TIMEOUT
ORA A
RET
; - - - - - - - - - - - - - - -
;MODEM SEND CHAR ROUTINE
SEND PUSH PSW
;CHECK IF MONITORING OUTPUT
IN 0FFH
ANI 20H
JZ NO$MON$OUTPUT
POP PSW
PUSH PSW
CALL SHOW
NO$MON$OUTPUT:
POP PSW
PUSH PSW
ADD C ;CALC CKSUM
MOV C,A
SENDW IN MODEM$CTL$PORT
ANI MODEM$SEND$MASK
CPI SEND$READY
JNZ SENDW
POP PSW ;GET CHAR
OUT MODEM$DATA$PORT
RET
; - - - - - - - - - - - - - - -
;SHOW CHAR RECEIVED OR SENT
SHOW CPI 0AH ;LF?
JZ TYPE
CPI 0DH
JZ TYPE
CPI 09 ;TAB
JZ TYPE
CPI ' '
JC SHOWHEX
CPI 7FH
JC TYPE
SHOWHEX PUSH PSW
MVI A,'('
CALL TYPE
POP PSW
CALL HEXO
MVI A,')'
JMP TYPE
; - - - - - - - - - - - - - - -
;PRINT TIMEOUT MESSAGE
TOUTM DB 'TIMEOUT $'
TOUT LXI D,TOUTM
CALL PRINT$MESSAGE
PRINT$ERRCT:
LDA ERRCT
CALL HEXO ;FALL INTO CR/LF
; - - - - - - - - - - - - - - -
CRLF MVI A,13
CALL TYPE
MVI A,10
; - - - - - - - - - - - - - - -
TYPE PUSH PSW
PUSH B
PUSH D
PUSH H
MOV E,A
MVI C,WRCON
CALL BDOS
POP H
POP D
POP B
POP PSW
RET
; - - - - - - - - - - - - - - -
;HEX OUTPUT
HEXO PUSH PSW
RAR
RAR
RAR
RAR
CALL NIBBL
POP PSW
NIBBL ANI 0FH
CPI 10
JC ISNUM
ADI 7
ISNUM ADI '0'
JMP TYPE
; - - - - - - - - - - - - - - -
;FILE READ ROUTINE
READ$SECTOR:
LXI D,FCB
MVI C,READ
CALL BDOS
ORA A
RZ
DCR A ;EOF?
JNZ RDERR
;EOF
XRA A
STA ERRCT
LXI D,FSENTM ;FILE SENT MESSAGE
CALL PRINT$MESSAGE
SEOT MVI A,EOT
CALL SEND
MVI B,5 ;WAIT 5 SEC FOR TIMEOUT
CALL RECV
JC EOTTOT ;EOT TIMEOUT
CPI ACK
JZ XFER$CPLT
;ACK NOT RECIEVED
CALL HEXO
LXI D,ERR1
CALL PRINT$MESSAGE
EOTERR LDA ERRCT
INR A
STA ERRCT
CPI ERROR$LIMIT
JC SEOT
CALL ERXIT
DB 'NO ACK RECIEVED ON EOT$',10,13
FSENTM DB 13,10,'FILE SENT, SENDING EOT''S',10,13,'$'
;TIMEOUT ON EOT
EOTTOT CALL TOUT
JMP EOTERR
;READ ERROR
RDERR CALL ERXIT
DB '++FILE READ ERROR$'
; - - - - - - - - - - - - - - -
;DONE - CLOSE UP SHOP
XFER$CPLT:
CALL ERXIT
DB 13,10,'TRANSFER COMPLETE$'
DS 40 ;STACK AREA
STACK DS 2 ;STACK POINTER
RECVD$SECT$NO DB 0
SECTNO DB 0 ;CURRENT SECTOR NUMBER
ERRCT DB 0 ;ERROR COUNT
;
; BDOS EQUATES (VERSION 2)
;
RDCON EQU 1
WRCON EQU 2
PRINT EQU 9
CONST EQU 11 ;CONSOLE STAT
OPEN EQU 15 ;0FFH=NOT FOUND
CLOSE EQU 16 ; " "
SRCHF EQU 17 ; " "
SRCHN EQU 18 ; " "
ERASE EQU 19 ;NO RET CODE
READ EQU 20 ;0=OK, 1=EOF
WRITE EQU 21 ;0=OK, 1=ERR, 2=?, 0FFH=NO DIR SPC
MAKE EQU 22 ;0FFH=BAD
REN EQU 23 ;0FFH=BAD
STDMA EQU 26
BDOS EQU 5
REIPL EQU 0
FCB EQU 5CH ;SYSTEM FCB