home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / simtel / sigm / vols000 / vol017 / xmodem41.asm < prev   
Assembly Source File  |  1984-04-29  |  29KB  |  1,212 lines

  1. ;
  2. ;    XMODEM.ASM V4.1, by Keith Petersen, W8SDZ
  3. ;    Latest Revision: 2/17/81 Tim Nicholas
  4. ;
  5. ;    REMOTE CP/M - CP/M FILE TRANSFER PROGRAM
  6. ;
  7. ;Based on MODEM.ASM V2.0, by Ward Christensen.
  8. ;This program is intended for use on remote CP/M
  9. ;systems where it is important that the initialization
  10. ;of the modem not be changed, such as when using
  11. ;the PMMIBYE program. The baud rate and number of bits
  12. ;remains the same as whatever was set previously.
  13. ;There is no disconnect, terminal or echo option.
  14. ;
  15. ;NOTE: This file will assemble, without need for
  16. ;editing, to work with a PMMI MM-103 modem and 2 Mhz
  17. ;system clock.    See equates for options including
  18. ;other modems and 4 Mhz system clock frequency.
  19. ;
  20. ;Program updates/fixes (these are written in reverse
  21. ;order to minimize reading time to find latest update):
  22. ;
  23. ;
  24. ;02/17/81 Added test for "f2" tagged files in OPENOK
  25. ;      for MP/M version 1.1 compatiblity, which
  26. ;      doesn't allow Ctl-C or Ctl-S in "f1" tagged
  27. ;      files. (Tim Nicholas)
  28. ;
  29. ;02/16/81 Added hex to file size display. Now reports
  30. ;      size in both decimal and (xxxxH) hex. Thanks
  31. ;      to Ben Bronson for the idea. (Tim Nicholas)
  32. ;
  33. ;02/15/81 Added a software timer to the carrier test
  34. ;      added in SEND and RECV routines. This will
  35. ;      now abort only if carrier is lost for a 
  36. ;      period of 15 seconds. This is only essential
  37. ;      for those using external modems with certain
  38. ;      SIO's, but will provide the PMMI/DCH user
  39. ;      faster recovery in a lost carrier situation
  40. ;      as well. Approx 15 seconds plus 15 seconds
  41. ;      in BYE.COM, compared to 3 minutes at 300
  42. ;      baud with earlier revisions. Thanks to Ben
  43. ;      Bronson for his aid in developing this
  44. ;      revision. (Tim Nicholas)
  45. ;
  46. ;02/14/81 Corrected error in last update which read
  47. ;      the incorrect port for PMMI in the added
  48. ;      carrier test. (Tim Nicholas)
  49. ;    
  50. ;01/31/81 Added equates and code for a carrier test.
  51. ;      Test performed in modem I/O routines. This
  52. ;      is required since loss of carrier will go
  53. ;      undetected by BYE.COM, if the loss occurs
  54. ;      after a sucessful XMODEM signon, when using
  55. ;      an external modem and SIO. (Tim Nicholas)
  56. ;
  57. ;01/17/81 Re-wrote routine to calculate file size so
  58. ;         that it works correctly on v2.X systems with
  59. ;         extent folding (non-zero extent mask). (BRR)
  60. ;
  61. ;12/06/80 Re-wrote routine to calculate file size,
  62. ;      added decimal print of file size. (KBP)
  63. ;
  64. ;12/05/80 Corrected error in use of ext byte that pre-
  65. ;      vented files greater than one extent from 
  66. ;      being sent.     Ron Fowler
  67. ;
  68. ;12/03/80 Corrected file extent length display. Now
  69. ;      reports correct number of records for files
  70. ;      longer than one extent. Display is now
  71. ;      double precision (xxxxH). Also made some
  72. ;      cosmetic changes by re-arranging the equates.
  73. ;      By Tim Nicholas
  74. ;
  75. ;10/28/80 Cleaned up file. (KBP)
  76. ;
  77. ;10/23/80 Expanded conditional assembly of NOCOM routines
  78. ;      into NOCOMS, NOLBS, and NOCOMR equates, to allow
  79. ;      separate conditional assembly of tests for sending
  80. ;      .COM files, sending .??# files, and receiving .COM
  81. ;      files, respectively.    (Dave Hardy)
  82. ;
  83. ;10/15/80 Added traps for ambiguous file name or
  84. ;      none at all. (KBP)
  85. ;
  86. ;09/09/80 Added conditional assembly to prevent filetypes
  87. ;      '.COM' or '.??#' from being sent to distant end
  88. ;      and added conditional assembly of test for '.COM'
  89. ;      filetype on receive as well. See 'NOCOM' below.
  90. ;      Any filetype ending in '#' will not be sent by
  91. ;      this program if 'NOCOM' is set to TRUE.  J.SEYMOUR
  92. ;
  93. ;NOTE: If you add improvements or otherwise update
  94. ;this program, please modem a copy of the new file
  95. ;to "TECHNICAL CBBS" in Dearborn, Michigan - phone
  96. ;313-846-6127 (110, 300, 450 or 600 baud).  Use the
  97. ;filename XMODEM.NEW.    (KBP)
  98. ;
  99. FALSE    EQU    0
  100. TRUE    EQU    NOT FALSE
  101. ;
  102. ;-----------------------------------------------------
  103. ;     --- Conditional Assembly Options ---          ;
  104. ;------------------------------------------------------
  105. ;
  106. STDCPM    EQU    TRUE    ;TRUE, IS STANDARD CP/M
  107. ALTCPM    EQU    FALSE    ;TRUE, IS H8 OR TRS-80 CP/M
  108. ;
  109. PMMI    EQU    TRUE     ;TRUE, IS PMMI
  110. DCH    EQU    FALSE    ;TRUE, IS D.C. HAYES
  111. ;
  112. NOCOMS    EQU    FALSE    ;TRUE, NO .COM FILES SENT
  113. NOLBS    EQU    TRUE    ;TRUE, NO .??# FILES SENT
  114. NOCOMR    EQU    TRUE    ;TRUE, NO .COM FILES RECEIVED
  115. ;
  116. FASTCLK EQU    FALSE    ;PUT TRUE HERE FOR 4 MHZ CLOCK
  117. ;
  118. ;------------------------------------------------------
  119. ;         --- Modem Port Equates ---           ;
  120. ;------------------------------------------------------
  121. ;
  122.     IF    PMMI
  123. MODCTLP EQU    0C0H    ;PMMI VALUES
  124. MODSNDB EQU    1    ;BIT TO TEST FOR SEND
  125. MODSNDR EQU    1    ;VALUE WHEN READY
  126. MODRCVB EQU    2    ;BIT TO TEST FOR RECEIVE
  127. MODRCVR EQU    2    ;VALUE WHEN READY
  128. MODDCDB    EQU    4    ;CARRIER DETECT BIT
  129. MODDCDA    EQU    0    ;VALUE WHEN ACTIVE
  130. MODDATP EQU    0C1H    ;DATA PORT
  131. BAUDRP    EQU    0C2H    ;BAUD RATE OUTPUT/MODEM STATUS
  132. MODCTL2 EQU    0C3H    ;SECOND CTL PORT
  133.     ENDIF
  134. ;
  135.     IF    DCH
  136. MODCTLP EQU    82H    ;D. C. HAYES VALUES
  137. MODSNDB EQU    2    ;BIT TO TEST FOR SEND
  138. MODSNDR EQU    2    ;VALUE WHEN READY
  139. MODRCVB EQU    1    ;BIT TO TEST FOR RECEIVE
  140. MODRCVR EQU    1    ;VALUE WHEN READY
  141. MODDCDB    EQU    40H    ;CARRIER DETECT BIT
  142. MODDCDA    EQU    40H    ;VALUE WHEN ACTIVE
  143. MODDATP EQU    80H    ;DATA PORT
  144. MODCTL2 EQU    81H    ;SECOND CTL PORT
  145.     ENDIF
  146. ;
  147. ;---> NOTE: DCD (Carrier Detect) values above are for
  148. ;        the Micromodem 100. For DC-Hayes 80-103
  149. ;        the values are different.
  150. ;        MODDCDB  EQU  1  ;Carrier bit (CTS).
  151. ;        MODDCDA  EQU  1  ;Active value.
  152. ;
  153. ;
  154. ;
  155. ;If you are using an external modem (not S-100 plug-in)
  156. ;change these equates for your modem port requirements
  157. ;
  158.     IF    NOT PMMI AND NOT DCH
  159. MODCTLP EQU    35H    ;PUT YOUR MODEM STATUS PORT HERE
  160. MODSNDB EQU    01H    ;YOUR BIT TO TEST FOR SEND
  161. MODSNDR EQU    01H    ;YOUR VALUE WHEN READY
  162. MODRCVB EQU    02H    ;YOUR BIT TO TEST FOR RECEIVE
  163. MODRCVR EQU    02H    ;YOUR VALUE WHEN READY
  164. MODDCDB    EQU    1    ;CARRIER DETECT BIT
  165. MODDCDA    EQU    1    ;VALUE WHEN ACTIVE
  166. MODDATP EQU    34H    ;YOUR MODEM DATA PORT
  167. MODCTL2    EQU    36H    ;SECOND CONTROL/STATUS PORT.
  168.     ENDIF        ;END OF EXTERNAL MODEM EQUATES
  169. ;
  170. ;        --- End of Options ---
  171. ;------------------------------------------------------
  172. ;
  173. ;
  174. ERRLIM    EQU    10    ;MAX ALLOWABLE ERRORS (10 STANDARD)
  175. ;
  176. ;Define ASCII characters used
  177. ;
  178. SOH    EQU    1    ;START OF HEADER
  179. EOT    EQU    4    ;END OF TRANSMISSION
  180. ACK    EQU    6    ;ACKNOWLEDGE
  181. NAK    EQU    15H    ;NEG ACKNOWLEDGE
  182. CAN    EQU    18H    ;CONTROL-X FOR CANCEL
  183. LF    EQU    10    ;LINEFEED
  184. CR    EQU    13    ;CARRIAGE RETURN
  185.     IF    STDCPM
  186. BASE    EQU    0    ;CP/M BASE ADDRESS
  187.     ENDIF
  188. ;
  189.     IF    ALTCPM
  190. BASE    EQU    4200H    ;ALTERNATE CP/M BASE ADDRESS
  191.     ENDIF
  192. ;
  193.     ORG    BASE+100H
  194. ;
  195. ;Init private stack
  196.     LXI    H,0    ;HL=0
  197.     DAD    SP    ;HL=STACK FROM CP/M
  198.     SHLD    STACK    ;..SAVE IT
  199.     LXI    SP,STACK ;SP=MY STACK
  200.     CALL    ILPRT    ;PRINT:
  201.     DB    CR,LF
  202.     DB    'XMODEM ver 4.1',CR,LF,0
  203. ;
  204. ;Get option
  205. ;
  206.     LDA    FCB+1    ;GET OPTION (S or R)
  207.     PUSH    PSW    ;SAVE OPTION
  208. ;
  209. ;Move the filename from FCB2 to FCB1
  210. ;
  211.     CALL    MOVEFCB
  212. ;
  213. ;Gobble up garbage chars from the line
  214. ;prior to receive or send
  215. ;
  216.     IN    MODDATP
  217.     IN    MODDATP
  218. ;
  219. ;Jump to appropriate function
  220. ;
  221.     POP    PSW    ;GET OPTION
  222. ;
  223.     CPI    'S'    ;SEND..
  224.     JZ    SENDFIL ;..A FILE?
  225. ;
  226.     CPI    'R'    ;RECEIVE..
  227.     JZ    RCVFIL    ;..A FILE?
  228. ;
  229. ;Invalid option
  230. ;
  231.     CALL    ERXIT    ;EXIT W/ERROR
  232.     DB    '++INVALID OPTION ON XMODEM '
  233.     DB    'COMMAND++',CR,LF
  234.     DB    'Must be S for SEND or R for '
  235.     DB    'RECEIVE',CR,LF,'$'
  236. ;
  237. * * * * * * * * * * * * * * * * * * * * *
  238. *                    *
  239. *    SENDFIL: SENDS A CP/M FILE    *
  240. *                    *
  241. * * * * * * * * * * * * * * * * * * * * *
  242. ;
  243. ;The CP/M file specified in the XMODEM command
  244. ;is transferred over the phone to another
  245. ;computer running MODEM with the "R" (receive)
  246. ;option.  The data is sent one sector at a
  247. ;time with headers and checksums, and re-
  248. ;transmission on errors.  
  249. ;
  250. SENDFIL CALL    TRAP    ;CHECK FOR NO NAME OR AMBIG. NAME
  251.     CALL    CNREC    ;COMPUTE # OF RECORDS.
  252.     CALL    OPENFIL ;OPEN THE FILE
  253.     MVI    E,80    ;WAIT 80 SEC..
  254.     CALL    WAITNAK ;..FOR INITIAL NAK
  255. ;
  256. SENDLP    CALL    RDSECT    ;READ A SECTOR
  257.     JC    SENDEOF ;SEND EOF IF DONE
  258.     CALL    INCRSNO ;BUMP SECTOR #
  259.     XRA    A    ;ZERO ERROR..
  260.     STA    ERRCT    ;..COUNT
  261. ;
  262. SENDRPT CALL    SENDHDR ;SEND A HEADER
  263.     CALL    SENDSEC ;SEND DATA SECTOR
  264.     CALL    SENDCKS ;SEND CKSUM
  265.     CALL    GETACK    ;GET THE ACK
  266.     JC    SENDRPT ;REPEAT IF NO ACK
  267.     JMP    SENDLP    ;LOOP UNTIL EOF
  268. ;
  269. ;File sent, send EOT's
  270. ;
  271. SENDEOF MVI    A,EOT    ;SEND..
  272.     CALL    SEND    ;..AN EOT
  273.     CALL    GETACK    ;GET THE ACK
  274.     JC    SENDEOF ;LOOP IF NO ACK
  275.     JMP    EXIT    ;ALL DONE
  276. ;
  277. * * * * * * * * * * * * * * * * * * * * *
  278. *                    *
  279. *    RCVFIL: RECEIVE A FILE        *
  280. *                    *
  281. * * * * * * * * * * * * * * * * * * * * *
  282. ;
  283. ;Receives a file in block format as sent
  284. ;by another person doing "MODEM S FN.FT".
  285. ;
  286. RCVFIL    CALL    TRAP    ;CHECK FOR NO NAME OR AMBIG. NAME
  287. ;
  288.     IF    NOCOMR
  289.     LXI    H,FCB+9 ;POINT TO FILETYPE
  290.     MVI    A,'C'    ;1ST LETTER
  291.     CMP    M    ;IS IT C ?
  292.     JNZ    CONTINU ;IF NOT, CONTINUE NORMALLY
  293.     INX    H    ;GET 2ND LETTER
  294.     MVI    A,'O'    ;2ND LETTER
  295.     CMP    M    ;IS IT O ?
  296.     JNZ    CONTINU ;IF NOT, CONTINUE NORMALLY
  297.     INX    H    ;GET 3RD LETTER
  298.     MVI    A,'M'    ;3RD LETTER
  299.     CMP    M    ;IS IT M ?
  300.     JNZ    CONTINU ;IF NOT, CONTINUE NORMALLY
  301.     CALL    ERXIT    ;EXIT, PRINT ERROR MESSAGE
  302.     DB    '++CAN''T RECEIVE A .COM FILE++'
  303.     DB    CR,LF,CR,LF
  304.     DB    'Rename filetype ".OBJ" and try again'
  305.     DB    CR,LF,'$'
  306.     ENDIF
  307. ;
  308. CONTINU CALL    CHEKFIL ;SEE IF FILE EXISTS
  309.     CALL    MAKEFIL ;..THEN MAKE NEW
  310.     CALL    ILPRT    ;PRINT:
  311.     DB    'FILE OPEN - READY TO RECEIVE',CR,LF,0
  312. ;
  313. RCVLP    CALL    RCVSECT ;GET A SECTOR
  314.     JC    RCVEOT    ;GOT EOT
  315.     CALL    WRSECT    ;WRITE THE SECTOR
  316.     CALL    INCRSNO ;BUMP SECTOR #
  317.     CALL    SENDACK ;ACK THE SECTOR
  318.     JMP    RCVLP    ;LOOP UNTIL EOF
  319. ;
  320. ;Got EOT on sector - flush buffers, end
  321. ;
  322. RCVEOT    CALL    WRBLOCK ;WRITE THE LAST BLOCK
  323.     CALL    SENDACK ;ACK THE SECTOR
  324.     CALL    CLOSFIL ;CLOSE THE FILE
  325.     JMP    EXIT    ;ALL DONE
  326. ;
  327. * * * * * * * * * * * * * * * * * * * * *
  328. *                    *
  329. *        SUBROUTINES        *
  330. *                    *
  331. * * * * * * * * * * * * * * * * * * * * *
  332. ;
  333. ;---->    TRAP: Check for no file name or ambiguous name
  334. ;
  335. TRAP    LXI    H,FCB+1 ;POINT TO FILE NAME
  336.     MOV    A,M    ;GET FIRST CHAR OF FILE NAME
  337.     CPI    ' '    ;ANY THERE?
  338.     JNZ    ATRAP    ;YES, CHECK FOR AMBIGOUS FILE NAME
  339.     CALL    ERXIT    ;PRINT MSG, EXIT
  340.     DB    '++NO FILE NAME SPECIFIED++',CR,LF,'$'
  341. ;
  342. ATRAP    MVI    B,11    ;11 CHARS TO CHECK
  343. ;
  344. TRLOOP    MOV    A,M    ;GET CHAR FROM FCB
  345.     CPI    '?'    ;AMBIGUOUS?
  346.     JZ    TRERR    ;YES, EXIT WITH ERROR MSG
  347.     INX    H    ;POINT TO NEXT CHAR
  348.     DCR    B    ;ONE LESS TO GO
  349.     JNZ    TRLOOP    ;NOT DONE, CHECK SOME MORE
  350.     RET        ;NO AMBIGUOUS NAME, RETURN
  351. ;
  352. TRERR    CALL    ERXIT    ;PRINT MSG, EXIT
  353.     DB    '++CAN''T USE WILD CARD OPTIONS',CR,LF,'$'
  354. ;
  355. ;---->    RCVSECT: Receive a sector
  356. ;
  357. ;Returns with carry set if EOT received.
  358. ;
  359. RCVSECT XRA    A    ;GET 0
  360.     STA    ERRCT    ;INIT ERROR COUNT
  361. ;
  362. RCVRPT    MVI    B,10    ;10 SEC TIMEOUT
  363.     CALL    RECV    ;GET SOH/EOT
  364.     JC    RCVSTOT ;TIMEOUT
  365.     CPI    SOH    ;GET SOH?
  366.     JZ    RCVSOH    ;..YES
  367. ;
  368. ;Earlier versions of MODEM program send some nulls -
  369. ;ignore them
  370. ;
  371.     ORA    A    ;00 FROM SPEED CHECK?
  372.     JZ    RCVRPT    ;YES, IGNORE IT
  373.     CPI    EOT    ;END OF TRANSFER?
  374.     STC        ;RETURN WITH CARRY..
  375.     RZ        ;..SET IF EOT
  376. ;
  377. ;Didn't get SOH or EOT - 
  378. ;    -or-
  379. ;Did'nt get valid header - purge the line,
  380. ;then send NAK.
  381. ;
  382. RCVSERR MVI    B,1    ;WAIT FOR 1 SEC..
  383.     CALL    RECV    ;..WITH NO CHARS
  384.     JNC    RCVSERR ;LOOP UNTIL SENDER DONE
  385.     MVI    A,NAK    ;SEND..
  386.     CALL    SEND    ;..THE NAK
  387.     LDA    ERRCT    ;ABORT IF..
  388.     INR    A    ;..WE HAVE REACHED..
  389.     STA    ERRCT    ;..THE ERROR..
  390.     CPI    ERRLIM    ;..LIMIT?
  391.     JC    RCVRPT    ;..NO, TRY AGAIN
  392. ;
  393. ;10 errors in a row -
  394. ;
  395. RCVSABT CALL    CLOSFIL ;KEEP WHATEVER WE GOT
  396.     CALL    ERXIT
  397.     DB    '++UNABLE TO RECEIVE BLOCK '
  398.     DB    '- ABORTING++',CR,LF,'$'
  399. ;
  400. ;Timed out on receive
  401. ;
  402. RCVSTOT JMP    RCVSERR ;BUMP ERR CT, ETC.
  403. ;
  404. ;Got SOH - get block #, block # complemented
  405. ;
  406. RCVSOH    MVI    B,1    ;TIMEOUT = 1 SEC
  407.     CALL    RECV    ;GET SECTOR
  408.     JC    RCVSTOT ;GOT TIMEOUT
  409.     MOV    D,A    ;D=BLK #
  410.     MVI    B,1    ;TIMEOUT = 1 SEC
  411.     CALL    RECV    ;GET CMA'D SECT #
  412.     JC    RCVSTOT ;TIMEOUT
  413.     CMA        ;CALC COMPLEMENT
  414.     CMP    D    ;GOOD SECTOR #?
  415.     JZ    RCVDATA ;YES, GET DATA
  416. ;
  417. ;Got bad sector #
  418. ;
  419.     JMP    RCVSERR ;BUMP ERROR CT.
  420. ;
  421. RCVDATA MOV    A,D    ;GET SECTOR #
  422.     STA    RCVSNO    ;SAVE IT
  423.     MVI    C,0    ;INIT CKSUM
  424.     LXI    H,BASE+80H ;POINT TO BUFFER
  425. ;
  426. RCVCHR    MVI    B,1    ;1 SEC TIMEOUT
  427.     CALL    RECV    ;GET CHAR
  428.     JC    RCVSTOT ;TIMEOUT
  429.     MOV    M,A    ;STORE CHAR
  430.     INR    L    ;DONE?
  431.     JNZ    RCVCHR    ;NO, LOOP
  432. ;
  433. ;Verify checksum
  434. ;
  435.     MOV    D,C    ;SAVE CHECKSUM
  436.     MVI    B,1    ;TIMEOUT LEN.
  437.     CALL    RECV    ;GET CHECKSUM
  438.     JC    RCVSTOT ;TIMEOUT
  439.     CMP    D    ;CHECKSUM OK?
  440.     JNZ    RCVSERR ;NO, ERROR
  441. ;
  442. ;Got a sector, it's a duplicate if = previous,
  443. ;    or OK if = 1 + previous sector
  444. ;
  445.     LDA    RCVSNO    ;GET RECEIVED
  446.     MOV    B,A    ;SAVE IT
  447.     LDA    SECTNO    ;GET PREV
  448.     CMP    B    ;PREV REPEATED?
  449.     JZ    RECVACK ;ACK TO CATCH UP
  450.     INR    A    ;CALC NEXT SECTOR #
  451.     CMP    B    ;MATCH?
  452.     JNZ    ABORT    ;NO MATCH - STOP SENDER, EXIT
  453.     RET        ;CARRY OFF - NO ERRORS
  454. ;
  455. ;Previous sector repeated, due to the last ACK
  456. ;being garbaged.  ACK it so sender will catch up 
  457. ;
  458. RECVACK CALL    SENDACK ;SEND THE ACK,
  459.     JMP    RCVSECT ;GET NEXT BLOCK
  460. ;
  461. ;Send an ACK for the sector
  462. ;
  463. SENDACK MVI    A,ACK    ;GET ACK
  464.     CALL    SEND    ;..AND SEND IT
  465.     RET
  466. ;
  467. ;---->    SENDHDR: Send the sector header
  468. ;
  469. ;SEND: (SOH) (block #) (complemented block #)
  470. ;
  471. SENDHDR MVI    A,SOH    ;SEND..
  472.     CALL    SEND    ;..SOH,
  473.     LDA    SECTNO    ;THEN SEND..
  474.     CALL    SEND    ;..SECTOR #
  475.     LDA    SECTNO    ;THEN SECTOR #
  476.     CMA        ;..COMPLEMENTED..
  477.     CALL    SEND    ;..SECTOR #
  478.     RET        ;FROM SENDHDR
  479. ;
  480. ;---->    SENDSEC: Send the data sector
  481. ;
  482. SENDSEC MVI    C,0    ;INIT CKSUM
  483.     LXI    H,BASE+80H ;POINT TO BUFFER
  484. SENDC    MOV    A,M    ;GET A CHAR
  485.     CALL    SEND    ;SEND IT
  486.     INR    L    ;POINT TO NEXT CHAR
  487.     JNZ    SENDC    ;LOOP IF <100H
  488.     RET        ;FROM SENDSEC
  489. ;
  490. ;---->    SENDCKS: Send the checksum
  491. ;
  492. SENDCKS MOV    A,C    ;SEND THE..
  493.     CALL    SEND    ;..CHECKSUM
  494.     RET        ;FROM SENDCKS
  495. ;
  496. ;---->    GETACK: Get the ACK on the sector
  497. ;
  498. ;Returns with carry clear if ACK received.
  499. ;If an ACK is not received, the error count
  500. ;is incremented, and if less than "ERRLIM",
  501. ;carry is set and control returns.  If the
  502. ;error count is at "ERRLIM", the program
  503. ;aborts.
  504. ;
  505. GETACK    MVI    B,10    ;WAIT 10 SECONDS MAX
  506.     CALL    RECVDG    ;RECV W/GARBAGE COLLECT
  507.     JC    GETATOT ;TIMED OUT
  508.     CPI    ACK    ;OK? (CARRY OFF IF =)
  509.     RZ        ;YES, RET FROM GETACK
  510. ;
  511. ;Timeout or error on ACK - bump error count
  512. ;
  513. ACKERR    LDA    ERRCT    ;GET COUNT
  514.     INR    A    ;BUMP IT
  515.     STA    ERRCT    ;SAVE BACK
  516.     CPI    ERRLIM    ;AT LIMIT?
  517.     RC        ;NOT AT LIMIT
  518. ;
  519. ;Reached error limit
  520. ;
  521. CSABORT CALL    ERXIT
  522.     DB    '++CAN''T SEND SECTOR '
  523.     DB    '- ABORTING++',CR,LF,'$'
  524. ;
  525. ;Timeout getting ACK
  526. ;
  527. GETATOT JMP    ACKERR    ;NO MSG
  528. ABORT    LXI    SP,STACK
  529. ;
  530. ABORTL    MVI    B,1    ;1 SEC. W/O CHARS.
  531.     CALL    RECV
  532.     JNC    ABORTL    ;LOOP UNTIL SENDER DONE
  533.     MVI    A,CAN    ;CONTROL X
  534.     CALL    SEND    ;STOP SENDING END
  535. ;
  536. ABORTW    MVI    B,1    ;1 SEC W/O CHARS.
  537.     CALL    RECV
  538.     JNC    ABORTW    ;LOOP UNTIL SENDER DONE
  539.     MVI    A,' '    ;GET A SPACE...
  540.     CALL    SEND    ;TO CLEAR OUT CONTROL X
  541.     CALL    ERXIT    ;EXIT WITH ABORT MSG
  542.     DB    'XMODEM PROGRAM CANCELLED',CR,LF,'$'
  543. ;
  544. ;---->    INCRSNO: Increment sector #
  545. ;
  546. INCRSNO LDA    SECTNO    ;INCR..
  547.     INR    A    ;..SECT..
  548.     STA    SECTNO    ;..NUMBER
  549.     RET
  550. ;
  551. ;---->    CHEKFIL: See if file exists
  552. ;
  553. ;If it exists, say use a different name.
  554. ;
  555. CHEKFIL LXI    D,FCB    ;POINT TO CTL BLOCK
  556.     MVI    C,SRCHF ;SEE IF IT..
  557.     CALL    BDOS    ;..EXISTS
  558.     INR    A    ;FOUND?
  559.     RZ        ;..NO, RETURN
  560.     CALL    ERXIT    ;EXIT, PRINT ERROR MESSAGE
  561.     DB    '++FILE EXISTS - USE A DIFFERENT NAME++'
  562.     DB    CR,LF,'$'
  563. ;
  564. ;---->    MAKEFIL: Makes the file to be received
  565. ;
  566. MAKEFIL    XRA    A    ;SET EXT & REC # TO 0
  567.     STA    FCBEXT
  568.     STA    FCBSNO
  569.     LXI    D,FCB    ;POINT TO FCB
  570.     MVI    C,MAKE    ;GET BDOS FNC
  571.     CALL    BDOS    ;TO THE MAKE
  572.     INR    A    ;FF=BAD?
  573.     RNZ        ;OPEN OK
  574. ;Directory full - can't make file
  575.     CALL    ERXIT
  576.     DB    '++ERROR - CAN''T MAKE FILE++',CR,LF
  577.     DB    'Directory must be full',CR,LF,'$'
  578. ;
  579. ;---->    CNREC: Computes record count, and saves it
  580. ;           until successful file OPEN.
  581. ;
  582. ;LOOK UP THE FCB IN THE DIRECTORY
  583. CNREC    MVI    A,'?'    ;MATCH ALL EXTENTS
  584.     STA    FCBEXT
  585.     MVI    A,0FFH
  586.     STA    MAXEXT    ;INIT MAX EXT NO.
  587.     MVI    C,SRCHF ;GET 'SEARCH FIRST' FNC
  588.     LXI    D,FCB
  589.     CALL    BDOS    ;READ FIRST
  590.     INR    A    ;WERE THERE ANY?
  591.     JNZ    SOME    ;GOT SOME
  592.     CALL    ERXIT
  593.     DB    '++FILE NOT FOUND++$'
  594. ;
  595. ;READ MORE DIRECTORY ENTRIES
  596. MOREDIR    MVI    C,SRCHN ;SEARCH NEXT
  597.     LXI    D,FCB
  598.     CALL    BDOS    ;READ DIR ENTRY
  599.     INR    A    ;CHECK FOR END (0FFH)
  600.     JNZ    SOME    ;NOT END OF DIR...PROCESS EXTENT
  601.     LDA    MAXEXT    ;HIT END...GET HIGHEST EXTENT NO. SEEN
  602.     MOV    L,A    ;WHICH GIVES EXTENT COUNT - 1
  603.     MVI    H,0
  604.     MOV    D,H
  605.     LDA    RCNT    ;GET RECORD COUNT OF MAX EXTENT SEEN
  606.     MOV    E,A    ;SAVE IT IN DE
  607.     DAD    H
  608.     DAD    H    ;MULTIPLY # OF EXTENTS - 1
  609.     DAD    H    ; TIMES 128
  610.     DAD    H
  611.     DAD    H
  612.     DAD    H
  613.     DAD    H
  614.     DAD    D    ;ADD IN SIZE OF LAST EXTENT
  615.     SHLD    RCNT    ;SAVE TOTAL RECORD COUNT
  616.     RET        ;AND EXIT
  617. ;
  618. ;POINT TO DIRECTORY ENTRY 
  619. SOME    DCR    A    ;UNDO PREV 'INR A'
  620.     ANI    3    ;MAKE MODULUS 4
  621.     ADD    A    ;MULTIPLY...
  622.     ADD    A    ;..BY 32 BECAUSE
  623.     ADD    A    ;..EACH DIRECTORY
  624.     ADD    A    ;..ENTRY IS 32
  625.     ADD    A    ;..BYTES LONG
  626.     LXI    H,BASE+80H ;POINT TO BUFFER
  627.     ADD    L    ;POINT TO ENTRY
  628.     ADI    15    ;OFFSET TO RECORD COUNT
  629.     MOV    L,A    ;HL NOW POINTS TO REC COUNT
  630.     MOV    B,M    ;GET RECORD COUNT
  631.     DCX    H
  632.     DCX    H    ;BACK DOWN TO EXTENT NUMBER
  633.     DCX    H
  634.     LDA    MAXEXT    ;COMPARE WITH CURRENT MAX.
  635.     ORA    A    ;IF NO MAX YET
  636.     JM    BIGGER    ;THEN SAVE RECORD COUNT ANYWAY
  637.     CMP    M
  638.     JNC    MOREDIR
  639. BIGGER:    MOV    A,B    ;SAVE NEW RECORD COUNT
  640.     STA    RCNT
  641.     MOV    A,M    ;SAVE NEW MAX. EXTENT NO.
  642.     STA    MAXEXT
  643.     JMP    MOREDIR    ;GO FIND MORE EXTENTS
  644. ;
  645. ;---->    OPENFIL: Opens the file to be sent
  646. ;
  647. OPENFIL    XRA    A    ;SET EXT & REC # TO 0 FOR PROPER OPEN
  648.     STA    FCBEXT
  649.     STA    FCBSNO
  650.     LXI    D,FCB    ;POINT TO FILE
  651.     MVI    C,OPEN    ;GET FUNCTION
  652.     CALL    BDOS    ;OPEN IT
  653.     INR    A    ;OPEN OK?
  654.     JNZ    OPENOK    ;..YES
  655.     CALL    ERXIT    ;..NO, ABORT
  656.     DB    '++OPEN ERROR++',CR,LF,'$'
  657. ;
  658. ;Check for distribution-protected file
  659. ;
  660. OPENOK    LDA    FCB+1    ;FIRST CHAR OF FILE NAME
  661.     ANI    80H    ;CHECK BIT 7
  662.     JNZ    OPENOT    ;If on, file can't be sent.
  663.     LDA    FCB+2    ;Also check "f2" for tag.
  664.     ANI    80H    ;Is it set?
  665.     JZ    OPENOK2    ;If not, ok to send file.
  666. ;
  667. OPENOT    CALL    ERXIT    ;EXIT W/MESSAGE
  668.     DB    '++THIS FILE IS NOT FOR DISTRIBUTION, SORRY++'
  669.     DB    CR,LF,'$'
  670. ;
  671. OPENOK2 EQU    $
  672. ;
  673.     IF    NOLBS OR NOCOMS ;CHECK FOR SEND RESTRICTIONS
  674.     LXI    H,FCB+11
  675.     MOV    A,M    ;CHECK FOR PROTECT ATTR
  676.     ANI    7FH    ;REMOVE CP/M 2.x ATTRS
  677.     ENDIF        ;NOLBS OR NOCOMS
  678. ;
  679.     IF    NOLBS    ;DON'T ALLOW '#' TO BE SENT.
  680.     CPI    '#'    ;CHK FOR '#' AS LAST FIRST
  681.     JZ    OPENOT    ;IF '#', CAN'T SEND, SHOW WHY
  682.     ENDIF        ;NOLBS
  683. ;
  684.     IF    NOCOMS    ;DON'T ALLOW .COM TO BE SENT
  685.     CPI    'M'    ;IF NOT, CHK FOR '.COM'
  686.     JNZ    OPENOK3 ;IF NOT, OK TO SEND
  687.     DCX    H
  688.     MOV    A,M    ;CHK NEXT CHAR
  689.     ANI    7FH    ;STRIP ATTRIBUTES
  690.     CPI    'O'    ; 'O'?
  691.     JNZ    OPENOK3 ;IF NOT, OK TO SEND
  692.     DCX    H
  693.     MOV    A,M    ;NOW CHK FIRST CHAR
  694.     ANI    7FH    ;STRIP ATTRIBUTES
  695.     CPI    'C'    ; 'C' AS IN '.COM'?
  696.     JNZ    OPENOK3 ;IF NOT, CONTINUE
  697.     CALL    ERXIT    ;EXIT W/MESSAGE
  698.     DB    '++CAN''T SEND A .COM FILE++'
  699.     DB    CR,LF,'$'
  700.     ENDIF        ;NOCOMS
  701. ;
  702. OPENOK3 CALL    ILPRT    ;PRINT:
  703.     DB    'FILE OPEN - SIZE: ',0
  704.     LHLD    RCNT    ; Get record count.
  705.     CALL    DECOUT    ;PRINT DECIMAL NUMBER OF SECTORS
  706.     CALL    ILPRT    ;Print:
  707.     DB    ' (',0
  708.     CALL    DHXOUT    ;Now print size in hex.
  709.     CALL    ILPRT    ;PRINT:
  710.     DB    'H) SECTORS',CR,LF,0
  711.     RET
  712. ;
  713. ;---->    CLOSFIL: Closes the received file
  714. ;
  715. CLOSFIL LXI    D,FCB    ;POINT TO FILE
  716.     MVI    C,CLOSE ;GET FUNCTION
  717.     CALL    BDOS    ;CLOSE IT
  718.     INR    A    ;CLOSE OK?
  719.     RNZ        ;..YES, RETURN
  720.     CALL    ERXIT    ;..NO, ABORT
  721.     DB    '++CAN''T CLOSE FILE++',CR,LF,'$'
  722. ;
  723. ;
  724. ;----> DECOUT: Decimal output routine
  725. ;
  726. DECOUT:    PUSH    B
  727.     PUSH    D
  728.     PUSH    H
  729.     LXI    B,-10
  730.     LXI    D,-1
  731. ;
  732. DECOU2:    DAD    B
  733.     INX    D
  734.     JC    DECOU2
  735.     LXI    B,10
  736.     DAD    B
  737.     XCHG
  738.     MOV    A,H
  739.     ORA    L
  740.     CNZ    DECOUT
  741.     MOV    A,E
  742.     ADI    '0'
  743.     CALL    CTYPE
  744.     POP    H
  745.     POP    D
  746.     POP    B
  747.     RET
  748. ;
  749. ; DHXOUT - double precision hex output routine.
  750. ;       Call with hex value in HL.
  751. ;
  752. DHXOUT    PUSH    H    ;Save H,L
  753.     PUSH    PSW    ;Save A
  754.     MOV    A,H    ;Get MS byte.
  755.     CALL    HEXO    ;Output hi order byte.
  756.     MOV    A,L    ;Get LS byte.
  757.     CALL    HEXO    ;Output lo order byte.
  758.     POP    PSW    ;Restore A
  759.     POP    H    ;Restore H,L
  760.     RET        ;Return to caller.
  761. ;
  762. ;
  763. ;---->    RDSECT: Reads a sector
  764. ;
  765. ;For speed, this routine buffers up 16
  766. ;sectors at a time.
  767. ;
  768. RDSECT    LDA    SECINBF ;GET # SECT IN BUFF.
  769.     DCR    A    ;DECREMENT..
  770.     STA    SECINBF ;..IT
  771.     JM    RDBLOCK ;EXHAUSTED?  NEED MORE.
  772.     LHLD    SECPTR    ;GET POINTER
  773.     LXI    D,BASE+80H ;TO DATA
  774.     CALL    MOVE128 ;MOVE TO BUFFER
  775.     SHLD    SECPTR    ;SAVE BUFFER POINTER
  776.     RET        ;FROM "READSEC"
  777. ;
  778. ;Buffer is empty - read in another block of 16
  779. ;
  780. RDBLOCK LDA    EOFLG    ;GED EOF FLAG
  781.     CPI    1    ;IS IT SET?
  782.     STC        ;TO SHOW EOF
  783.     RZ        ;GOT EOF
  784.     MVI    C,0    ;SECTORS IN BLOCK
  785.     LXI    D,DBUF    ;TO DISK BUFFER
  786. ;
  787. RDSECLP PUSH    B
  788.     PUSH    D
  789.     MVI    C,STDMA ;SET DMA..
  790.     CALL    BDOS    ;..ADDR
  791.     LXI    D,FCB
  792.     MVI    C,READ
  793.     CALL    BDOS
  794.     POP    D
  795.     POP    B
  796.     ORA    A    ;READ OK?
  797.     JZ    RDSECOK ;YES
  798.     DCR    A    ;EOF?
  799.     JZ    REOF    ;GOT EOF
  800. ;
  801. ;Read error
  802. ;
  803.     CALL    ERXIT
  804.     DB    '++FILE READ ERROR++',CR,LF,'$'
  805. ;
  806. RDSECOK LXI    H,80H    ;ADD LENGTH OF ONE SECTOR...
  807.     DAD    D    ;...TO NEXT BUFF
  808.     XCHG        ;BUFF TO DE
  809.     INR    C    ;MORE SECTORS?
  810.     MOV    A,C    ;GET COUNT
  811.     CPI    16    ;DONE?
  812.     JZ    RDBFULL ;..YES, BUFF IS FULL
  813.     JMP    RDSECLP ;READ MORE
  814. ;
  815. REOF    MVI    A,1
  816.     STA    EOFLG    ;SET EOF FLAG
  817.     MOV    A,C
  818. ;
  819. ;Buffer is full, or got EOF
  820. ;
  821. RDBFULL STA    SECINBF ;STORE SECTOR COUNT
  822.     LXI    H,DBUF    ;INIT BUFFER..
  823.     SHLD    SECPTR    ;..POINTER
  824.     LXI    D,BASE+80H ;RESET..
  825.     MVI    C,STDMA ;..DMA..
  826.     CALL    BDOS    ;..ADDR
  827.     JMP    RDSECT    ;PASS SECT TO CALLER
  828. ;
  829. ;---->    WRSECT: Write a sector
  830. ;
  831. ;Writes the sector into a buffer.  When 16
  832. ;have been written, writes the block to disk.
  833. ;
  834. ;Entry point "WRBLOCK" flushes the buffer at EOF.
  835. ;
  836. WRSECT    LHLD    SECPTR    ;GET BUFF ADDR
  837.     XCHG        ;TO DE FOR MOVE
  838.     LXI    H,BASE+80H    ;FROM HERE
  839.     CALL    MOVE128 ;MOVE TO BUFFER
  840.     XCHG        ;SAVE NEXT..
  841.     SHLD    SECPTR    ;..BLOCK POINTER
  842.     LDA    SECINBF ;BUMP THE..
  843.     INR    A    ;..SECTOR #..
  844.     STA    SECINBF ;..IN THE BUFF
  845.     CPI    16    ;HAVE WE 16?
  846.     RNZ        ;NO, RETURN
  847. ;
  848. ;---->    WRBLOCK: Writes a block to disk
  849. ;
  850. WRBLOCK LDA    SECINBF ;# SECT IN BUFFER
  851.     ORA    A    ;0 MEANS END OF FILE
  852.     RZ        ;NONE TO WRITE
  853.     MOV    C,A    ;SAVE COUNT
  854.     LXI    D,DBUF    ;POINT TO DISK BUFF
  855. ;
  856. DKWRLP    PUSH    H
  857.     PUSH    D
  858.     PUSH    B
  859.     MVI    C,STDMA ;SET DMA
  860.     CALL    BDOS    ;TO BUFFER
  861.     LXI    D,FCB    ;THEN WRITE
  862.     MVI    C,WRITE ;..THE..
  863.     CALL    BDOS    ;..BLOCK
  864.     POP    B
  865.     POP    D
  866.     POP    H
  867.     ORA    A
  868.     JNZ    WRERR    ;OOPS, ERROR
  869.     LXI    H,80H    ;LENGTH OF 1 SECT
  870.     DAD    D    ;HL= NEXT BUFF
  871.     XCHG        ;TO DE FOR SETDMA
  872.     DCR    C    ;MORE SECTORS?
  873.     JNZ    DKWRLP    ;..YES, LOOP
  874.     XRA    A    ;GET A ZERO
  875.     STA    SECINBF ;RESET # OF SECTORS
  876.     LXI    H,DBUF    ;RESET BUFFER..
  877.     SHLD    SECPTR    ;..POINTER
  878. ;
  879. RSDMA    LXI    D,BASE+80H ;RESET..
  880.     MVI    C,STDMA ;..DMA..
  881.     CALL    BDOS    ;..ADDR
  882.     RET
  883. ;
  884. WRERR    CALL    RSDMA    ;RESET DMA TO NORM.
  885.     MVI    C,CAN    ;CANCEL..
  886.     CALL    SEND    ;..SENDER
  887.     CALL    ERXIT    ;EXIT W/MSG:
  888.     DB    '++ERROR WRITING FILE++',CR,LF,'$'
  889. ;
  890. ;---->    RECV: Receive a character
  891. ;
  892. ;Timeout time is in B, in seconds.  Entry via
  893. ;"RECVDG" deletes garbage characters on the
  894. ;line.    For example, having just sent a sector,
  895. ;calling RECVDG will delete any line-noise-induced
  896. ;characters "long" before the ACK/NAK would
  897. ;be received.
  898. ;
  899. RECVDG    EQU    $    ;RECEIVE W/GARBAGE DELETE
  900.     IN    MODDATP ;GET A CHAR
  901.     IN    MODDATP ;..TOTALLY PURGE UART
  902. ;
  903. RECV    PUSH    D    ;SAVE
  904. ;
  905.     IF    FASTCLK ;4MHZ?
  906.     MOV    A,B    ;GET TIME REQUEST
  907.     ADD    A    ;DOUBLE IT
  908.     MOV    B,A    ;NEW TIME IN B
  909.     ENDIF
  910. ;
  911. MSEC    LXI    D,50000 ;1 SEC DCR COUNT
  912. ;
  913.     IF    NOT DCH
  914. MWTI    IN    MODCTLP ;CHECK STATUS
  915.     ENDIF
  916. ;
  917.     IF    DCH
  918. MWTI    IN    MODCTL2 ;CHECK STATUS
  919.     ENDIF
  920. ;
  921.     ANI    MODRCVB ;ISOLATE BIT
  922.     CPI    MODRCVR ;READY?
  923.     JZ    MCHAR    ;GOT CHAR
  924.     DCR    E    ;COUNT..
  925.     JNZ    MWTI    ;..DOWN..
  926.     DCR    D    ;..FOR..
  927.     JNZ    MWTI    ;..TIMEOUT
  928.     DCR    B    ;MORE SECONDS?
  929.     JNZ    MSEC    ;YES, WAIT
  930. ;
  931. ;Test for the presence of carrier - if none, go to 
  932. ;CARCK and continue testing for 15 seconds. If carrier
  933. ;returns, continue. If is doesn't return, exit.
  934. ;
  935.     IF    NOT DCH AND NOT PMMI
  936.     IN    MODCTL2    ;Read modem status.
  937.     ENDIF
  938. ;
  939.     IF    DCH
  940.     IN    MODCTLP    ;Read modem status.
  941.     ENDIF
  942. ;
  943.     IF    PMMI
  944.     IN    BAUDRP    ;Read modem status.
  945.     ENDIF
  946. ;
  947.     ANI    MODDCDB    ;Carrier detect mask.
  948.     CPI    MODDCDA    ;Is it still on?
  949.     CNZ    CARCK    ;If not, test for 15 seconds.
  950. ;
  951. ;Modem timed out receiving - but carrier still on.
  952. ;
  953.     POP    D    ;RESTORE D,E
  954.     STC        ;CARRY SHOWS TIMEOUT
  955.     RET
  956. ;
  957. ;Got character from modem
  958. ;
  959. MCHAR    IN    MODDATP ;READ THE CHAR
  960.     POP    D    ;RESTORE DE
  961. ;
  962. ;Calc checksum
  963. ;
  964.     PUSH    PSW    ;SAVE THE CHAR
  965.     ADD    C    ;ADD TO CHECKSUM
  966.     MOV    C,A    ;SAVE CHECKSUM
  967.     POP    PSW    ;RESTORE CHAR
  968.     ORA    A    ;CARRY OFF: NO ERROR
  969.     RET        ;FROM "RECV"
  970. ;
  971. ; CARCK - common 15 second carrier test for RECV and
  972. ; SEND. If carrier returns within 15 seconds, normal
  973. ; program execution continues. Else, it will abort
  974. ; to CP/M via EXIT.
  975. ;
  976. CARCK    MVI    E,150    ;Value for 15 second delay.
  977. CARCK1    CALL    DELAY    ;Kill .1 seconds.
  978.     ;
  979.     IF    NOT DCH AND NOT PMMI
  980.     IN    MODCTL2    ;Read modem status.
  981.     ENDIF
  982. ;
  983.     IF    DCH
  984.     IN    MODCTLP    ;Read modem status.
  985.     ENDIF
  986. ;
  987.     IF    PMMI
  988.     IN    BAUDRP    ;Read modem status.
  989.     ENDIF
  990. ;
  991.     ANI    MODDCDB    ;Carrier detect mask.
  992.     CPI    MODDCDA    ;Is it still on?
  993.     RZ        ;Return if carrier on.
  994.     DCR    E    ;Has 15 seconds expired?
  995.     JNZ    CARCK1    ;If not, continue testing.
  996.     JMP    EXIT    ;Else, abort to CP/M.
  997. ;
  998. ; DELAY - 100 millisecond delay.
  999. ;
  1000. DELAY    PUSH    B    ;Save B,C
  1001. ;
  1002.     IF    FASTCLK    ;If 4mhz clock.
  1003.     LXI    B,16667    ;Value for 100 ms delay.
  1004.     ENDIF
  1005. ;
  1006.     IF    NOT FASTCLK
  1007.     LXI    B,8334    ;Value for 100ms delay.
  1008.     ENDIF
  1009. ;
  1010. DELAY2    DCX    B    ;Update count.
  1011.     MOV    A,B    ;Get MS byte.
  1012.     ORA    C    ;Count = zero?
  1013.     JNZ    DELAY2    ;If not, continue.
  1014.     POP    B    ;Restore B,C
  1015.     RET        ;Return to CARCK1.
  1016. ;
  1017. ;
  1018. ;
  1019. ;---->    SEND: Send a character to the modem
  1020. ;
  1021. SEND    PUSH    PSW    ;SAVE THE CHAR
  1022.     ADD    C    ;CALC CKSUM
  1023.     MOV    C,A    ;SAVE CKSUM
  1024. ;
  1025.     IF    NOT DCH
  1026. SENDW    IN    MODCTLP ;GET STATUS
  1027.     ENDIF
  1028. ;
  1029.     IF    DCH
  1030. SENDW    IN    MODCTL2 ;GET STATUS
  1031.     ENDIF
  1032. ;
  1033.     ANI    MODSNDB ;ISOLATE READY BIT
  1034.     CPI    MODSNDR ;READY?
  1035.     JZ    SENDR    ;..Yes, go send.
  1036. ;
  1037. ;Xmit status not ready, so test for carrier before
  1038. ;looping - if lost, go to CARCK and give it up to 15
  1039. ;seconds to return. If it doesn't return abort via
  1040. ;EXIT.
  1041. ;
  1042.     PUSH    D    ;Save D,E
  1043. ;
  1044.     IF    NOT DCH AND NOT PMMI
  1045.     IN    MODCTL2    ;Read modem status.
  1046.     ENDIF
  1047. ;
  1048.     IF    DCH
  1049.     IN    MODCTLP    ;Read modem status.
  1050.     ENDIF
  1051. ;
  1052.     IF    PMMI
  1053.     IN    BAUDRP    ;Read modem status.
  1054.     ENDIF
  1055. ;
  1056.     ANI    MODDCDB    ;Carrier detect mask.
  1057.     CPI    MODDCDA    ;Is it still on?
  1058.     CNZ    CARCK    ;If not, continue testing it.
  1059.     POP    D    ;Restore D,E
  1060.     JMP    SENDW    ;Else, wait for xmit ready.
  1061. ;
  1062. ;Xmit status ready, carrier still on - send the data.
  1063. ;
  1064. SENDR    POP    PSW    ;GET CHAR
  1065.     OUT    MODDATP ;OUTPUT IT
  1066.     RET        ;FROM "SEND"
  1067. ;
  1068. ;---->    WAITNAK: Waits for initial NAK
  1069. ;
  1070. ;To ensure no data is sent until the receiving
  1071. ;program is ready, this routine waits for the
  1072. ;first timeout-NAK from the receiver.
  1073. ;(E) contains the # of seconds to wait.
  1074. ;
  1075. WAITNAK MVI    B,1    ;TIMEOUT DELAY
  1076.     CALL    RECV    ;DID WE GET..
  1077.     CPI    NAK    ;..A NAK?
  1078.     RZ        ;YES, SEND BLOCK
  1079.     DCR    E    ;80 TRIES?
  1080.     JZ    ABORT    ;YES, ABORT
  1081.     JMP    WAITNAK ;NO, LOOP
  1082. ;
  1083. ;---->    MOVEFCB: Moves FCB(2) to FCB
  1084. ;
  1085. ;In order to make the XMODEM command 'natural',
  1086. ;i.e. XMODEM SEND FILENAME (MODEM S FN.FT) rather
  1087. ;than XMODEM FILENAME SEND (MODEM FN.FT S), this
  1088. ;routine moves the filename from the second FCB
  1089. ;to the first.
  1090. ;
  1091. MOVEFCB LXI    H,FCB+16 ;FROM
  1092.     LXI    D,FCB    ;TO
  1093.     MVI    B,16    ;LEN
  1094.     CALL    MOVE    ;DO THE MOVE
  1095.     XRA    A    ;GET 0
  1096.     STA    FCBSNO    ;ZERO SECTOR #
  1097.     STA    FCBEXT    ;..AND EXTENT
  1098.     RET
  1099. ;
  1100. CTYPE    PUSH    B    ;SAVE..
  1101.     PUSH    D    ;..ALL..
  1102.     PUSH    H    ;..REGS
  1103.     MOV    E,A    ;CHAR TO E
  1104.     MVI    C,WRCON ;GET BDOS FNC
  1105.     CALL    BDOS    ;PRIN THE CHR
  1106.     POP    H    ;RESTORE..
  1107.     POP    D    ;..ALL..
  1108.     POP    B    ;..REGS
  1109.     RET        ;FROM "CTYPE"
  1110. ;
  1111. HEXO    PUSH    PSW    ;SAVE FOR RIGHT DIGIT
  1112.     RAR        ;RIGHT..
  1113.     RAR        ;..JUSTIFY..
  1114.     RAR        ;..LEFT..
  1115.     RAR        ;..DIGIT..
  1116.     CALL    NIBBL    ;PRINT LEFT DIGIT
  1117.     POP    PSW    ;RESTORE RIGHT
  1118. ;
  1119. NIBBL    ANI    0FH    ;ISOLATE DIGIT
  1120.     CPI    10    ;IS IT <10?
  1121.     JC    ISNUM    ;YES, NOT ALPHA
  1122.     ADI    7    ;ADD ALPHA BIAS
  1123. ;
  1124. ISNUM    ADI    '0'    ;MAKE PRINTABLE
  1125.     JMP    CTYPE    ;..THEN TYPE IT
  1126. ;
  1127. ;---->    ILPRT: Inline print of message
  1128. ;
  1129. ;The call to ILPRT is followed by a message,
  1130. ;binary 0 as the end.
  1131. ;
  1132. ILPRT    XTHL        ;SAVE HL, GET HL=MSG
  1133. ;
  1134. ILPLP    MOV    A,M    ;GET CHAR
  1135.     ORA    A    ;END OF MSG?
  1136.     JZ    ILPRET    ;..YES, RETURN
  1137.     CALL    CTYPE    ;TYPE THE MSG
  1138.     INX    H    ;TO NEXT CHAR
  1139.     JMP    ILPLP    ;LOOP
  1140. ;
  1141. ILPRET    XTHL        ;RESTORE HL
  1142.     RET        ;PAST MSG
  1143. ;
  1144. ;---->    ERXIT: Exit printing message following call
  1145. ;
  1146. ERXIT    POP    D    ;GET MESSAGE
  1147.     MVI    C,PRINT ;GET BDOS FNC
  1148.     CALL    BDOS    ;PRINT MESSAGE
  1149. ;
  1150. EXIT    LHLD    STACK    ;GET ORIGINAL STACK
  1151.     SPHL        ;RESTORE IT
  1152.     RET        ;--EXIT-- TO CP/M
  1153. ;
  1154. ;Move 128 characters
  1155. ;
  1156. MOVE128 MVI    B,128    ;SET MOVE COUNT
  1157. ;
  1158. ;Move from (HL) to (DE) length in (B)
  1159. ;
  1160. MOVE    MOV    A,M    ;GET A CHAR
  1161.     STAX    D    ;STORE IT
  1162.     INX    H    ;TO NEXT "FROM"
  1163.     INX    D    ;TO NEXT "TO"
  1164.     DCR    B    ;MORE?
  1165.     JNZ    MOVE    ;..YES, LOOP
  1166.     RET        ;..NO, RETURN
  1167. ;
  1168. ;Temporary storage area
  1169. ;
  1170. MAXEXT    DB    0    ;HIGHEST EXTENT NO. SEEN IN FILE SIZE CALC.
  1171. RCNT    DW    0    ;RECORD COUNT
  1172. RCVSNO    DB    0    ;SECT # RECEIVED
  1173. SECTNO    DB    0    ;CURRENT SECTOR NUMBER 
  1174. ERRCT    DB    0    ;ERROR COUNT
  1175. ;Following 3 used by disk buffering routines
  1176. EOFLG    DB    0    ;EOF FLAG (1=TRUE)
  1177. SECPTR    DW    DBUF
  1178. SECINBF DB    0    ;# OF SECTORS IN BUFFER
  1179.     DS    60    ;STACK AREA
  1180. STACK    DS    2    ;STACK POINTER
  1181. ;
  1182. ;16 sector disk buffer
  1183. ;
  1184. DBUF    EQU    $    ;16 SECTOR DISK BUFFER
  1185. ;
  1186. ;BDOS equates
  1187. ;
  1188. RDCON    EQU    1
  1189. WRCON    EQU    2
  1190. PRINT    EQU    9
  1191. CONST    EQU    11    ;CONSOLE STAT
  1192. OPEN    EQU    15    ;0FFH = NOT FOUND
  1193. CLOSE    EQU    16    ;    "       "
  1194. SRCHF    EQU    17    ;    "       "
  1195. SRCHN    EQU    18    ;    "       "
  1196. ERASE    EQU    19    ;NO RET CODE
  1197. READ    EQU    20    ;0=OK, 1=EOF
  1198. WRITE    EQU    21    ;0=OK, 1=ERR, 2=?, 0FFH=NO DIR SPC
  1199. MAKE    EQU    22    ;0FFH=BAD
  1200. REN    EQU    23    ;0FFH=BAD
  1201. STDMA    EQU    26    ;SET DMA
  1202. BDOS    EQU    BASE+5
  1203. FCB    EQU    BASE+5CH ;SYSTEM FCB
  1204. FCBEXT    EQU    FCB+12    ;FILE EXTENT
  1205. FCBSNO    EQU    FCB+32    ;SECTOR #
  1206. FCB2    EQU    BASE+6CH ;SECOND FCB
  1207. ;
  1208.     END
  1209.  
  1210.