home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 June / SIMTEL_0692.cdr / msdos / pcmag / vol8n04.arc / ZCOPY.ASM < prev    next >
Assembly Source File  |  1988-12-07  |  90KB  |  1,911 lines

  1. ;----------------------------------------------------------------------
  2. ; ZCOPY - Transfer files via the COM port.  Syntax is
  3. ;----------------------------------------------------------------------
  4. CSEG        SEGMENT PARA PUBLIC 'CODE'
  5.         ASSUME  CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
  6.         ORG     100H
  7. START:        JMP     BEGINNING            ; go to start of program
  8.         JMP     ZCXFER            ; transfer self
  9.  
  10. COPYRIGHT   DB      "ZCOPY 1.0 (c) Copyright 1989 Ziff Communications Co."
  11.             DB      13,10,"PC Magazine ",254," Bob Flanders",13,10,"$",26
  12.  
  13. BIOS_DATA   EQU     40H             ; bios data segment
  14. TIMER_LOW   EQU     WORD PTR 6CH        ; offset of low word
  15. TIMER_HI    EQU     WORD PTR 6EH        ; ... high word
  16. LSR        EQU     5                ; lsr register offset
  17. LSR_DRDY    EQU     00000001B            ; data ready
  18. LSR_ORUN    EQU     00000010B            ; overrun error
  19. LSR_PRTY    EQU     00000100B            ; parity error
  20. LSR_FRM     EQU     00001000B            ; framing error
  21. LSR_BRK     EQU     00010000B            ; break interrupt
  22. LSR_THRE    EQU     00100000B            ; transmit holding reg empty
  23. LSR_TSRE    EQU     01000000B            ; transmit shift register emtpy
  24. LSR_ERR     EQU     LSR_FRM+LSR_PRTY+LSR_ORUN    ; error conditions
  25. LCR_SETUP   EQU     00000111B            ; set 8 bits, no parity, 2 stop
  26. LCR_DLAB    EQU     10000000B            ; divisor latch access bit
  27. MCR        EQU     4                ; mcr register offset
  28. MCR_OUT2    EQU     00001000B            ; out2 control bit
  29. I8259        EQU     20H             ; 8259 control register addr
  30. EOI        EQU     20H             ; 8259 end of interrupt command
  31. I8259M        EQU     21H             ; 8259 mask register
  32. FLG        DB        0                ; system operation flag
  33. FLGR        EQU     80H             ;  receiver mode
  34. FLGO        EQU     40H             ;  /o overwrite
  35. FLGU        EQU     20H             ;  /u update
  36. FLGD        EQU     10H             ;  /d set current date
  37. FLGA        EQU     08H             ;  /a abort on full
  38. FLGP        EQU     04H             ;  /p pause for diskette
  39. FLGW        EQU     02H             ;  wait forever for other system
  40. FLG_SET     EQU     07EH            ; flag mask on flg_set
  41. FLG1        DB        0                ; second flag
  42. FLG1I        EQU     80H             ;  system interrupts init'd
  43. FLG1O        EQU     40H             ;  output file is open
  44. FLG1B        EQU     20H             ;  break requested
  45. FLG1S        EQU     10H             ;  shutdown sent ok
  46. XBUF_LTS    DW        0                ; left to send
  47. XBUFL        EQU     4000H            ; buffer length
  48. XBUF_WL     EQU     XBUFL-WBUFL-1        ; write when over this value
  49. IO_LEN        EQU     512
  50. XBUF_RBL    EQU     (XBUFL/IO_LEN)*IO_LEN   ; number of bytes to read
  51. ERRORS        DW        8                ; errors so far
  52. MAX_ERRORS  EQU     3                ; max retries before resync
  53. SYNC_BYTE   EQU     08H             ; first byte to sync on
  54. SYNC_END    EQU     04H             ; end of sync bytes
  55. SYNC_LEN    EQU     128
  56. SYNC_INC    EQU     11
  57. CRC_VAL     EQU     01021H            ; value for CRC
  58. FNDOP        DB        4EH             ; find first/find next op
  59. ; Note:  ** ZCPARM requires PARM_TBL to be in "OUDAPW" order
  60. PARM_TBL    DB        'OUDAPW'                ; parameter specifications
  61. ARG1        DW        0                ; pointer to arg1
  62. ARG2        DW        0                ; pointer to arg2
  63. WAIT_COUNT  DW        0                ; timer tick counter
  64. TIME_COUNT  DW        0                ; timer inc amount
  65. COM_STR     DB        "COM"                   ; com definition
  66. BAUD_CNTR   DB        0                ; baud rate counter
  67. BAUD_TABLE  DB      1,'115k $',2,'57.6k$',3,'38.4k$',6,'19.2k$',12,'9600 $'
  68.             DB      24,'4800 $'
  69. LSR_VAL     DB        0                ; lsr value after interrupt
  70. LSR_NEW     DB        0                ; lsr value is new flag
  71. SEND_BLKNO  DW        0                ; next block number to send
  72. RCV_BLKNO   DW        0                ; next block to receive
  73. DFLDIR        DB        '.',0                   ; default receive directory
  74. CURDIR        DB        ".\"                    ; current directory
  75. FILENAME    DB        13 DUP (0)            ; work area for send filename
  76. ;-------message process table--------
  77. MSG_P_TBL:
  78. CRE_FILE    EQU     1                ; create requested file
  79. OPR_PROMPT  EQU     2                ; display a prompt
  80. SHUTDOWN    EQU     3                ; end the program
  81. MSG_ACK     EQU     4                ; previous message ok
  82. DATA_BLK    EQU     5                ; block of data
  83. EOF_MARK    EQU     6                ; end of file mark
  84. MSG_NAK     EQU     7                ; previous message not ok
  85. QRY_FLE     EQU     8                ; query file existence
  86. SET_FLG     EQU     9                ; set flag bits
  87. RESYNC        EQU     10                ; resync
  88. OPR_REPLY   EQU     11                ; reply from oper
  89. DIENOW        EQU     0FFH            ; die immediately
  90. DW OFFSET CRE_FILE_P,OFFSET ZCPPROMPT,OFFSET SHUTDOWN_P,OFFSET MSG_ACK_P
  91. DW OFFSET DATA_BLK_P,OFFSET EOF_MARK_P,OFFSET MSG_NAK_P,OFFSET QRY_FLE_P
  92. DW OFFSET SET_FLG_P,OFFSET RESYNC_P
  93. SOH        EQU     01H             ; start of header
  94. STX        EQU     02H             ; start of text
  95. ETX        EQU     03H             ; end of text
  96. ACK        EQU     06H             ; acknowledge
  97. NAK        EQU     15H             ; non-acknowledge
  98. RLR        EQU     1DH             ; request last response
  99. LAST_RESP   DB        NAK             ; last response holder
  100. SEC_30        EQU     (18*30)+(2*3)        ; 30 seconds in ticks
  101. SEC_10        EQU     (18*10)+(2*1)        ; 10 seconds in ticks
  102. SEC_5        EQU     (18*5)+1            ;  5 seconds in ticks
  103. SEC_3        EQU     (18*3)+1            ;  3 seconds in ticks
  104. SEC_1        EQU     (18*1)+1            ;  1 second  in ticks
  105. DSRWAIT     DW        SEC_30            ; tics to wait for dsr
  106. RETRIES     EQU     3                ; number of retries
  107. ;    message structure
  108. MSTX        EQU     0                ; start of message
  109. MCRC        EQU     MSTX+1            ; CRC value
  110. MLEN        EQU     MCRC+2            ; length of remainder less etx
  111. MBLKNO        EQU     MLEN+2            ; number of this block
  112. MCMD        EQU     MBLKNO+2            ; command
  113. MDATA        EQU     MCMD+1            ; data area
  114. ;                        ; etx address based on data len
  115. MOHEAD        EQU     6                ; overhead bytes not in len
  116. ;                        ;     stx + crc + len + etx
  117. ;    DTA structure for DOS "find matching" call
  118. DTA        EQU     80H             ; dta offset
  119. DTA_ATTR    EQU     BYTE PTR DTA+21        ; file attribute
  120. DTA_TIME    EQU     WORD PTR DTA_ATTR+1     ; file time
  121. DTA_DATE    EQU     WORD PTR DTA_TIME+2     ; file date
  122. DTA_LSIZ    EQU     WORD PTR DTA_DATE+2     ; file lsw of size
  123. DTA_HSIZ    EQU     WORD PTR DTA_LSIZ+2     ; file msw of size
  124. DTA_NAME    EQU     BYTE PTR DTA_HSIZ+2     ; file name of file
  125. DTA_LEN     EQU     DTA_NAME+15-DTA        ; length of dta find entry
  126. ;    messages to user
  127. PARMERR     DB   "Usage: ZCOPY source [target] [/w][/u][/o][/a][/p][/d]"
  128.             DB   13,10,"/w-wait",13,10,"/u-newer files only",13,10
  129.             DB   "/o-overwrite",13,10,"/a-abort if target full",13,10
  130.             DB   "/p-pause before copy",13,10,"/d-use current date",13,10,'$'
  131. BADDIR        DB        "Invalid directory.",13,10,'$'
  132. FILERR        DB        "No files specified.",13,10,'$'
  133. FILENOPEN   DB        "Unable to create, skipping.",13,10,'$'
  134. INVFIL        DB        "Invalid filename.",13,10,'$'
  135. DISKFULL    DB        "Disk full .. press a key ..",13,10,'$'
  136. BSENT        DB        " being sent.",13,10,'$'
  137. BRECVD        DB        " being received.",13,10,'$'
  138. TOOMANY     DB        "Resyncing ...",13,10,'$'
  139. FILEXISTS   DB        ": exists. Overwrite?",13,10,'$'
  140. TOOBIG        DB        ": won't fit, skipped.", 13, 10, '$'
  141. WAITING     DB        "Press a key to continue ..",13,10,'$'
  142. SHUTDOWN_R1 DB        13,10
  143. SHUTDOWN_R  DB        "ZCOPY is done."
  144. CRLF        DB        13,10,'$'
  145. TRYING        DB        13,"Baud rate $"
  146. SPDERROR    DB        13,10,"Link not established.",13,10,'$'
  147. SPDSET        DB        13,10,"Link established.",13,10,'$'
  148. NOTUP        DB        13,10,"Other node not detected.",13,10,'$'
  149.         DB        '.....'
  150. B_LEFT        DB        '.h blocks left.     ',13,'$'
  151.  
  152. BEGINNING   PROC    NEAR            ; start of program
  153.             MOV     DX,OFFSET COPYRIGHT
  154.             MOV     AH,9
  155.             INT     21H
  156.         MOV     BX, OFFSET BUF_START    ; bx -> start of buffer space
  157.         MOV     RBUF, BX            ; set offset of the receive buffer
  158.         MOV     RBUF_RPTR, BX        ; .. for receive
  159.         MOV     RBUF_GPTR, BX        ; .. and get
  160.         ADD     BX, RBUFL            ; bx -> start of send buffer
  161.         MOV     RBUF_HI, BX         ; .. save for int handler
  162.         MOV     SBUF, BX            ; set offset of the send buffer
  163.         ADD     BX, SBUFL            ; bx -> start of work buffer
  164.         MOV     WBUF, BX            ; set offset of the work buffer
  165.         ADD     BX, WBUFL            ; bx -> star to file build buffer
  166.         MOV     XBUF, BX            ; set pointer to buffer
  167.         MOV     XBUF_PTR, BX        ; .. and write pointer
  168.         ADD     BX, XBUFL            ; bx -> entry directory area
  169.         MOV     EDIR, BX            ; .. save pointer
  170.         MOV     AH, 19H            ; ah = get current drive
  171.         INT     21H             ; al = current drive
  172.         MOV     EDRV, AL            ; save entry drive
  173.         MOV     SI, EDIR            ; si -> current directory area
  174.         MOV     BYTE PTR [SI], '\'      ; .. start with backslash
  175.         INC     SI                ; si -> next byte
  176.         XOR     DL, DL            ; dl = default drive
  177.         MOV     AH, 47H            ; ah = get current dir
  178.         INT     21H             ; .. save in area
  179.         CALL    ZCPARM            ; set up parameters
  180.         CALL    ZCINIT            ; init interrupts
  181.         CALL    ZCSPEED            ; setup transfer speed
  182.         TEST    FLG, FLGR            ; Q. receiver?
  183.         JNZ     MAINRCV            ; A. yes .. rcv
  184.         MOV     AL, SET_FLG         ; al = set flags command
  185.         MOV     SI, OFFSET FLG        ; si -> flags byte
  186.         MOV     CX, 1            ; .. len to send
  187.         CALL    ZCBLKSND            ; .. send set flags
  188.         MOV     BX, WAIT_COUNT        ; bx = wait_count
  189.         ADD     BX, SEC_10            ; .. max 10 secs
  190. MAIN10:     CALL    ZCTRYRCV            ; Q. block available?
  191.         JNC     MAIN15            ; A. yes .. continue
  192.         CMP     WAIT_COUNT, BX        ; Q. timeout?
  193.         JB        MAIN10            ; A. no .. continue
  194.         MOV     DX, OFFSET NOTUP        ; dx -> error message
  195.         CALL    ZCDIE            ; .. die of old age
  196. MAIN15:     OR        FLG, AL            ; save flags
  197.         TEST    FLG, FLGP            ; Q. pause before starting?
  198.         JZ        MAIN20            ; A. no .. wait
  199.         MOV     DI, OFFSET WAITING        ; di -> waiting prompt
  200.         CALL    ZCSPROMPT            ; .. wait for response
  201. MAIN20:     JMP     ZCSF            ; send the files requested
  202. MAINRCV:    CALL    ZCRECV            ; start receive mode
  203.         JMP     MAINRCV            ; .. continuously
  204. BEGINNING   ENDP
  205. ; ---------------------------------------------------------------------
  206. ;    This routine initializes the system interrupts.
  207. ; ---------------------------------------------------------------------
  208. ZCINIT        PROC    NEAR
  209.         MOV     DX, IO_BASE         ; dx = base io port
  210.         IN        AL, DX            ; .. clear any character
  211.         INC     DX                ; dx = ier
  212.         XOR     AL, AL            ; al = zero
  213.         OUT     DX, AL            ; no ints for now
  214.         ADD     DX, 3            ; dx = mcr
  215.         OUT     DX, AL            ; .. set off all stats
  216.         ADD     DX, 2            ; dx = msr
  217.         IN        AL, DX            ; .. reset msr now
  218.         MOV     AL, INT_VECTOR        ; al = com interupt to set
  219.         ADD     AL, 8            ; .. set to actual interrupt
  220.         MOV     SI, OFFSET OLD_COM        ; si -> save area for old
  221.         MOV     DX, OFFSET ZCINT        ; dx -> com int routine
  222.         CALL    ZCSETINT            ; set up the interrupt
  223.         MOV     AL, 08H            ; al = timer interrupt to set
  224.         MOV     SI, OFFSET OLD_TIMER    ; si -> save area for old
  225.         MOV     DX, OFFSET ZCTIMER        ; dx -> timer int routine
  226.         CALL    ZCSETINT            ; set up the interrupt
  227.         MOV     AL, 1BH            ; al = control break interrupt
  228.         MOV     SI, OFFSET OLD_CTLBRK   ; si -> save area for old
  229.         MOV     DX, OFFSET ZCCTLBRK     ; dx -> timer int routine
  230.         CALL    ZCSETINT            ; set up the interrupt
  231.         MOV     AL, 23H            ; al = control break interrupt
  232.         MOV     SI, OFFSET OLD_DOSCTLB  ; si -> save area for old
  233.         MOV     DX, OFFSET ZCCTLBRK     ; dx -> timer int routine
  234.         CALL    ZCSETINT            ; set up the interrupt
  235.         MOV     AL, 24H            ; ax = doserr interrupt to set
  236.         MOV     SI, OFFSET OLD_DOSERR   ; si -> save area for old
  237.         MOV     DX, OFFSET ZCDOSERR     ; dx -> dos error routine
  238.         CALL    ZCSETINT            ; set up the interrupt
  239.         MOV     DX, IO_BASE         ; dx -> base of com port
  240.         ADD     DX, 2            ; dx -> Int id register
  241.         MOV     ZCINTIIR1, DX        ; modify int rtn instruction
  242.         MOV     ZCINTIIR2, DX        ; modify int rtn instruction
  243.         INC     DX                ; dx -> line control reg
  244.         MOV     AL, LCR_SETUP        ; al = com parm setup
  245.         OUT     DX, AL            ; .. set line characteristics
  246.         INC     DX                ; dx -> modem control reg
  247.         MOV     AL, MCR_OUT2        ; al = set on OUT2
  248.         OUT     DX, AL            ; .. set MCR value
  249.         SUB     DX, 3            ; dx -> interrupt enable reg
  250.         MOV     AL, 05H            ; al = allow lsr & rx ints
  251.         OUT     DX, AL            ; .. set int enable register
  252.         IN        AL, 21H            ; al = current int mask
  253.         MOV     CL, INT_VECTOR        ; cl = interrupt to use
  254.         MOV     AH, 1            ; ah = 1 ..
  255.         SHL     AH, CL            ; .. shift bit to mask pos
  256.         NOT     AH                ; .. and invert mask
  257.         AND     AL, AH            ; .. set off mask bit
  258.         OUT     21H, AL            ; .. allow com interrupts
  259.         OR        FLG1, FLG1I         ; show initialized
  260.         MOV     AL, INT_VECTOR        ; al = int vector
  261.         DEC     AL                ; al -> lower vector
  262.         OR        AL, 0C0H            ; al = set 8259 priority cmd
  263.         OUT     20H, AL            ; .. reset priority
  264.         RET                 ; .. return to caller
  265. ZCINIT        ENDP
  266. ; ---------------------------------------------------------------------
  267. ;    This routine resets the system to pre-runtime settings.
  268. ; ---------------------------------------------------------------------
  269. ZCRESET     PROC    NEAR
  270.         MOV     AL, 0C7H            ; al = set priority command
  271.         OUT     20H, AL            ; reset normal 8259 priority
  272.         TEST    FLG1, FLG1O         ; Q. file open?
  273.         JZ        ZCRESET10            ; A. no .. continue
  274.         MOV     BX, HANDLE            ; bx = file handle
  275.         MOV     AH, 3EH            ; ah = close
  276.         INT     21H             ; .. close that file
  277. ZCRESET10:  MOV     CL, INT_VECTOR        ; cl = interrupt to use
  278.         IN        AL, 21H            ; al = current int mask
  279.         MOV     AH, 1            ; ah = 1 ..
  280.         SHL     AH, CL            ; .. shift bit to mask pos
  281.         OR        AL, AH            ; .. set on mask bit
  282.         OUT     21H, AL            ; .. disallow com interrupts
  283.         MOV     DX, IO_BASE         ; dx -> base of com port
  284.         INC     DX                ; dx -> interrupt enable reg
  285.         XOR     AL, AL            ; al = all interrupts off
  286.         OUT     DX, AL            ; .. disallow all interrupts
  287.         ADD     DX, 3            ; dx -> modem control reg
  288.         OUT     DX, AL            ; .. set OUT2 & DTR off
  289.         MOV     AL, INT_VECTOR        ; al = com interupt to reset
  290.         ADD     AL, 8            ; .. set to actual interrupt
  291.         MOV     SI, OFFSET OLD_COM        ; si -> save area for old
  292.         CALL    ZCRESINT            ; reset the interrupt
  293.         MOV     AL, 1BH            ; al = ctlbreak interrupt
  294.         MOV     SI, OFFSET OLD_CTLBRK   ; si -> save area for old
  295.         CALL    ZCRESINT            ; reset the interrupt
  296.         MOV     AL, 23H            ; al = ctlbreak interrupt
  297.         MOV     SI, OFFSET OLD_DOSCTLB  ; si -> save area for old
  298.         CALL    ZCRESINT            ; reset the interrupt
  299.         MOV     AL, 08H            ; al = timer interrupt to reset
  300.         MOV     SI, OFFSET OLD_TIMER    ; si -> save area for old
  301.         CALL    ZCRESINT            ; reset the interrupt
  302.         CALL    ZCTIMUP            ; assure timer fully reset
  303.         MOV     AL, 24H            ; ax = doserr interrupt to reset
  304.         MOV     SI, OFFSET OLD_DOSERR   ; si -> save area for old
  305.         CALL    ZCRESINT            ; reset the interrupt
  306.         RET                 ; .. return to caller
  307. ZCRESET     ENDP
  308. ; ---------------------------------------------------------------------
  309. ; This routine initializes an interrupt vector.
  310. ; Entry:al = interrupt to setup,si -> save area for old,dx -> routine to call
  311. ; ---------------------------------------------------------------------
  312. ZCSETINT    PROC    NEAR
  313.         PUSH    BX                ; save caller's bx
  314.         PUSH    ES                ; .. and es
  315.         MOV     AH, 35H            ; ah = get int vector
  316.         INT     21H             ; es:bx -> current vector
  317.         MOV     WORD PTR [SI], BX        ; save offset
  318.         MOV     WORD PTR [SI+2], ES     ; .. and segment
  319.         MOV     AH, 25H            ; ah = set int vector
  320.         INT     21H             ; .. set up the interrupt
  321.         POP     ES                ; restore regs
  322.         POP     BX
  323.         RET                 ; .. return to caller
  324. ZCSETINT    ENDP
  325. ; ---------------------------------------------------------------------
  326. ; This routine restores the original interrupt vector.
  327. ; Entry:al = interrupt to setup,si -> save area for old
  328. ; ---------------------------------------------------------------------
  329. ZCRESINT    PROC    NEAR
  330.         PUSH    DS                ; save ds
  331.         PUSH    DX                ; .. and dx
  332.         LDS     DX, [SI]            ; ds:dx -> original vector
  333.         MOV     AH, 25H            ; ah = set int vector
  334.         INT     21H             ; .. set up the interrupt
  335.         POP     DX                ; restore regs
  336.         POP     DS
  337.         RET                 ; .. return to caller
  338. ZCRESINT    ENDP
  339. ; ---------------------------------------------------------------------
  340. ; This routine intercepts control-breaks and handles them gracefully.
  341. ; ---------------------------------------------------------------------
  342. ZCCTLBRK    PROC    NEAR
  343.         OR        CS:FLG1, FLG1B        ; show break issued
  344.         IRET                ; return to caller
  345. ZCCTLBRK    ENDP
  346. ; ---------------------------------------------------------------------
  347. ; This routine increments a local timer variable when called.
  348. ; ---------------------------------------------------------------------
  349. ZCTIMER     PROC    NEAR
  350.         STI                 ; allow ints
  351.         PUSH    AX                ; save ax
  352.         MOV     AL, 20H            ; al = reset interrupt
  353.         OUT     20H, AL            ; .. reset it
  354.         POP     AX                ; restore ax
  355.         INC     CS:WAIT_COUNT        ; increment # ticks
  356.         INC     CS:TIME_COUNT        ; .. and timer ticks
  357.         IRET                ; return from interrupt
  358. ZCTIMER     ENDP
  359. ; ---------------------------------------------------------------------
  360. ; This routine updates the system timer.
  361. ; ---------------------------------------------------------------------
  362. ZCTIMUP     PROC    NEAR
  363.         OR        TIME_COUNT, 0        ; Q. any update?
  364.         JZ        ZCTIMUP90            ; A. no .. return
  365.         PUSH    DS                ; save ds
  366.         MOV     AX, 40H            ; ax -> bios low memory seg
  367.         MOV     DS, AX            ; ds -> bios low memory seg
  368.         XOR     AX, AX            ; ax = zero
  369.         XCHG    AX, CS:TIME_COUNT        ; ax = ticks since update
  370.         ADD     DS:[TIMER_LOW], AX        ; .. add to timer value
  371.         ADC     DS:[TIMER_HI], 0        ; .. and the overflow
  372.         POP     DS                ; restore ds
  373. ZCTIMUP90:  RET
  374. ZCTIMUP     ENDP
  375. ; ---------------------------------------------------------------------
  376. ; This routine intercepts and handles DOS critical errors.
  377. ; Entry: Standard INT 24h entry; Exit: Only allows retries and aborts.
  378. ; ---------------------------------------------------------------------
  379. ZCDOSERR    PROC    NEAR
  380.         PUSHF                ; save the flags
  381.         AND     AH, NOT 28H         ; allow retry, abort only
  382.         CALL    CS:OLD_DOSERR        ; .. call old routine
  383.         CMP     AL, 1            ; Q. retry?
  384.         JE        ZCDOSERR90            ; A. yes .. continue
  385.         OR        CS:FLG1, FLG1B        ; turn on die flag
  386.         MOV     AL, 0            ; .. and ignore error
  387. ZCDOSERR90: IRET
  388. ZCDOSERR    ENDP
  389. ; ---------------------------------------------------------------------
  390. ; Communications interrupt handler. Handled from the com port
  391. ;    specified by the user on the command line.
  392. ; ---------------------------------------------------------------------
  393. ZCINT        PROC    NEAR            ; interrupt handler entry point
  394.         PUSH    AX                ; save entry registers
  395.         PUSH    BX                ; ...
  396.         PUSH    DX                ;     ...
  397.         MOV     AL, EOI            ; al = EOI instruction
  398.         OUT     I8259, AL            ; .. reset the 8259
  399. ZCINT05:    MOV     DX, 0FFFFH            ; dx = int ID register addr
  400. ZCINTIIR1   EQU     WORD PTR ZCINT05+1        ; .. address to mod for iir
  401.         IN        AL, DX            ; al = int id
  402.         JMP     SHORT ZCINT17        ; .. process interrupt
  403. ZCINT10:    MOV     DX, 0FFFFH            ; dx = int ID register addr
  404. ZCINTIIR2   EQU     WORD PTR ZCINT10+1        ; .. address to mod for iir
  405. ZCINT15:    IN        AL, DX            ; al = interrupt ID
  406.         TEST    AL, 00000001B        ; Q. any interrupt?
  407.         JNZ     ZCINT90            ; A. no .. exit now.
  408. ZCINT17:    CMP     AL, 4            ; Q. received data int?
  409.         JNE     ZCINT50            ; A. no .. process stat regs
  410.         SUB     DX, 2            ; dx = base reg
  411.         IN        AL, DX            ; al = next receive character
  412. ZCINT_RPTR: MOV     BX, 0F1F2H            ; bx -> receive buffer
  413.         MOV     CS:[BX], AL         ; .. save received character
  414.         INC     BX                ; bx -> next receive char pos
  415. ZCINT_RHI:  CMP     BX, 0F1F2H            ; Q. end of receive buffer?
  416.         JNB     ZCINT_RBUF            ; A. yes .. set to rbuf
  417. ZCINT20:    MOV     CS:RBUF_RPTR, BX        ; save receive pointer
  418.         JMP     ZCINT10            ; see if another int occurred
  419. ZCINT_RBUF: MOV     BX, 0F1F2H            ; bx -> start of buffer
  420.         JMP     ZCINT20            ; .. and continue
  421. ZCINT50:    ADD     DX, 3            ; dx -> lsr
  422.         IN        AL, DX            ; .. get value
  423.         MOV     CS:LSR_VAL, AL        ; save lsr value
  424.         MOV     CS:LSR_NEW, 0FFH        ; .. show value is new
  425.         SUB     DX, 3            ; dx -> int ID reg
  426.         JMP     ZCINT15            ; See if done
  427. ZCINT90:    STI                 ; allow interrupt
  428.         POP     DX                ; Restore entry registers
  429.         POP     BX                ;     ...
  430.         POP     AX                ;      ...
  431.         IRET                ; return from interrupt
  432. RBUF_RPTR   EQU     WORD PTR ZCINT_RPTR+1   ; rptr word
  433. RBUF        EQU     WORD PTR ZCINT_RBUF+1   ; rbuf word
  434. RBUF_HI     EQU     WORD PTR ZCINT_RHI+2    ; hi word
  435. ZCINT        ENDP
  436. ; ---------------------------------------------------------------------
  437. ; This routine sends the requested character.
  438. ; Entry: al = character to send
  439. ; ---------------------------------------------------------------------
  440. ZCPUTC        PROC    NEAR
  441.         PUSH    BX                ; save registers
  442.         PUSH    CX
  443.         PUSH    DX
  444.         PUSH    SI
  445.         PUSH    AX
  446.         MOV     DX, IO_BASE         ; dx -> base io address
  447.         ADD     DX, LSR            ; dx = line status addr
  448. ZCPUTC10:   IN        AL, DX            ; al = lsr
  449.         AND     AL, LSR_THRE        ; leave tsre & thre on
  450.         CMP     AL, LSR_THRE        ; Q. all empty?
  451.         JNE     ZCPUTC10            ; A. no .. retry
  452.         POP     AX                ; get character
  453.         MOV     DX, IO_BASE         ; .. and base register
  454.         OUT     DX, AL            ; .. put the char
  455.         POP     SI                ; restore registers
  456.         POP     DX
  457.         POP     CX
  458.         POP     BX
  459.         RET                 ; ..and return to caller
  460. ZCPUTC        ENDP
  461. ; ---------------------------------------------------------------------
  462. ; This routine gets a character from the receive buffer if one is available.
  463. ; Exit: al = character; carry flag set indicates no character available
  464. ; ---------------------------------------------------------------------
  465. ZCGETC        PROC    NEAR            ; get a received char, if any
  466.         CALL    ZCCLA            ; Q. anything to get?
  467.         JNC     ZCGETC80            ; A. yes .. update pointers
  468.         RET                 ; .. else .. return to caller
  469. ZCGETC80:   PUSH    BX                ; save caller's bx
  470.         MOV     BX, RBUF_GPTR        ; bx = next get pointer
  471.         INC     BX                ; bx -> next position
  472.         CMP     BX, RBUF_HI         ; Q. end of buffer?
  473.         JB        ZCGETC90            ; A. no .. store as it
  474.         MOV     BX, RBUF            ; bx -> start of buffer
  475. ZCGETC90:   MOV     RBUF_GPTR, BX        ; save get pointer
  476.         POP     BX                ; restore caller's bx
  477.         CLC                 ; .. show char available
  478.         RET                 ; return to caller
  479. ZCGETC        ENDP
  480. ; ---------------------------------------------------------------------
  481. ; This routine reads one character from the receive buffer
  482. ; without adjusting the read buffer pointers.
  483. ; Exit: al = character; carry flag set indicates no character available
  484. ; ---------------------------------------------------------------------
  485. ZCCLA        PROC    NEAR
  486.         PUSH    BX                ; save registers
  487.         MOV     BX, RBUF_GPTR        ; bx = next get offset
  488.         CMP     BX, RBUF_RPTR        ; Q. anything to get?
  489.         JNE     ZCCLA10            ; A. yes .. continue
  490.         STC                 ; show no char found
  491.         JMP     SHORT ZCCLA90        ; .. and return to caller
  492. ZCCLA10:    MOV     AL, [BX]            ; al = char
  493.         CLC                 ; .. set carry to char found
  494. ZCCLA90:    POP     BX                ; restore registers
  495.         RET                 ; .. and return to caller
  496. ZCCLA        ENDP
  497. ; ---------------------------------------------------------------------
  498. ; This routine parses the command line.
  499. ; Exit: Returns to DOS if error else argument bits and values are set.
  500. ; ---------------------------------------------------------------------
  501. ZCPARM        PROC    NEAR
  502.         CALL    ZCUC            ; upper case the parm area
  503.         MOV     SI, 81H            ; si -> parms area
  504. ZCPARM10:   CALL    ZCPARMC            ; get parameter character
  505.         CMP     AL, '/'                 ; Q. option?
  506.         JE        ZCPARM80            ; A. yes .. check option
  507.         CMP     AL, 13            ; Q. end of line?
  508.         JE        ZCPARM50            ; A. yes .. exit
  509.         CMP     AL, ' '                 ; Q. blank?
  510.         JNA     ZCPARM10            ; A. yes .. skip
  511.         CALL    ZCARG            ; set the argument
  512.         JC        ZCPARMERR            ; .. die on an error
  513. ZCPARM30:   CALL    ZCPARMC            ; get next character
  514.         CMP     AL, 13            ; Q. end of line?
  515.         JE        ZCPARM50            ; A. yes .. process
  516.         CMP     AL, '/'                 ; Q. start of option?
  517.         JE        ZCPARM80            ; A. yes .. process
  518.         CMP     AL, ' '                 ; Q. end of parm?
  519.         JA        ZCPARM30            ; A. no .. next char
  520.         MOV     BYTE PTR [SI-1], 0        ; end the parm
  521.         JMP     ZCPARM10            ; .. look for next
  522. ZCPARM50:   MOV     BYTE PTR [SI-1], 0        ; zero out the <cr>
  523.         CMP     ARG1, 0            ; Q. parm 1 available?
  524.         JE        ZCPARMERR            ; A. no .. error
  525.         CMP     ARG2, 0            ; Q. Parm 2 available?
  526.         JNE     ZCPARM60            ; A. yes .. continue
  527.         MOV     ARG2, OFFSET DFLDIR     ; set up for current directory
  528. ZCPARM60:   CALL    ZCCOM            ; check the com parameter
  529.         CALL    ZCFLSET            ; set up file parameters
  530.         RET                 ; return to caller
  531. ZCPARM80:   MOV     BYTE PTR [SI-1], 0        ; end the parm
  532.         CALL    ZCPARMC            ; al = option character
  533.         CMP     AL, '1'                 ; Q. < 1?
  534.         JB        ZCPARM82            ; A. yes .. continue
  535.         CMP     AL, '6'                 ; Q. > 6?
  536.         JA        ZCPARM82            ; A. yes .. continue
  537.         SUB     AL, '1'                 ; .. adjust the value
  538.         MOV     BAUD_CNTR, AL        ; .. save as starting baud
  539.         JMP     ZCPARM10            ; .. continue
  540. ZCPARM82:   LEA     DI, PARM_TBL        ; di -> table to search
  541.         MOV     CX, 6            ; cx = max entries
  542.      REPNE  SCASB                ; Q. entry found?
  543.         JNE     ZCPARMERR            ; A. no .. parameter in error
  544.         MOV     AL, 1            ; al - amount to shift
  545.         SHL     AL, CL            ; .. do it
  546.         OR        FLG, AL            ; .. or in the flag
  547.         JMP     ZCPARM10            ; .. continue scanning
  548. ZCPARMERR:  LEA     DX, PARMERR         ; dx -> invalid number of parms
  549.         CALL    ZCDIE            ; abort
  550. ZCPARM        ENDP
  551. ; ---------------------------------------------------------------------
  552. ; This routine gets the next character from the parm area in the DOS PSP.
  553. ; Entry: si -> next char to get.
  554. ; Exit: Char translated to upper case. al = character; si -> next character
  555. ; ---------------------------------------------------------------------
  556. ZCPARMC     PROC    NEAR
  557.         CMP     BYTE PTR [SI], 'a'      ; Q. below lower case a?
  558.         JB        ZCPARMC10            ; A. yes .. do not upcase
  559.         CMP     BYTE PTR [SI], 'z'      ; Q. above lower case z?
  560.         JA        ZCPARMC10            ; A. yes .. same
  561.         AND     BYTE PTR [SI], NOT 20H  ; .. translate to upper case
  562. ZCPARMC10:  LODSB                ; load the character in AL
  563.         RET                 ; .. and return to caller
  564. ZCPARMC     ENDP
  565. ; ---------------------------------------------------------------------
  566. ; This routine sets the appropriate argument pointer.
  567. ; Entry: si -> second character in argument.
  568. ; Exit: arg1 or arg2 pointer filled in. Carry set if more than 2 arguments
  569. ; ---------------------------------------------------------------------
  570. ZCARG        PROC    NEAR
  571.         LEA     BX, [SI-1]            ; bx -> argument
  572.         CMP     ARG1, 0            ; Q. arg1 filled in?
  573.         JNE     ZCARG10            ; A. yes .. check 2
  574.         MOV     ARG1, BX            ; save arg1 pointer
  575.         JMP     SHORT ZCARG90        ; .. exit ok!
  576. ZCARG10:    CMP     ARG2, 0            ; Q. arg2 filled in?
  577.         JE        ZCARG20            ; A. no .. fill it in
  578.         STC                 ; else .. error
  579.         RET                 ; .. and return to caller
  580. ZCARG20:    MOV     ARG2, BX            ; save arg2 pointer
  581. ZCARG90:    CLC                 ; show no error
  582.         RET                 ; return to caller
  583. ZCARG        ENDP
  584. ; ---------------------------------------------------------------------
  585. ; This routine determines whether we are the sender or receiver
  586. ; and which communication port is to be used.
  587. ; Entry: ARG1, ARG2 must be set, one pointing to COMx with an optional colon
  588. ; Exit: Send/receive flag is set properly. IO_BASE and INT_VECTOR are set.
  589. ;       Exits to DOS if no COM port or 2 COM ports specified.
  590. ; ---------------------------------------------------------------------
  591. ZCCOM        PROC    NEAR
  592.         MOV     SI, ARG1            ; si -> parm1
  593.         CALL    ZCCOMP            ; Q. receiver?
  594.         JC        ZCCOM10            ; A. no .. check parm2
  595.         OR        FLG, FLGR            ; else .. set receiver mode
  596. ZCCOM10:    MOV     BL, FLG            ; bx = flags
  597.         MOV     SI, ARG2            ; si -> parm2
  598.         CALL    ZCCOMP            ; Q. sender?
  599.         JC        ZCCOM20            ; A. no .. assure receiver
  600.         TEST    BL, FLGR            ; Q. Are we receiver?
  601.         JZ        ZCCOM80            ; A. No .. parms ok
  602. ZCCOM15:    LEA     DX, PARMERR         ; dx -> parameter error
  603.         CALL    ZCDIE            ; .. die gracefully
  604. ZCCOM20:    TEST    BL, FLGR            ; Q. Are we a receiver?
  605.         JZ        ZCCOM15            ; A. no .. issue error
  606. ZCCOM80:    CMP     AL, 1            ; Q. COM1?
  607.         JNE     ZCCOM85            ; A. no .. set up for COM2.
  608.         MOV     IO_BASE, 3F8H        ; set base port address
  609.         MOV     INT_VECTOR, 4        ; .. and interrupt number
  610.         RET                 ; return to caller
  611. ZCCOM85:    MOV     IO_BASE, 2F8H        ; set base port address
  612.         MOV     INT_VECTOR, 3        ; .. and interrupt number
  613.         RET                 ; return to caller
  614. ZCCOM        ENDP
  615. ; ---------------------------------------------------------------------
  616. ; This routine looks for a valid COMx: in the passed parameter.
  617. ; Entry: si -> string to check
  618. ; Exit: Carry set if not COMx: string; al = 1 or 2 for COM1: or COM2:
  619. ; ---------------------------------------------------------------------
  620. ZCCOMP        PROC    NEAR
  621.         PUSH    BX                ; save bx
  622.         MOV     BX, SI            ; bx -> argument
  623.         CLD                 ; set direction
  624.         LEA     DI, COM_STR         ; di -> 'COM'
  625.         MOV     CX, 3            ; cx = length of string
  626.      REPE   CMPSB                ; Q. 'COM' start the string?
  627.         JE        ZCCOMP10            ; A. yes.. continue
  628. ZCCOMP05:   STC                 ; show not a com port
  629.         POP     BX                ; restore bx
  630.         RET                 ; .. return to caller
  631. ZCCOMP10:   CMP     BYTE PTR [BX+4], ':'    ; Q. end in colon?
  632.         JE        ZCCOMP30            ; A. yes .. check which port
  633.         CMP     BYTE PTR [BX+4], 0        ; Q. non-colon end?
  634.         JNE     ZCCOMP05            ; A. no .. not a com parameter
  635. ZCCOMP30:   MOV     AL, [BX+3]            ; ah = ascii com port number.
  636.         SUB     AL, 30H            ; ah = binary com port number.
  637.         CMP     AL, 1            ; Q. below COM1?
  638.         JB        ZCCOMP05            ; A. yes .. invalid com port
  639.         CMP     AL, 2            ; Q. above com2?
  640.         JA        ZCCOMP05            ; A. yes .. invalid com port
  641.         CLC                 ; else .. good com port
  642.         POP     BX                ; restore bx
  643.         RET                 ; .. return to caller
  644. ZCCOMP        ENDP
  645. ; ---------------------------------------------------------------------
  646. ; This routine displays an error message and terminates.
  647. ; Entry: dx -> error message ended in dollar sign.
  648. ; Exit: Exits to DOS
  649. ; ---------------------------------------------------------------------
  650. ZCDIE        PROC    NEAR
  651.         TEST    FLG1, FLG1I         ; Q. initialized?
  652.         JZ        ZCDIE10            ; A. no .. print & return
  653.         PUSH    DX                ; else .. save message address
  654.         CALL    ZCRESET            ; .. reset system
  655.         POP     DX                ; .. restore message address
  656. ZCDIE10:    MOV     AH, 9            ; ah = print string
  657.         INT     21H             ; .. call dos to print error
  658.         MOV     AX, 4C01H            ; ax = exit
  659.         INT     21H             ; .. terminate routine
  660. ZCDIE        ENDP
  661. ; ---------------------------------------------------------------------
  662. ; This routine changes all arguments on the command line to upper case
  663. ; ---------------------------------------------------------------------
  664. ZCUC        PROC    NEAR
  665.         PUSH    SI                ; save caller regs
  666.         PUSH    DI
  667.         MOV     SI, 81H            ; si -> start of parm area
  668.         MOV     DI, SI            ; .. same for di
  669. ZCUC10:     LODSB                ; al = char
  670.         CMP     AL, 13            ; Q. end of line?
  671.         JE        ZCUC90            ; A. yes .. end of line!
  672.         CMP     AL, 'a'                 ; Q. is it below 'a'?
  673.         JB        ZCUC20            ; A. yes .. continue
  674.         CMP     AL, 'z'                 ; Q. is it above 'z'?
  675.         JA        ZCUC20            ; A. yes .. continue
  676.         SUB     AL, 20H            ; set to upper case
  677. ZCUC20:     STOSB                ; save the byte
  678.         JMP     ZCUC10            ; .. and continue
  679. ZCUC90:     POP     DI                ; restore caller regs
  680.         POP     SI
  681.         RET                 ; .. and return to caller
  682. ZCUC        ENDP
  683. ; ---------------------------------------------------------------------
  684. ; This routine sets the default drive and path.
  685. ; On the sending machine, the file name is also set up.
  686. ; ---------------------------------------------------------------------
  687. ZCFLSET     PROC    NEAR
  688.         MOV     DI, ARG1            ; di -> first arg
  689.         TEST    FLG, FLGR            ; Q. receiver?
  690.         JZ        ZCFLSET10            ; A. no .. continue
  691.         MOV     DI, ARG2            ; di -> second arg
  692. ZCFLSET10:  CMP     BYTE PTR [DI+1], ':'    ; Q. drive specified?
  693.         JNE     ZCFLSET20            ; A. no .. use current drive
  694.         MOV     DL, [DI]            ; dl = drive to use
  695.         SUB     DL, 'A'                 ; get requested drive number
  696.         MOV     AH, 0EH            ; set requested drive
  697.         INT     21H             ; .. via dos
  698.         ADD     DI, 2            ; di -> next part
  699. ZCFLSET20:  TEST    FLG, FLGR            ; Q. receiver?
  700.         JNZ     ZCFLSET50            ; A. yes .. filename not used
  701.         PUSH    DI                ; save pointer
  702.         MOV     BX, DI            ; bx -> start of area
  703.         XOR     AL, AL            ; al = search for null
  704.         MOV     CX, 128            ; very max to search
  705.         CLD
  706.     REPNE   SCASB                ; find end of arg
  707.         LEA     SI, [DI-1]            ; si -> nul
  708.         MOV     CX, 0            ; cx = # chars to move
  709.         CMP     SI, BX            ; Q. any file name
  710.         JE        ZCFLSET80            ; A. no .. error
  711. ZCFLSET30:  DEC     SI                ; si -> prev char
  712.         CMP     BYTE PTR [SI], '\'      ; Q. dir?
  713.         JE        ZCFLSET35            ; A. yes .. end of file name.
  714.         INC     CX                ; cx = char count
  715.         CMP     SI, BX            ; Q. done?
  716.         JE        ZCFLSET37            ; A. yes .. move file name
  717.         JMP     ZCFLSET30            ; .. continue
  718. ZCFLSET35:  INC     SI                ; si -> start of file name
  719. ZCFLSET37:  OR        CX, CX            ; Q. file name spec'd?
  720.         JZ        ZCFLSET80            ; A. no .. error
  721.         CMP     CX, 12            ; Q. too long?
  722.         JA        ZCFLSET85            ; A. yes .. error
  723.         PUSH    SI                ; save start pointer
  724.         MOV     DI, OFFSET FILENAME     ; di -> file name
  725.      REP    MOVSB                ; .. move in the file name
  726.         POP     SI                ; restore start pointer
  727.         POP     DI                ; .. and dir pointer
  728.         CMP     SI, BX            ; Q. at start of parm?
  729.         JE        ZCFLSET90            ; A. yes .. return
  730.         INC     BX                ; bx -> next char
  731.         CMP     SI, BX            ; Q. root only given?
  732.         JE        ZCFLSET40            ; A. yes .. continue
  733.         DEC     SI                ; si -> last \
  734. ZCFLSET40:  MOV     BYTE PTR [SI], 0        ; make dir ASCIIZ
  735. ZCFLSET50:  MOV     DX, DI            ; dx -> directory
  736.         MOV     AH, 3BH            ; ah = CHDIR opcode
  737.         INT     21H             ; .. change directory
  738.         JNC     ZCFLSET90            ; if ok .. continue
  739.         MOV     DX, OFFSET BADDIR        ; dx -> baddir request
  740.         CALL    ZCDIE            ; .. die now
  741. ZCFLSET80:  MOV     DX, OFFSET FILERR        ; dx -> no file specified
  742.         CALL    ZCDIE
  743. ZCFLSET85:  MOV     DX, OFFSET INVFIL        ; dx -> invalid filename spec'd
  744.         CALL    ZCDIE
  745. ZCFLSET90:  RET                 ; return to caller
  746. ZCFLSET     ENDP
  747. ; ---------------------------------------------------------------------
  748. ; This routine waits for n nbr of timer ticks to transpire.
  749. ; Entry: ax = nbr of timer ticks to wait
  750. ; ---------------------------------------------------------------------
  751. ZCWAIT        PROC    NEAR
  752.         ADD     AX, WAIT_COUNT        ; ax = count to wait till
  753. ZCWAIT10:   CMP     WAIT_COUNT, AX        ; Q. enough time elapsed?
  754.         JNA     ZCWAIT10            ; A. no .. loop
  755.         CALL    ZCTIMUP            ; .. update system timer
  756.         RET                 ; finally, return to caller
  757. ZCWAIT        ENDP
  758. ; ---------------------------------------------------------------------
  759. ; This routine retrieves the most recent LSR value.
  760. ; Exit: carry set if new value is found.; al = last LSR value detected.
  761. ; ---------------------------------------------------------------------
  762. ZCLSRGET    PROC    NEAR
  763.         CLI                 ; no interrupts
  764.         MOV     AL, LSR_VAL         ; al = last known LSR value
  765.         OR        LSR_NEW, 0            ; check if value is new
  766.         MOV     LSR_NEW, 0            ; .. reset it
  767.         STI                 ; .. allow interrupts
  768.         JNZ     ZCLSRGET90            ; .. jump if new value
  769.         CLC                 ; show no new value
  770.         RET                 ; .. and return to caller
  771. ZCLSRGET90: STC                 ; show new value
  772.         RET                 ; .. and return to caller
  773. ZCLSRGET    ENDP
  774. ; ---------------------------------------------------------------------
  775. ; This routine sends a break .2 seconds long.
  776. ; ---------------------------------------------------------------------
  777. ZCBREAK     PROC    NEAR
  778.         PUSH    AX                ; save caller regs
  779.         PUSH    BX
  780.         PUSH    DX
  781.         MOV     DX, IO_BASE         ; dx -> comm base register
  782.         ADD     DX, 3            ; dx = line control reg addr
  783.         IN        AL, DX            ; al = LCR contents
  784.         MOV     BL, AL            ; bl = LCR
  785.         OR        AL, 40H            ; .. turn on break bit
  786.         OUT     DX, AL            ; .. send a break
  787.         MOV     AX, 4            ; wait 4 ticks (~ .2 secs)
  788.         CALL    ZCWAIT            ; .. wait ...
  789.         AND     AL,NOT 40H            ; assure no break bit
  790.         MOV     AL,BL            ; al = old LSR contents
  791.         OUT     DX, AL            ; end the break
  792.         POP     DX                ; restore registers
  793.         POP     BX
  794.         POP     AX
  795.         RET                 ; return to caller
  796. ZCBREAK     ENDP
  797. ; ---------------------------------------------------------------------
  798. ; This routine clears the incomming buffer by resetting the buffer pointers.
  799. ; ---------------------------------------------------------------------
  800. ZCCLRCOM    PROC    NEAR
  801.         PUSH    RBUF_RPTR            ; push the receive pointer
  802.         POP     RBUF_GPTR            ; .. and pop get pointer
  803.         RET                 ; .. and return to caller
  804. ZCCLRCOM    ENDP
  805. ; ---------------------------------------------------------------------
  806. ; This routine tests if a break was recently detected.
  807. ; Exit: returns NZ if break found, zero if not.
  808. ; ---------------------------------------------------------------------
  809. ZCTSTBRK    PROC    NEAR
  810.         PUSH    AX                ; save caller registers
  811.         CALL    ZCLSRGET            ; get LSR value
  812.         JC        ZCTSTBRK80            ; .. test value if found
  813.         SUB     AH, AH            ; assure zero flag set
  814.         JMP     SHORT ZCTSTBRK90        ; .. return to caller
  815. ZCTSTBRK80: TEST    AL, LSR_BRK         ; Q. BREAK occur?
  816. ZCTSTBRK90: POP     AX                ; restore ax
  817.         RET                 ; return to caller
  818. ZCTSTBRK    ENDP
  819. ; ---------------------------------------------------------------------
  820. ; This routine will setup the baud rate for the com port.
  821. ; Entry: ax = baud rate index
  822. ; 0=115.2kb, 1=57.6kb, 2=38.4kb, 3=19.2kb, 4=9600, 5=4800
  823. ; ---------------------------------------------------------------------
  824. ZCBAUD        PROC    NEAR
  825.         PUSH    AX                ; save registers
  826.         PUSH    BX
  827.         PUSH    DX
  828.         PUSH    AX                ; save ax
  829.         MOV     DX, OFFSET TRYING        ; dx -> baud message
  830.         MOV     AH, 9            ; ah = print "$" message
  831.         INT     21H             ; .. tell 'em what we're doing
  832.         POP     AX                ; restore baud request
  833.         MOV     BX, AX            ; bx = baud index
  834.         MOV     CL, 3            ; .. shift for * 8
  835.         SHL     BX, CL            ; bx = baud index * 8
  836.         SUB     BX, AX            ; .. make that * 7
  837.         LEA     DX, BAUD_TABLE+1[BX]    ; dx -> $ message
  838.         MOV     BL, BAUD_TABLE[BX]        ; bl = divisor
  839.         XOR     BH, BH            ; .. upper byte off
  840.         MOV     AH, 9H            ; ah = print '$' message
  841.         INT     21H             ; .. display baud rate
  842.         TEST    FLG1, FLG1B         ; Q. ctl-break?
  843.         JZ        ZCBAUD10            ; A. no .. continue
  844.         MOV     DX, OFFSET SHUTDOWN_R1  ; dx -> shutdown msg
  845.         CALL    ZCDIE            ; .. end it all
  846. ZCBAUD10:   MOV     DX, IO_BASE         ; dx = io port base addr
  847.         ADD     DX, 3            ; dx = line control register
  848.         IN        AL, DX            ; al = lcr
  849.         OR        AL, LCR_DLAB        ; al = divisor latch enable
  850.         CLI                 ; stop interrupts, then ..
  851.         OUT     DX, AL            ; enable the setting of the dlab
  852.         SUB     DX, 3            ; dx = LSB port of divisor latch
  853.         MOV     AL, BL            ; al = LSB of new divisor
  854.         OUT     DX, AL            ; output the LSB portion
  855.         INC     DX                ; dx = MSB port of divisor latch
  856.         MOV     AL, BH            ; al = MSB of new divisor
  857.         OUT     DX, AL            ; output the MSB portion
  858.         ADD     DX, 2            ; dx = line control register
  859.         IN        AL, DX            ; al = lcr
  860.         AND     AL, NOT LCR_DLAB        ; .. set off dlab
  861.         OUT     DX, AL            ; .. restore line control register
  862.         STI                 ; .. and re-enable interrupts
  863.         POP     DX                ; restore caller's registers
  864.         POP     BX
  865.         POP     AX
  866.         RET                 ; ..and return to caller
  867. ZCBAUD        ENDP
  868. ; ---------------------------------------------------------------------
  869. ; This routine tests for the highest possible baud rate.
  870. ; ---------------------------------------------------------------------
  871. ZCSPEED     PROC    NEAR
  872.         PUSH    AX                ; save register
  873. ZCSPEED05:  CMP     BAUD_CNTR, 6        ; Q. comm attempts done?
  874.         JB        ZCSPEED10            ; A. no .. try again
  875.         MOV     DX, OFFSET SPDERROR     ; dx -> Comm not possible
  876.         CALL    ZCDIE            ; die now
  877. ZCSPEED10:  MOV     AL, BAUD_CNTR        ; al = baud rate counter
  878.         CBW                 ; ax = baud rate counter
  879.         CALL    ZCBAUD            ; .. setup baud rate
  880.         MOV     AX, 2            ; wait .1 sec
  881.         CALL    ZCWAIT            ; .. for all to calm down
  882.         MOV     WAIT_COUNT, 0        ; .. and wait counter
  883.         CALL    ZCCLRCOM            ; .. clear out receive buffer
  884. ZCSPEED11:  MOV     AL, STX            ; al = send stx
  885.         CALL    ZCPUTC            ; .. send char
  886.         MOV     AX, 1            ; wait 1 tick
  887.         CALL    ZCWAIT            ; .. wait
  888.         CALL    ZCGETC            ; Q. char available?
  889.         JC        ZCSPEED15            ; A. no .. try again
  890.         CMP     AL, STX            ; Q. stx?
  891.         JE        ZCSPEED17            ; A. yes .. continue
  892. ZCSPEED15:  TEST    FLG1, FLG1B         ; Q. ctl-break?
  893.         JNZ     ZCSPEED16            ; A. yes .. end it now
  894.         TEST    FLG, FLGW            ; Q. wait forever?
  895.         JNZ     ZCSPEED11            ; A. yes .. do so.
  896.         MOV     AX, DSRWAIT         ; ax = current wait count
  897.         CMP     WAIT_COUNT, AX        ; Q. time expire?
  898.         JNA     ZCSPEED11            ; A. no.. try again
  899.         MOV     DX, OFFSET NOTUP        ; dx -> error message
  900.         CALL    ZCDIE            ; .. die gracefully
  901. ZCSPEED16:  MOV     DX, OFFSET SHUTDOWN_R1  ; dx -> ZCOPY done msg
  902.         CALL    ZCDIE            ; .. end gracefully
  903. ZCSPEED17:  CALL    ZCCLRCOM            ; clear receive buffer
  904.         CALL    ZCLSRGET            ; assure old lsr killed
  905.         MOV     DSRWAIT, SEC_3        ; reset dsrwait
  906.         TEST    FLG,FLGR            ; Q. are we the receiver?
  907.         JNZ     ZCSPEED50            ; A. yes .. sync as such
  908. ; SENDING NODE
  909.         CALL    ZCSPDA            ; Q. first part ok?
  910.         JC        ZCSPEED80            ; A. no .. try next baud
  911.         CALL    ZCSPDB            ; Q. second part ok?
  912.         JC        ZCSPEED80            ; A. no .. try next baud
  913.         JMP     SHORT ZCSPEED90        ; else.. exit ok
  914. ; RECEIVING NODE
  915. ZCSPEED50:  CALL    ZCSPDB            ; Q. answer to first part ok?
  916.         JC        ZCSPEED80            ; A. no .. try next baud
  917.         CALL    ZCSPDA            ; Q. answer to second ok?
  918.         JNC     ZCSPEED90            ; A. no .. try next baud
  919. ZCSPEED80:  INC     BAUD_CNTR            ; next baud rate
  920.         JMP     ZCSPEED05            ; .. try re-sync
  921. ZCSPEED90:  CALL    ZCCLRCOM            ; assure all bytes cleared
  922.         MOV     DX, OFFSET SPDSET        ; dx -> ok message
  923.         MOV     AH, 9            ; ah = print to "$"
  924.         INT     21H             ; display message
  925.         POP     AX                ; restore caller's regs
  926.         RET                 ; .. and return to caller
  927. ZCSPEED     ENDP
  928. ; ---------------------------------------------------------------------
  929. ; This routine is one side of the set baud rate routine -- sender.
  930. ; Exit: Carry set if unsuccessful.
  931. ; ---------------------------------------------------------------------
  932. ZCSPDA        PROC    NEAR
  933.         MOV     DX, WAIT_COUNT        ; dx = current wait count
  934.         ADD     DX, 6            ; dx = future wait count
  935. ZCSPDA12:   MOV     AL, SYNC_BYTE        ; al = start signature byte
  936.         CALL    ZCPUTC            ; .. put it out
  937.         MOV     AX, 1            ; ax = wait 1 tick
  938.         CALL    ZCWAIT            ; .. wait 1 tick
  939.         CALL    ZCGETC            ; Q. char available?
  940.         JC        ZCSPDA17            ; A. no .. continue
  941.         CMP     AL, STX            ; Q. stx?
  942.         JNE     ZCSPDA15            ; A. no .. continue
  943.         CALL    ZCPUTC            ; .. send STX back
  944.         JMP     ZCSPDA12            ; .. and do it again
  945. ZCSPDA15:   CMP     AL, ACK            ; Q. ack?
  946.         JE        ZCSPDA20            ; A. yes .. send sync string
  947. ZCSPDA17:   CMP     DX, WAIT_COUNT        ; Q. time up?
  948.         JA        ZCSPDA12            ; A. no .. try again
  949.         JMP     SHORT ZCSPDA80        ; return unsuccessful
  950. ;    SYNC BYTE RECEIVED .. SEND STRING
  951. ZCSPDA20:   MOV     AL, SYNC_END        ; al = end of sync sequence
  952.         CALL    ZCPUTC            ; .. write it
  953.         MOV     CX, SYNC_LEN        ; Length of sync string
  954.         XOR     AL, AL            ; al = sync char
  955. ZCSPDA25:   CALL    ZCPUTC            ; put out sync string char
  956.         ADD     AL, SYNC_INC        ; .. calc next char
  957.         LOOP    ZCSPDA25            ; .. continue until done
  958.         MOV     AX, 9            ; ax = .5 sec
  959.         CALL    ZCWAIT            ; .. wait .5 secs
  960.         CALL    ZCTSTBRK            ; Q. did break occur?
  961.         JNZ     ZCSPDA90            ; A. yes .. return successful
  962. ZCSPDA80:   STC                 ; return unsuccessful
  963.         RET                 ; .. return to caller
  964. ZCSPDA90:   CLC                 ; return successful
  965.         RET                 ; .. return to caller
  966. ZCSPDA        ENDP
  967. ; ---------------------------------------------------------------------
  968. ; This routine is one side of the set baud rate routine -- receiver.
  969. ; Exit: Carry set if unsuccessful.
  970. ; ---------------------------------------------------------------------
  971. ZCSPDB        PROC    NEAR
  972.         MOV     WAIT_COUNT, 0        ; set wait counter to 0
  973. ZCSPDB10:   CALL    ZCGETC            ; Q. char available?
  974.         JNC     ZCSPDB20            ; A. yes .. check it.
  975.         CMP     WAIT_COUNT, 19        ; Q. 1 second?
  976.         JB        ZCSPDB10            ; A. no .. keep trying.
  977.         JMP     SHORT ZCSPDB80        ; else .. return unsuccessful
  978. ZCSPDB20:   CMP     AL, SYNC_BYTE        ; Q. sync byte received?
  979.         JNE     ZCSPDB25            ; A. yes .. answer it.
  980.         MOV     AL, ACK            ; al = ack
  981.         CALL    ZCPUTC            ; .. tell 'em wt got it.
  982.         JMP     ZCSPDB10            ; .. try for sync_end
  983. ZCSPDB25:   CMP     AL, SYNC_END        ; Q. end of sync bytes?
  984.         JE        ZCSPDB30            ; A. yes .. expect sync string.
  985.         CMP     AL, STX            ; Q. still stxing?
  986.         JNE     ZCSPDB10            ; A. no .. continue
  987.         CALL    ZCPUTC            ; else .. tell 'em we got it
  988.         JMP     ZCSPDB10            ; .. and try again
  989. ZCSPDB30:   CALL    ZCSPDCHK            ; Q. block receive ok?
  990.         JC        ZCSPDB80            ; A. no .. return unsuccessful
  991.         CALL    ZCBREAK            ; else .. tell 'em we're talking
  992.         JMP     SHORT ZCSPDB90        ; .. and return to caller
  993. ZCSPDB80:   MOV    AX, SEC_1            ; wait 1 second ...
  994.         CALL   ZCWAIT            ; .. wait
  995.         STC                 ; return unsuccessful
  996.         RET                 ; .. return to caller
  997. ZCSPDB90:   CLC                 ; return successful
  998.         RET                 ; .. return to caller
  999. ZCSPDB        ENDP
  1000. ; ---------------------------------------------------------------------
  1001. ; This routine calculates a CRC for a block of characters.
  1002. ; Entry: si -> character block; cx = # characters to include in calc
  1003. ; Exit: ax = CRC
  1004. ; ---------------------------------------------------------------------
  1005. ZCCRC        PROC    NEAR
  1006.         PUSH    SI                ; save caller regs
  1007.         PUSH    BX
  1008.         PUSH    CX
  1009.         XOR     AX, AX            ; ax = start value (0)
  1010.         ADD     CX, 2            ; do 2 "additional" bytes
  1011. ZCCRC05:    PUSH    CX                ; save cx
  1012.         MOV     BL, BYTE PTR [SI]        ; bl = next byte
  1013.         INC     SI                ; si -> next character
  1014.         CMP     CX, 2            ; Q. more than 2 chars left?
  1015.         JA        ZCCRC08            ; A. yes .. continue
  1016.         MOV     BL, 0FFH            ; .. set to 0ffh
  1017. ZCCRC08:    MOV     CX, 8            ; 8 bits ..
  1018. ZCCRC10:    XOR     BH, BH            ; clear bh
  1019.         SHL     BX, 1            ; shift the next char
  1020.         SHL     AX, 1            ; Q. high bit on?
  1021.         JNC     ZCCRC20            ; A. no .. do not xor CRC value
  1022.         OR        AL, BH            ; .. include the next bit
  1023.         XOR     AX, CRC_VAL         ; .. xor the CRC value
  1024.         LOOP    ZCCRC10            ; loop 'til done
  1025.         JMP     SHORT ZCCRC30        ; .. continue when done
  1026. ZCCRC20:    OR        AL, BH            ; include the next bit
  1027.         LOOP    ZCCRC10            ; loop 'til done
  1028. ZCCRC30:    POP     CX                ; restore char count
  1029.         LOOP    ZCCRC05            ; .. continue until done
  1030.         POP     CX                ; restore caller's regs
  1031.         POP     BX
  1032.         POP     SI
  1033.         RET
  1034. ZCCRC        ENDP
  1035. ; ---------------------------------------------------------------------
  1036. ; This routine builds a block and sends it to the other machine.
  1037. ; Block Format: STX crc(2) len(2) blk#(2) cmd(1) data(n) ETX
  1038. ; where: STX=02h, crc=16 bit error check value, len=length of block (i.e.
  1039. ; data length+3), blk#=number of this block, 0 thru 65535, wrapping
  1040. ; cmd=command/identifier for this block, data=send characters, ETX=03h
  1041. ; Entry: al=command; si->chars to send; cx=# chars to include in calc
  1042. ; Exit: Returns when transmission complete.
  1043. ; ---------------------------------------------------------------------
  1044. ZCBLKSND    PROC    NEAR
  1045.         PUSH    AX                ; save caller's regs
  1046.         PUSH    BX
  1047.         PUSH    DX
  1048.         PUSH    SI
  1049.         PUSH    DI
  1050.         PUSH    CX
  1051.         MOV     DI, SBUF            ; di -> send buffer
  1052.         TEST    FLG1, FLG1B         ; Q. control-break detected?
  1053.         JZ        ZCBLKSND05            ; A. no .. continue
  1054.         MOV     AL, DIENOW            ; al = die now command
  1055.         OR        FLG1, FLG1S         ; .. show shutdown sent
  1056. ZCBLKSND05: PUSH    AX
  1057.         CLD                 ; we want to increment
  1058.         MOV     AL, STX            ; al = stx value
  1059.         STOSB                ; .. save in send buffer
  1060.         ADD     DI, 2            ; di -> past CRC bytes
  1061.         MOV     AX, CX            ; ax = characters string len
  1062.         ADD     AX, 3            ; ax = chars + cmd + blk# len
  1063.         STOSW                ; .. save the length
  1064.         MOV     AX, SEND_BLKNO        ; ax = next send block number
  1065.         STOSW                ; save send block number
  1066.         POP     AX                ; restore the command
  1067.         STOSB                ; save the command
  1068.         JCXZ    ZCBLKSND10            ; jump if no bytes to move
  1069.      REP    MOVSB                ; .. move in the chars
  1070. ZCBLKSND10: MOV     AL, ETX            ; al = etx value
  1071.         STOSB                ; .. save at end of buffer
  1072.         MOV     BX, SBUF            ; bx -> buffer
  1073.         MOV     CX, [BX+MLEN]        ; cx = blk#+cmd+data len
  1074.         LEA     SI, [BX+MBLKNO]        ; si -> blk#/cmd/data area
  1075.         CALL    ZCCRC            ; calculate the crc
  1076.         MOV     [BX+MCRC], AX        ; .. save in the buffer
  1077.         MOV     DL, RETRIES         ; dl = max retries
  1078. ZCBLKSND20: MOV     SI, BX            ; si -> buffer
  1079.         MOV     CX, [BX+MLEN]        ; cx = blk#/cmd/data length
  1080.         ADD     CX, MOHEAD            ; characters to send
  1081. ZCBLKSND25: LODSB                ; al = char to send
  1082.         CALL    ZCPUTC            ; .. send it
  1083.         LOOP    ZCBLKSND25            ; .. loop until all sent
  1084.         MOV     BX, WAIT_COUNT        ; bx = now
  1085.         ADD     BX, SEC_10            ; bx = later, 10 seconds
  1086. ZCBLKSND35: CALL    ZCWAITC            ; .. and wait for a character
  1087.         JC        ZCBLKSND60            ; .. timeout .. see if any resp
  1088.         CMP     AL, ACK            ; Q. send ok?
  1089.         JE        ZCBLKSND80            ; A. yes .. continue
  1090.         CMP     AL, NAK            ; Q. send bad?
  1091.         JE        ZCBLKSND75            ; A. yes .. restart send
  1092.         CMP     AL, RLR            ; Q. request last response
  1093.         JE        ZCBLKSND50            ; A. yes .. continue
  1094.         JMP     SHORT ZCBLKSND70        ; .. clear buffer, retry
  1095. ZCBLKSND50: CALL    ZCGETC            ; kill the rlr
  1096.         MOV     AL, LAST_RESP        ; al = last response sent
  1097.         CALL    ZCPUTC            ; .. tell the other machine
  1098.         MOV     BX, SBUF            ; bx -> buffer
  1099.         JMP     ZCBLKSND20            ; .. and resend our block
  1100. ZCBLKSND60: CMP     WAIT_COUNT, BX        ; Q. 10 seconds yet
  1101.         JB        ZCBLKSND65            ; A. no .. continue
  1102.         MOV     DX, OFFSET NOTUP        ; dx -> error message
  1103.         CALL    ZCDIE            ; .. and die now
  1104. ZCBLKSND65: MOV     AL, RLR            ; al = get last response
  1105.         CALL    ZCPUTC            ; .. request last response
  1106.         INC     ERRORS            ; .. increment the error count
  1107.         JMP     ZCBLKSND35            ; .. and ask other machine
  1108. ZCBLKSND70: CALL    ZCGETC            ; get a char
  1109.         CALL    ZCWAITC            ; .. wait for another to arrive
  1110.         JNC     ZCBLKSND70            ; .. if another does, get it
  1111.         JMP     ZCBLKSND65            ; .. get last response now.
  1112. ZCBLKSND75: CALL    ZCGETC            ; .. kill the nak
  1113.         INC     ERRORS            ; increment error count
  1114.         MOV     BX, SBUF            ; bx -> buffer
  1115.         JMP     ZCBLKSND20            ; .. retry
  1116. ZCBLKSND80: CALL    ZCGETC            ; kill the character
  1117.         INC     SEND_BLKNO            ; next send block number
  1118.         TEST    FLG1, FLG1S         ; Q. shutdown sent?
  1119.         JZ        ZCBLKSND90            ; A. no .. continue
  1120.         MOV     DX, OFFSET SHUTDOWN_R1  ; dx -> shutdown request
  1121.         CALL    ZCDIE            ; .. and end it all
  1122. ZCBLKSND90: POP     CX                ; restore length
  1123.         POP     DI
  1124.         POP     SI
  1125.         POP     DX
  1126.         POP     BX
  1127.         POP     AX
  1128.         RET
  1129. ZCBLKSND    ENDP
  1130. ; ---------------------------------------------------------------------
  1131. ; This routine waits for a character, .5 secs.
  1132. ; Exit: carry=TIMEOUT; no carry=char received; al = character
  1133. ; ---------------------------------------------------------------------
  1134. ZCWAITC     PROC    NEAR
  1135.         PUSH    BX
  1136.         MOV     BX, WAIT_COUNT        ; bx = now ..
  1137.         ADD     BX, 13            ; bx = later (.5 secs) ..
  1138. ZCWAITC10:  CALL    ZCCLA            ; Q. char available?
  1139.         JNC     ZCWAITC90            ; A. yes .. return
  1140.         CMP     WAIT_COUNT, BX        ; Q. .5 secs?
  1141.         JB        ZCWAITC10            ; A. no .. continue
  1142.         STC                 ; show timeout
  1143.         JMP     SHORT ZCWAITC90        ; .. return to caller
  1144. ZCWAITC90:  POP     BX                ; .. return to caller
  1145.         RET                 ; .. and return to caller
  1146. ZCWAITC     ENDP
  1147. ; ---------------------------------------------------------------------
  1148. ; This routine receives a block, checks CRC, ACKs its reception and places
  1149. ; the data in wbuf.  STX of block should have already been read and discarded
  1150. ; The block format is documented in ZCBLKSND.
  1151. ; Exit: Carry - block not available (timeout or bad crc).
  1152. ; No Carry - block received ok, in wbuf, starting w/CRC; al = command byte
  1153. ; ---------------------------------------------------------------------
  1154. ZCBLKRCV    PROC    NEAR
  1155.         PUSH    BX                ; save regs
  1156.         PUSH    CX
  1157.         PUSH    DX
  1158.         PUSH    DI
  1159.         PUSH    SI
  1160.         MOV     BX, WAIT_COUNT        ; bx = current timer
  1161.         ADD     BX, 5            ; bx = max time to wait until
  1162.         MOV     CX, 0            ; zero out char counter
  1163.         MOV     DI, WBUF            ; di -> wbuf
  1164.         ADD     DI, MCRC            ; di -> work buffer crc field
  1165.         MOV     DX, -1            ; .. dummy # chars needed
  1166. ZCBLKRCV10: CALL    ZCGETC            ; Q. char available?
  1167.         JC        ZCBLKRCV30            ; A. no .. error
  1168.         MOV     BX, WAIT_COUNT        ; bx = current timer
  1169.         ADD     BX, 5            ; .. next time to wait until
  1170.         STOSB                ; put in wbuf
  1171.         INC     CX                ; cx = # chars
  1172.         CMP     CX, 4            ; Q. len in yet?
  1173.         JNE     ZCBLKRCV20            ; A. no .. continue
  1174.         MOV     DX, [DI-2]            ; dx = message len
  1175.         ADD     DX, 5            ; dx = # character needed
  1176. ZCBLKRCV20: CMP     CX, DX            ; Q. enough chars received?
  1177.         JE        ZCBLKRCV50            ; A. yes .. check 'em out.
  1178.         JMP     SHORT ZCBLKRCV10        ; else .. get another
  1179. ZCBLKRCV30: CMP     WAIT_COUNT, BX        ; Q. timeout?
  1180.         JA        ZCBLKRCV70            ; A. yes .. NAK
  1181.         JMP     SHORT ZCBLKRCV10        ; .. try again
  1182. ZCBLKRCV50: MOV     SI, WBUF            ; si -> wbuf
  1183.         MOV     CX, [SI+MLEN]        ; dx = length
  1184.         PUSH    SI                ; save wbuf pointer
  1185.         LEA     SI, [SI+MBLKNO]        ; si -> blk#
  1186.         CALL    ZCCRC            ; .. calc crc
  1187.         POP     SI                ; si -> wbuf
  1188.         CMP     AX, [SI+MCRC]        ; Q. crc same?
  1189.         JE        ZCBLKRCV55            ; A. yes .. ok
  1190.         JMP     SHORT ZCBLKRCV70        ; .. else .. NAK
  1191. ZCBLKRCV55: MOV     AX, RCV_BLKNO        ; ax = expected block
  1192.         CMP     AX, [SI+MBLKNO]        ; Q. same block?
  1193.         JE        ZCBLKRCV80            ; A. yes .. continue
  1194.         CALL    ZCCLRCOM            ; else .. clear com buffer
  1195.         MOV     AL, ACK            ; al = ack
  1196.         MOV     LAST_RESP, AL        ; .. save as last resp
  1197.         CALL    ZCPUTC            ; .. ack last block
  1198.         STC                 ; show no receive
  1199.         JMP     SHORT ZCBLKRCV90        ; .. return to caller
  1200. ZCBLKRCV70: MOV     AL, NAK            ; al = NAK
  1201.         MOV     LAST_RESP, AL        ; .. save as last resp
  1202.         CALL    ZCPUTC            ; .. tell remote .. no go
  1203.         INC     ERRORS            ; increment error count
  1204.         STC                 ; show error condition
  1205.         JMP     SHORT ZCBLKRCV90        ; .. and return to caller
  1206. ZCBLKRCV80: MOV     AL, ACK            ; al = ACK
  1207.         MOV     LAST_RESP, AL        ; .. save as last resp
  1208.         CALL    ZCPUTC            ; .. tell remote .. all is go
  1209.         INC     RCV_BLKNO            ; next block number
  1210.         MOV     AL, [SI+MCMD]        ; al = received command
  1211.         CMP     AL, DIENOW            ; Q. die now?
  1212.         JNE     ZCBLKRCV85            ; A. no .. continue
  1213.         MOV     DX, OFFSET SHUTDOWN_R1  ; dx -> shutdown msg
  1214.         CALL    ZCDIE            ; .. end it all now
  1215. ZCBLKRCV85: CLC                 ; show received ok
  1216. ZCBLKRCV90: POP     SI                ; restore regs
  1217.         POP     DI                ; save regs
  1218.         POP     DX
  1219.         POP     CX
  1220.         POP     BX
  1221.         RET
  1222. ZCBLKRCV    ENDP
  1223. ; ---------------------------------------------------------------------
  1224. ; Determine if chars are available.  If so, attempt to receive a block.
  1225. ; Exit: CY=block not available; NC=block received ok, in wbuf, starting w/CRC.
  1226. ;       al = command byte
  1227. ; ---------------------------------------------------------------------
  1228. ZCTRYRCV    PROC    NEAR
  1229.         CALL    ZCGETC            ; Q. any chars available?
  1230.         JC        ZCTRYRCV90            ; A. no .. exit
  1231.         CMP     AL, STX            ; Q. stx received?
  1232.         JNE     ZCTRYRCV60            ; A. no .. exit
  1233.         CALL    ZCBLKRCV            ; receive a block
  1234.         JMP     SHORT ZCTRYRCV90        ; tell 'em how it went
  1235. ZCTRYRCV60: CMP     AL, RLR            ; Q. request of last resp?
  1236.         JNE     ZCTRYRCV70            ; A. no .. show no block
  1237.         MOV     AL, NAK            ; al = resend last block
  1238.         CALL    ZCPUTC            ; .. send the response
  1239. ZCTRYRCV70: STC                 ; show no block
  1240. ZCTRYRCV90: RET                 ; .. and exit
  1241. ZCTRYRCV    ENDP
  1242. ; ---------------------------------------------------------------------
  1243. ; This routine subtracts the IO_LEN from the bytes in the current file, and
  1244. ; prints the number of blocks left to transfer on each 10h blocks transferred
  1245. ; ---------------------------------------------------------------------
  1246. ZCPRTLFT    PROC    NEAR
  1247.         PUSH    AX                ; save regs
  1248.         PUSH    CX
  1249.         CMP     WORD PTR BYTESLFT+2, 0    ; Q. < 64k bytes to go?
  1250.         JA        ZCPRTLFT10            ; A. no .. continue
  1251.         CMP     WORD PTR BYTESLFT, IO_LEN    ; Q. io_len left?
  1252.         JA        ZCPRTLFT10            ; A. yes .. continue
  1253.         MOV     WORD PTR BYTESLFT, 0    ; zero out bytes left
  1254.         JMP     SHORT ZCPRTLFT80        ; ... and print!
  1255. ZCPRTLFT10: SUB     WORD PTR BYTESLFT, IO_LEN    ; subtract transferred
  1256.         SBB     WORD PTR BYTESLFT+2, 0    ; .. from left to xfer
  1257.         MOV     AX, WORD PTR BYTESLFT    ; get # bytes left (lws)
  1258.         AND     AX, 1E00H            ; Q. 16 block boundary?
  1259.         JNZ     ZCPRTLFT90            ; A. no .. skip print
  1260. ZCPRTLFT80: CALL    ZCPRBLKS            ; .. print # blocks left
  1261. ZCPRTLFT90: POP     CX                ; restore regs
  1262.         POP     AX
  1263.         RET                 ; .. return to caller
  1264. ZCPRTLFT    ENDP
  1265. ; ---------------------------------------------------------------------
  1266. ; This routine calculates and prints the number of blocks left.
  1267. ; ---------------------------------------------------------------------
  1268. ZCPRBLKS    PROC    NEAR
  1269.         PUSH    AX                ; restore es
  1270.         PUSH    BX
  1271.         PUSH    CX
  1272.         PUSH    DX
  1273.         PUSH    DI
  1274.         PUSH    ES                ; save es
  1275.         LES     BX, BYTESLFT        ; bx = bytes left
  1276.         MOV     DX, ES            ; dx = high order
  1277.         POP     ES                ; .. restore es
  1278.         CLC                 ; clear the carry bit
  1279.         RCR     DX, 1            ; move lsb of dx to cf
  1280.         RCR     BX, 1            ; .. continue in bx
  1281.         MOV     BL, BH            ; bl = low order
  1282.         MOV     BH, DL            ; bh = middle
  1283.         MOV     DL, DH            ; dl = hight
  1284.         XOR     DH, DH            ; .. high is zero
  1285.         MOV     DI, OFFSET B_LEFT        ; di -> blocks left
  1286.         STD                 ; .. and count down
  1287.         MOV     CX, 6            ; .. max bytes to do
  1288. ZCPRBLKS20: PUSH    CX                ; save counter
  1289.         MOV     AL, BL            ; al = digit
  1290.         AND     AL, 0FH            ; .. upper bits off
  1291.         OR        AL, 30H            ; change to printable
  1292.         CMP     AL, '9'                 ; Q. above '9'?
  1293.         JNA     ZCPRBLKS25            ; A. no .. continue
  1294.         ADD     AL, 7            ; .. convert to prtable
  1295. ZCPRBLKS25: STOSB                ; save the char
  1296.         MOV     CL, 4            ; cl = shift value
  1297. ZCPRBLKS27: CLC                 ; clear the carry bit
  1298.         RCR     DX, 1            ; rotate dx:bs ..
  1299.         RCR     BX, 1            ; .. by as many bits as needed
  1300.         LOOP    ZCPRBLKS27            ; .. continue
  1301.         POP     CX                ; .. restore count
  1302.         OR        BX, BX            ; Q. all done?
  1303.         JNZ     ZCPRBLKS30            ; A. no .. continue
  1304.         OR        DX, DX            ; Q. all done?
  1305.         JZ        ZCPRBLKS40            ; A. yes .. print it
  1306. ZCPRBLKS30: LOOP    ZCPRBLKS20            ; .. xlat next char
  1307. ZCPRBLKS40: LEA     DX, [DI+1]            ; dx -> message to print
  1308.         MOV     AH, 9            ; .. ah = print ascii$
  1309.         INT     21H             ; .. ask DOS to do it
  1310.         CLD                 ; .. return direction to up
  1311.         POP     DI                ; restore registers
  1312.         POP     DX
  1313.         POP     CX
  1314.         POP     BX
  1315.         POP     AX
  1316.         RET
  1317. ZCPRBLKS    ENDP
  1318. ; ---------------------------------------------------------------------
  1319. ; Determine if speed sync string received ok.
  1320. ; Entry: Receive buffer should have sync string.
  1321. ; Exit: Carry bit set indicates sync error.
  1322. ; ---------------------------------------------------------------------
  1323. ZCSPDCHK    PROC    NEAR
  1324.         CALL    ZCLSRGET            ; Q. did lsr change?
  1325.         JNC     ZCSPDCHK10            ; A. no .. check received string
  1326.         AND     AL, LSR_ERR         ; Q. any error?
  1327.         JNZ     ZCSPDCHK90            ; A. yes .. return.
  1328. ZCSPDCHK10: MOV     CX, SYNC_LEN        ; len of speed set
  1329.         MOV     BL, 0            ; start of speed string
  1330. ZCSPDCHK20: MOV     AX, WAIT_COUNT        ; ax = wait counter
  1331.         ADD     AX, 2            ; .. wait 2 ticks, max
  1332. ZCSPDCHK25: CALL    ZCGETC            ; Q. any char?
  1333.         JNC     ZCSPDCHK30            ; A. yes ... check it
  1334.         CMP     WAIT_COUNT, AX        ; Q. count up?
  1335.         JB        ZCSPDCHK25            ; A. no .. check again.
  1336.         JMP     SHORT ZCSPDCHK90        ; .. else .. error
  1337. ZCSPDCHK30: CMP     AL, BL            ; Q. same character?
  1338.         JNE     ZCSPDCHK90            ; A. no .. error
  1339.         ADD     BL, SYNC_INC        ; bl = next char
  1340.         LOOP    ZCSPDCHK20            ; .. check next char
  1341.         CLC                 ; show sync ok
  1342.         RET                 ; .. return to caller
  1343. ZCSPDCHK90: STC                 ; show no sync
  1344.         RET                 ; .. return to caller
  1345. ZCSPDCHK    ENDP
  1346. ; ---------------------------------------------------------------------
  1347. ; This routine causes a prompt to be placed on both machines.
  1348. ; The response may be given from either machine.
  1349. ; Entry: di -> prompt message, ended in $
  1350. ; Exit: al = response
  1351. ; ---------------------------------------------------------------------
  1352. ZCSPROMPT   PROC    NEAR
  1353.         PUSH    BX                ; save registers
  1354.         PUSH    CX
  1355.         PUSH    DX
  1356.         PUSH    SI
  1357.         PUSH    DI
  1358.         CLD                 ; clear direction
  1359.         PUSH    DI                ; save initial pointer
  1360.         MOV     AL, '$'                 ; Look for $ character
  1361.         MOV     CX, 100            ; .. max 100 chars
  1362.    REPNE    SCASB                ; .. find the value
  1363.         MOV     CX, DI            ; cx -> char after '$'
  1364.         POP     SI                ; si -> start of string
  1365.         SUB     CX, SI            ; cx = length of string
  1366.         MOV     AL, OPR_PROMPT        ; al = command (prompt)
  1367.         CALL    ZCBLKSND            ; Q. send ok?
  1368.         MOV     DX, SI            ; bx -> start of string
  1369.         CALL    ZCPRESP            ; prompt & get response
  1370.         POP     DI                ; restore regs
  1371.         POP     SI
  1372.         POP     DX
  1373.         POP     CX
  1374.         POP     BX
  1375.         RET
  1376. ZCSPROMPT   ENDP
  1377. ; ---------------------------------------------------------------------
  1378. ; This routine displays a prompt and waits for a response.
  1379. ; The response may be given from either machine.
  1380. ; Entry: dx -> prompt message, ended in $
  1381. ; Exit: al = response; Carry=response came from remote machine
  1382. ;    no carry - response came from local machine
  1383. ; ---------------------------------------------------------------------
  1384. ZCPRESP     PROC    NEAR
  1385.         PUSH    SI                ; save regs
  1386.         PUSH    BX
  1387.         PUSH    CX
  1388.         MOV     AH, 09H            ; al = print string
  1389.         INT     21H             ; .. display prompt
  1390.         MOV     BX, WBUF            ; bx -> wbuf
  1391. ZCPRESP10:  CALL    ZCTIMUP            ; update timer
  1392.         MOV     AH, 1            ; ah = query keyboard
  1393.         INT     16H             ; Q. is a key available?
  1394.         JZ        ZCPRESP20            ; A. no .. check for block
  1395.         MOV     AH, 0            ; al = get key
  1396.         INT     16H             ; al = key typed
  1397.         PUSH    AX                ; save ax
  1398.         MOV     [BX], AL            ; save response in wbuf
  1399.         MOV     AL, OPR_REPLY        ; al = command
  1400.         MOV     SI, WBUF            ; si -> wbuf
  1401.         MOV     CX, 1            ; cx = # chars to send
  1402.         CALL    ZCBLKSND            ; send the block
  1403.         POP     AX                ; restore reply
  1404.         CLC                 ; response from local
  1405.         JMP     SHORT ZCPRESP90        ; .. return to caller
  1406. ZCPRESP20:  CALL    ZCTRYRCV            ; Q. block available?
  1407.         JC        ZCPRESP10            ; A. no .. try again
  1408.         CMP     BYTE PTR [BX+MCMD], OPR_REPLY   ; Q. reply?
  1409.         JNE     ZCPRESP10                ; A. no .. try again
  1410.         MOV     AL, BYTE PTR [BX+MDATA] ; al = response
  1411.         STC                 ; response from remote
  1412. ZCPRESP90:  POP     CX                ; restore regs
  1413.         POP     BX
  1414.         POP     SI
  1415.         RET                 ; return to caller
  1416. ZCPRESP     ENDP
  1417. ; ---------------------------------------------------------------------
  1418. ; This routine displays the prompt sent from the other machine.
  1419. ; Entry: wbuf contains received prompt
  1420. ; ---------------------------------------------------------------------
  1421. ZCPPROMPT   PROC    NEAR
  1422.         PUSH    AX                ; save ax
  1423.         MOV     DX, WBUF            ; dx -> received buffer
  1424.         ADD     DX, MDATA            ; dx -> prompt
  1425.         CALL    ZCPRESP            ; get response
  1426.         POP     AX                ; restore ax
  1427.         RET                 ; return to caller
  1428. ZCPPROMPT   ENDP
  1429. ; ---------------------------------------------------------------------
  1430. ; This routine sends the requested file.
  1431. ; Entry: handle = currently opened file.
  1432. ; ---------------------------------------------------------------------
  1433. ZCSEND        PROC    NEAR
  1434.         PUSH    AX                ; save regs
  1435.         PUSH    BX
  1436.         PUSH    CX
  1437.         PUSH    DX
  1438.         PUSH    SI
  1439.         MOV     AL, CRE_FILE        ; al = file header cmd
  1440.         MOV     CX, DTA_LEN         ; cx = find file data
  1441.         MOV     SI, DTA            ; si -> dta
  1442.         CALL    ZCBLKSND            ; send the request
  1443.         CALL    ZCRECV            ; get the response
  1444.         CMP     AL, MSG_NAK         ; Q. create ok?
  1445.         JNE     ZCSEND10            ; A. yes .. continue
  1446.         MOV     DX, OFFSET FILENOPEN    ; dx -> error message
  1447.         MOV     AH, 9            ; ah = print ascii$
  1448.         INT     21H             ; .. tell 'em, Jim
  1449.         JMP     SHORT ZCSEND90        ; try next file
  1450. ZCSEND10:   MOV     CX, XBUF_LTS        ; cx = bytes left to send
  1451.         OR        CX, CX            ; Q. any?
  1452.         JNZ     ZCSEND20            ; A. yes .. send them
  1453.         MOV     AH, 3FH            ; ah = read from file
  1454.         MOV     BX, HANDLE            ; .. bx = file handle
  1455.         MOV     CX, XBUF_RBL        ; .. cx = # of bytes
  1456.         MOV     DX, XBUF            ; .. dx -> buffer
  1457.         MOV     XBUF_PTR, DX        ; .. save in send pointer
  1458.         INT     21H             ; .. read a buffer full
  1459.         JC        ZCSEND80            ; .. process errors
  1460.         OR        AX, AX            ; Q. anything read?
  1461.         JZ        ZCSEND70            ; A. no .. eof
  1462.         MOV     CX, AX            ; cx = number of bytes
  1463.         MOV     XBUF_LTS, AX        ; .. left to send
  1464. ZCSEND20:   CMP     CX, IO_LEN            ; Q. more than io_len?
  1465.         JNA     ZCSEND25            ; A. no .. send it
  1466.         MOV     CX, IO_LEN            ; cx = bytes to send
  1467. ZCSEND25:   SUB     XBUF_LTS, CX        ; adjust pointer
  1468.         MOV     SI, XBUF_PTR        ; .. si -> data
  1469.         ADD     XBUF_PTR, CX        ; .. adjust pointer
  1470.         MOV     AL, DATA_BLK        ; .. al = data block cmd
  1471.         MOV     ERRORS, 0            ; .. zero out errors
  1472.         CALL    ZCBLKSND            ; .. send a block
  1473.         CALL    ZCRECV            ; wait & execute reply
  1474.         CALL    ZCPRTLFT            ; .. print blocks left
  1475.         CMP     ERRORS, MAX_ERRORS        ; Q. too many errors
  1476.         JB        ZCSEND10            ; A. no ..continue
  1477.         MOV     AL, RESYNC            ; al = resync
  1478.         MOV     CX, 0            ; cx = no data to send
  1479.         CALL    ZCBLKSND            ; .. send the block
  1480.         CALL    RESYNC_P            ; resync on too many block errs
  1481.         JMP     ZCSEND10            ; .. and continue
  1482. ZCSEND70:   MOV     AL, EOF_MARK        ; al = eof command
  1483.         XOR     CX, CX            ; .. cx = no data
  1484.         CALL    ZCBLKSND            ; .. tell other side
  1485.         CALL    ZCRECV            ; wait for reply
  1486.         JMP     SHORT ZCSEND90        ; .. return to caller
  1487. ZCSEND80:   MOV     AL, SHUTDOWN        ; al = shutdown command
  1488.         XOR     CX, CX            ; .. cx = no data
  1489.         CALL    ZCBLKSND            ; .. tell other side
  1490. ZCSEND90:   POP     SI                ; restore registers
  1491.         POP     DX
  1492.         POP     CX
  1493.         POP     BX
  1494.         POP     AX
  1495.         RET
  1496. ZCSEND        ENDP
  1497. ; ---------------------------------------------------------------------
  1498. ; Receive blocks and process them based on request from the other machine.
  1499. ; ---------------------------------------------------------------------
  1500. ZCRECV        PROC    NEAR
  1501.         MOV     BX, WAIT_COUNT        ; bx = current wait count
  1502.         ADD     BX, SEC_10            ; bx = ten secs from now
  1503. ZCRECV05:   CALL    ZCTIMUP            ; update the timer
  1504.         CMP     WAIT_COUNT, BX        ; Q. 30 seconds yet?
  1505.         JB        ZCRECV07            ; A. no .. continue
  1506.         MOV     DX, OFFSET NOTUP        ; dx -> error message
  1507.         CALL    ZCDIE            ; .. I'm dead, Jim
  1508. ZCRECV07:   CALL    ZCTRYRCV            ; Q. anything waiting?
  1509.         JC        ZCRECV05            ; A. no.. try again
  1510.         CBW                 ; ax = command
  1511.         SHL     AL, 1            ; ax = entry offset
  1512.         LEA     BX, MSG_P_TBL-2        ; bx -> message table
  1513.         ADD     BX, AX            ; bx -> run pointer
  1514.         CALL    [BX]            ; .. call requested routine
  1515. ZCRECV90:   RET                 ; return to caller
  1516. ZCRECV        ENDP
  1517. ; ----------------------------------------
  1518. ; create the requested file
  1519. ; ----------------------------------------
  1520. CRE_FILE_P  PROC    NEAR            ; create file
  1521.         PUSH    AX                ; save regs
  1522.         PUSH    BX
  1523.         PUSH    CX
  1524.         PUSH    SI
  1525.         PUSH    DI
  1526.         MOV     WAIT_COUNT, 0        ; clear the wait counter
  1527.         MOV     SI, WBUF            ; si -> received data
  1528.         MOV     AX, [SI+MDATA+28]        ; ax =  file size high
  1529.         MOV     WORD PTR BYTESLFT+2, AX ; .. save high value
  1530.         MOV     AX, [SI+MDATA+26]        ; ax = file size low
  1531.         MOV     WORD PTR BYTESLFT, AX   ; .. save low value
  1532.         ADD     SI, MDATA+30        ; si -> file name
  1533.         MOV     DI, OFFSET FILENAME     ; di -> file name area
  1534.         MOV     CX, 13            ; .. length to move
  1535.        REP  MOVSB                ; move in the file name
  1536.         MOV     DX, OFFSET CURDIR        ; dx -> file name to open
  1537.         XOR     CX, CX            ; cx = attributes
  1538.         MOV     AH, 3CH            ; ah = create file
  1539.         INT     21H             ; Q. create ok?
  1540.         JC        CRE_FILEP1            ; A. no .. error
  1541.         MOV     HANDLE, AX            ; save handle
  1542.         OR        FLG1, FLG1O         ; .. show file is open
  1543.         MOV     SI, WBUF            ; si -> received data
  1544.         PUSH    MDATA+22[SI]        ; push file time
  1545.         POP     FILETIME            ; .. pop it
  1546.         PUSH    MDATA+24[SI]        ; push file date
  1547.         POP     FILEDATE            ; .. pop it
  1548.         MOV     SI, OFFSET FILENAME     ; si -> file created
  1549.         CALL    ZCPRTAZ            ; .. print the name
  1550.         MOV     DX, OFFSET BRECVD        ; dx -> being received
  1551.         MOV     AH, 09H            ; ah = print ascii$ string
  1552.         INT     21H             ; .. print the string
  1553.         CALL    ZCPRBLKS            ; .. print blocks to send
  1554.         MOV     AL, MSG_ACK         ; ack the request
  1555.         JMP     SHORT CRE_FILEP2        ; .. continue
  1556. CRE_FILEP1: MOV     AH, 9            ; ah = print ascii$
  1557.         MOV     DX, OFFSET FILENOPEN    ; dx -> error message
  1558.         INT     21H             ; .. tell 'em Jim
  1559.         MOV     AL, MSG_NAK         ; nak the request
  1560. CRE_FILEP2: MOV     CX, 0            ; .. no data
  1561.         CALL    ZCBLKSND            ; .. reply
  1562.         POP     DI                ; restore regs
  1563.         POP     SI
  1564.         POP     CX
  1565.         POP     BX
  1566.         POP     AX
  1567.         RET
  1568. CRE_FILE_P  ENDP
  1569. ; ----------------------------------------
  1570. ; determine if file exists
  1571. ; ----------------------------------------
  1572. QRY_FLE_P   PROC    NEAR            ; determine if file exists
  1573.         PUSH    AX                ; save caller's regs
  1574.         PUSH    CX
  1575.         PUSH    DX
  1576.         PUSH    SI
  1577.         PUSH    DI
  1578.         MOV     SI, WBUF            ; si -> received data
  1579.         ADD     SI, MDATA+30        ; si -> file name
  1580.         MOV     DI, OFFSET FILENAME     ; di -> file name area
  1581.         MOV     CX, 13            ; .. length to move
  1582.        REP  MOVSB                ; move in the file name
  1583.         MOV     DX, OFFSET CURDIR        ; dx -> file name to open
  1584.         XOR     CX, CX            ; cx = attributes
  1585.         MOV     AH, 4EH            ; ah = find first
  1586.         INT     21H             ; Q. file found?
  1587.         JC        QRY_FLE_P1            ; A. no .. error
  1588.         MOV     AL, MSG_ACK         ; ack the request
  1589.         JMP     SHORT QRY_FLE_P2        ; .. continue
  1590. QRY_FLE_P1: MOV     AL, MSG_NAK         ; nak the request
  1591. QRY_FLE_P2: PUSH    AX                ; save reply
  1592.         MOV     AH, 36H            ; ah = get free space
  1593.         XOR     DL, DL            ; .. on current drive
  1594.         INT     21H             ; .. via dos
  1595.         XOR     DX, DX            ; dx = 0
  1596.         MUL     CX                ; .. clusters x secs/cluster
  1597.         MUL     BX                ; .. secs x bytes/sector
  1598.         MOV     DS:DTA+DTA_LEN, AX        ; save lsw of free
  1599.         MOV     DS:DTA+DTA_LEN+2, DX    ; .. and msw
  1600.         MOV     CX, DTA_LEN+4        ; cx = find file data len
  1601.         MOV     SI, DTA            ; si -> dta
  1602.         POP     AX                ; .. restore reply
  1603.         CALL    ZCBLKSND            ; .. send reply
  1604.         POP     DI                ; restore caller's regs
  1605.         POP     SI
  1606.         POP     DX
  1607.         POP     CX
  1608.         POP     AX
  1609.         RET
  1610. QRY_FLE_P   ENDP
  1611. ; ----------------------------------------
  1612. ; process shutdown request
  1613. ; ----------------------------------------
  1614. SHUTDOWN_P  PROC    NEAR            ; process shutdown request
  1615.         MOV     DX, OFFSET SHUTDOWN_R   ; dx -> request
  1616.         JMP     ZCDIE            ; .. we'll never return
  1617. SHUTDOWN_P  ENDP
  1618. ; ----------------------------------------
  1619. ; ack received
  1620. ; ----------------------------------------
  1621. MSG_ACK_P   PROC    NEAR            ; process ack
  1622.         CLC                 ; show ack received
  1623.         RET
  1624. MSG_ACK_P   ENDP
  1625. ; ----------------------------------------
  1626. ; process nak request
  1627. ; ----------------------------------------
  1628. MSG_NAK_P   PROC    NEAR            ; process nak
  1629.         STC                 ; show nak received
  1630.         RET
  1631. MSG_NAK_P   ENDP
  1632. ; ----------------------------------------
  1633. ; process data block
  1634. ; ----------------------------------------
  1635. DATA_BLK_P  PROC    NEAR            ; process data block
  1636.         MOV     BX, WBUF            ; bx -> buffer
  1637.         LEA     DX, [BX+MDATA]        ; dx -> data area
  1638.         MOV     DI, XBUF_PTR        ; di -> build buffer
  1639.         MOV     SI, DX            ; si -> input data
  1640.         MOV     CX, [BX+MLEN]        ; cx = buffer length
  1641.         SUB     CX, 3            ; .. exclude cmd & blkno
  1642.         CLD                 ; .. positive direction
  1643.      REP    MOVSB                ; .. move data to buffer
  1644.         MOV     XBUF_PTR, DI        ; save new o/p ptr
  1645.         MOV     SI, XBUF            ; si -> xbuf
  1646.         ADD     SI, XBUF_WL         ; si -> write pos
  1647.         CMP     DI, SI            ; Q. write?
  1648.         JB        DATA_BLK90            ; A. no .. continue
  1649.         MOV     CX, XBUF_PTR        ; cx -> past data
  1650.         MOV     DX, XBUF            ; dx -> data
  1651.         SUB     CX, DX            ; cx = data length
  1652.         MOV     XBUF_PTR, DX        ; .. save put pointer
  1653.         MOV     BX, HANDLE            ; bx - handle
  1654.         MOV     AH, 40H            ; ah = write
  1655.         INT     21H             ; .. write file
  1656. DATA_BLK90: CALL    ZCPRTLFT            ; print # blocks left
  1657.         MOV     AL, MSG_ACK         ; ack the msg
  1658.         XOR     CX, CX            ; .. no data
  1659.         CALL    ZCBLKSND            ; .. send it
  1660.         RET
  1661. DATA_BLK_P  ENDP
  1662. ; ----------------------------------------
  1663. ; process eof request
  1664. ; ----------------------------------------
  1665. EOF_MARK_P  PROC    NEAR            ; process eof
  1666.         MOV     CX, XBUF_PTR        ; cx -> past data
  1667.         MOV     DX, XBUF            ; dx -> data
  1668.         SUB     CX, DX            ; Q. any to write?
  1669.         JZ        EOF_MARK80            ; A. no .. close & exit
  1670.         MOV     XBUF_PTR, DX        ; .. save put pointer
  1671.         MOV     BX, HANDLE            ; bx - handle
  1672.         MOV     AH, 40H            ; ah = write
  1673.         INT     21H             ; .. write file
  1674. EOF_MARK80: MOV     BX, HANDLE            ; bx = handle to close
  1675.         TEST    FLG, FLGD            ; Q. use machine date?
  1676.         JNZ     EOF_MARK85            ; A. yes .. skip sent date.
  1677.         MOV     AX, 5701H            ; ax = set file date
  1678.         MOV     CX, FILETIME        ; cx = file time
  1679.         MOV     DX, FILEDATE        ; dx = file date
  1680.         INT     21H             ; set file date & time
  1681. EOF_MARK85: MOV     AH, 3EH            ; ah = close command
  1682.         INT     21H             ; .. close the file
  1683.         AND     FLG1, NOT FLG1O        ; .. show file closed
  1684.         MOV     AL, MSG_ACK         ; ack the msg
  1685.         XOR     CX, CX            ; .. no data
  1686.         CALL    ZCBLKSND            ; .. send it
  1687.         MOV     DX, OFFSET CRLF        ; dx -> crlf
  1688.         MOV     AH, 9            ; ah = print ascii$
  1689.         INT     21H             ; .. display it
  1690.         RET
  1691. EOF_MARK_P  ENDP
  1692. ; ----------------------------------------
  1693. ; process set flags request
  1694. ; ----------------------------------------
  1695. SET_FLG_P   PROC    NEAR            ; process verify ok
  1696.         MOV     BX, WBUF            ; bx -> received packet
  1697.         MOV     AL, MDATA[BX]        ; al = flags sent
  1698.         AND     AL, FLG_SET         ; assure other flags off
  1699.         OR        FLG, AL            ; .. turn on other flags
  1700.         MOV     AL, FLG            ; al = new flag set
  1701.         AND     AL, FLG_SET         ; .. set off others
  1702.         XOR     CX, CX            ; cx = send no data
  1703.         CALL    ZCBLKSND            ; .. return flags
  1704.         RET
  1705. SET_FLG_P   ENDP
  1706. ; ----------------------------------------
  1707. ; resync speed
  1708. ; ----------------------------------------
  1709. RESYNC_P    PROC    NEAR            ; resync speed
  1710.         MOV     DX, OFFSET TOOMANY        ; dx -> message
  1711.         MOV     AH, 9            ; ah = print ascii$
  1712.         INT     21H             ; .. display message
  1713.         MOV     DSRWAIT, SEC_30        ; .. reset start wait time
  1714.         INC     BAUD_CNTR            ; .. select next baud rate
  1715.         CALL    ZCSPEED            ; .. resync
  1716.         CALL    ZCCLRCOM            ; .. clear our recv buffer
  1717.         RET
  1718. RESYNC_P    ENDP
  1719. ; ---------------------------------------------------------------------
  1720. ; This routine will send the requested files.
  1721. ; Exit: Returns to DOS when all files sent.
  1722. ; ---------------------------------------------------------------------
  1723. ZCSF        PROC    NEAR
  1724.         MOV     AH, FNDOP            ; ah = find operation to use
  1725.         XOR     CX, CX            ; cx = attribute to find
  1726.         MOV     DX, OFFSET CURDIR        ; dx -> path/filename
  1727.         INT     21H             ; Q. any file found?
  1728.         JNC     ZCSF05            ; A. yes .. try to send it
  1729.         JMP     ZCSF90            ; .. else .. end of job
  1730. ZCSF05:     MOV     FNDOP, 4FH            ; set op to find next
  1731.         PUSH    ES                ; save es
  1732.         LES     AX, DS:DWORD PTR DTA_LSIZ    ; es:ax = file size
  1733.         MOV     WORD PTR BYTESLFT, AX    ; .. save lsw
  1734.         MOV     WORD PTR BYTESLFT+2, ES    ; .. and msw
  1735.         POP     ES
  1736.         MOV     AX, 3D00H            ; ax = open for read
  1737.         MOV     DX, DTA_NAME            ; ds:dx -> filename to open
  1738.         INT     21H             ; Q. open the file ok?
  1739.         JC        ZCSF            ; A. no .. try next file
  1740.         MOV     HANDLE, AX            ; save the handle
  1741.         MOV     AL, QRY_FLE         ; al = determine existence
  1742.         MOV     CX, DTA_LEN         ; cx = find file data
  1743.         MOV     SI, DTA            ; si -> dta
  1744.         CALL    ZCBLKSND            ; send the request
  1745.         CALL    ZCRECV            ; Q. does file exist?
  1746.         MOV     BX, WBUF            ; bx -> received buffer
  1747.         MOV     AX,WORD PTR DTA_LEN[BX+MDATA]   ; ax = lsw of free
  1748.         MOV     DX,WORD PTR DTA_LEN[BX+2+MDATA] ; dx = msw of free
  1749.         MOV     FILESZL, AX         ; .. save locally
  1750.         MOV     FILESZH, DX         ; .. lsw & msw
  1751.         JC        ZCSF20            ; A. no .. continue
  1752.         ADD     AX, MDATA+26[BX]        ; add in file's len
  1753.         ADC     DX, MDATA+28[BX]        ; .. lsw & msw
  1754.         MOV     FILESZL, AX         ; .. save locally
  1755.         MOV     FILESZH, DX         ; .. lsw & msw
  1756.         TEST    FLG, FLGO            ; Q. overwrite?
  1757.         JNZ     ZCSF20            ; A. yes .. make it so
  1758.         TEST    FLG, FLGU            ; Q. update?
  1759.         JZ        ZCSF10            ; A. no .. ask operator
  1760.         MOV     BX, WBUF            ; bx -> recv'd message
  1761.         MOV     AX, MDATA+24[BX]        ; ax = receiver's file date
  1762.         CMP     AX, DS:DTA_DATE        ; Q. is receivers file older?
  1763.         JB        ZCSF20            ; A. yes..    send our's
  1764.         JA        ZCSF80            ; A. younger .. skip it
  1765.         MOV     AX, MDATA+22[BX]        ; ax = receiver's file time
  1766.         CMP     AX, DS:DTA_TIME        ; Q. is receivers file older?
  1767.         JB        ZCSF20            ; A. yes .. send our's
  1768.         JMP     SHORT ZCSF80        ; .. else .. skip
  1769. ZCSF10:     MOV     DX, OFFSET FILEXISTS    ; dx -> message
  1770.         CALL    ZCFPR            ; .. issue overwrite prompt
  1771.         CMP     AL, 'Y'                 ; Q. overwrite?
  1772.         JE        ZCSF20            ; A. yes .. do it
  1773.         CMP     AL, 'N'                 ; Q. do not overwrite?
  1774.         JE        ZCSF80            ; A. yes ... skip file
  1775.         JMP     SHORT ZCSF10        ; .. retry prompt
  1776. ZCSF20:     MOV     AX, DS:DTA_HSIZ        ; ax = hi file size
  1777.         CMP     AX, FILESZH         ; Q. is our file smaller?
  1778.         JB        ZCSF30            ; A. yes .. start transfer
  1779.         JA        ZCSF25            ; A. no .. check for abort
  1780.         MOV     AX, DS:DTA_LSIZ        ; .. get low order
  1781.         CMP     AX, FILESZL         ; Q. is our file smaller?
  1782.         JNA     ZCSF30            ; A. yes .. start transfer
  1783. ZCSF25:     TEST    FLG, FLGA            ; Q. abort if too big?
  1784.         JNZ     ZCSF28            ; A. no .. next file
  1785.         MOV     SI, DTA_NAME        ; si -> file name
  1786.         CALL    ZCPRTAZ            ; .. display it
  1787.         MOV     DX, OFFSET TOOBIG        ; dx -> too big message
  1788.         MOV     AH, 9            ; ah = print to $
  1789.         INT     21H             ; .. display message
  1790.         JMP     SHORT ZCSF80        ; .. next file
  1791. ZCSF28:     MOV     DI, OFFSET DISKFULL     ; di -> full prompt
  1792.         CALL    ZCSPROMPT            ; .. tell the user
  1793.         JMP     SHORT ZCSF90        ; .. shutdown
  1794. ZCSF30:     MOV     SI, DTA_NAME        ; si -> filename
  1795.         CALL    ZCPRTAZ            ; print the
  1796.         MOV     DX, OFFSET BSENT        ; dx -> being sent
  1797.         MOV     AH, 09H            ; ah = display ascii$
  1798.         INT     21H             ; display message
  1799.         CALL    ZCPRBLKS            ; print blocks left message
  1800.         MOV     WAIT_COUNT, 0        ; .. clear the wait count value
  1801.         CALL    ZCSEND            ; .. and send the file
  1802.         MOV     DX, OFFSET CRLF        ; dx -> crlf
  1803.         MOV     AH, 9            ; ah = print ascii$
  1804.         INT     21H             ; .. display it
  1805. ZCSF80:     MOV     BX, HANDLE            ; bx = handle of last file
  1806.         MOV     AH, 3EH            ; ah = close file opcode
  1807.         INT     21H             ; .. file closed, captain!
  1808.         JMP     ZCSF            ; .. try next file
  1809. ZCSF90:     MOV     AL, SHUTDOWN        ; al = shutdown command
  1810.         XOR     CX, CX            ; .. no data is sent
  1811.         CALL    ZCBLKSND            ; send the command
  1812.         MOV     DX, OFFSET SHUTDOWN_R   ; dx -> shutdown string
  1813.         JMP     ZCDIE            ; end gracefully
  1814. ZCSF        ENDP
  1815. ; ---------------------------------------------------------------------
  1816. ; This routine will display the requested string.
  1817. ; Entry: si -> string to print.
  1818. ; ---------------------------------------------------------------------
  1819. ZCPRTAZ     PROC    NEAR
  1820.         PUSH    AX                ; save regs
  1821.         PUSH    DX
  1822.         PUSH    SI
  1823.         MOV     AH, 02H            ; ah = display character
  1824. ZCPRTAZ10:  LODSB                ; al = char to prt
  1825.         OR        AL, AL            ; Q. anything to prt?
  1826.         JZ        ZCPRTAZ90            ; A. no .. return
  1827.         MOV     DL, AL            ; dl = char to prt
  1828.         INT     21H             ; .. display the char
  1829.         JMP     ZCPRTAZ10            ; .. next char
  1830. ZCPRTAZ90:  POP     SI                ; restore regs
  1831.         POP     DX
  1832.         POP     AX
  1833.         RET                 ; return to caller
  1834. ZCPRTAZ     ENDP
  1835. ; ---------------------------------------------------------------------
  1836. ; This routine will build a prompt for both machines.
  1837. ; Entry: filename in the DTA contains file name; dx -> prompt string to use
  1838. ; Exit: al = reply char, upper case
  1839. ; ---------------------------------------------------------------------
  1840. ZCFPR        PROC    NEAR
  1841.         PUSH    SI                ; save regs
  1842.         PUSH    DI
  1843.         MOV     DI, XBUF            ; di -> work area
  1844.         MOV     SI, DTA_NAME        ; si -> filename
  1845. ZCFPR10:    LODSB                ; al = char from filename
  1846.         OR        AL, AL            ; Q. end of name?
  1847.         JZ        ZCFPR20            ; A. yes .. next field
  1848.         STOSB                ; .. save in xbuf
  1849.         JMP     SHORT ZCFPR10        ; process next char
  1850. ZCFPR20:    MOV     SI, DX            ; dx -> prompt
  1851. ZCFPR25:    LODSB                ; al = prompt char
  1852.         STOSB                ; .. save it
  1853.         CMP     AL, '$'                 ; Q. end of prompt?
  1854.         JNE     ZCFPR25            ; A. no .. continue
  1855.         MOV     DI, XBUF            ; di -> xbuf
  1856.         CALL    ZCSPROMPT            ; issue prompt
  1857.         AND     AL, NOT 20H         ; response to upper case
  1858.         POP     DI                ; restore regs
  1859.         POP     SI
  1860.         RET                 ; return to caller
  1861. ZCFPR        ENDP
  1862. ; ---------------------------------------------------------------------
  1863. ; This routine transfers ZCOPY out the port in DX.
  1864. ; Entry: dx = port to transfer on; cx = # chars to send
  1865. ; Exit: Stops via int 3 - debug better be there
  1866. ; ---------------------------------------------------------------------
  1867. ZCXFER        PROC    NEAR
  1868.         MOV     SI, 0FEH            ; si -> start of area to send
  1869.         MOV     WORD PTR [SI], CX        ; set up length of program
  1870.         ADD     CX, 2            ; add in length
  1871. ZCXFER10:   ADD     DX, 5            ; dx -> lsr
  1872.         IN        AL, DX            ; al = lsr
  1873.         SUB     DX, 5            ; dx -> base port
  1874.         TEST    AL, LSR_THRE        ; Q. thr empty?
  1875.         JZ        ZCXFER10            ; A. no .. wait
  1876.         LODSB                ; al = char to send
  1877.         OUT     DX, AL            ; .. sent the char
  1878.         LOOP    ZCXFER10            ; .. loop til done
  1879.         INT     3                ; then return to debug
  1880. ZCXFER        ENDP
  1881. ;   Uninitialized data areas
  1882. UDATA        EQU     $                ; start of unitialized data
  1883. IO_BASE     EQU     WORD PTR UDATA        ; base com port address
  1884. INT_VECTOR  EQU     BYTE PTR IO_BASE+2        ; interrupt vector to use
  1885. OLD_COM     EQU     DWORD PTR INT_VECTOR+1  ; old interrupt for com:
  1886. OLD_TIMER   EQU     DWORD PTR OLD_COM+4     ; old interrupt for timer tick
  1887. OLD_CTLBRK  EQU     DWORD PTR OLD_TIMER+4   ; old interrupt for control break
  1888. OLD_DOSCTLB EQU     DWORD PTR OLD_CTLBRK+4  ; old interrupt for dos ^break
  1889. OLD_DOSERR  EQU     DWORD PTR OLD_DOSCTLB+4 ; old interrupt for dos error
  1890. HANDLE        EQU     WORD PTR OLD_DOSERR+4   ; open file handle
  1891. RBUF_GPTR   EQU     WORD PTR HANDLE+2        ; receive buffer next get address
  1892. RBUFL        EQU     1100H            ; length of receive buffer
  1893. SBUF        EQU     WORD PTR RBUF_GPTR+2    ; send buffer address
  1894. SBUFL        EQU     600H            ; length of send buffer
  1895. WBUF        EQU     WORD PTR SBUF+2        ; work buffer address
  1896. WBUFL        EQU     500H            ; length of work buffer
  1897. XBUF        EQU     WORD PTR WBUF+2        ; file build buffer
  1898. XBUF_PTR    EQU     WORD PTR XBUF+2        ; i/o pointer
  1899. EDRV        EQU     BYTE PTR XBUF_PTR+2     ; entry time logged drive
  1900. EDIR        EQU     WORD PTR EDRV+1        ; pointer to entry time directory
  1901. EDIRL        EQU     65                ; length of area
  1902. FILESZL     EQU     WORD PTR EDIR+2        ; file size low
  1903. FILESZH     EQU     WORD PTR FILESZL+2        ; .. and high
  1904. FILEDATE    EQU     WORD PTR FILESZH+2        ; file date
  1905. FILETIME    EQU     WORD PTR FILEDATE+2     ; file time
  1906. BYTESLFT    EQU     DWORD PTR FILETIME+2    ; bytes left to transfer
  1907. BUF_START   EQU     BYTESLFT+4            ; start of buffer space
  1908.  
  1909. CSEG        ENDS
  1910.         END     START
  1911.