home *** CD-ROM | disk | FTP | other *** search
/ Frostbyte's 1980s DOS Shareware Collection / floppyshareware.zip / floppyshareware / GLEN / PCREMOT2.ZIP / ZCOPY.ASM < prev    next >
Assembly Source File  |  1992-01-05  |  94KB  |  2,000 lines

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