home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / simtel / sigm / vols000 / vol007 / xmodem32.asm < prev    next >
Assembly Source File  |  1984-04-29  |  20KB  |  865 lines

  1. ;
  2. ;XMODEM.ASM V3.2, BY KEITH PETERSEN, W8SDZ
  3. ;       (revised 9/13/80)
  4. ;
  5. ;CP/M - CP/M FILE TRANSFER PROGRAM
  6. ;BASED ON MODEM.ASM V2.0, BY WARD CHRISTENSEN
  7. ;THIS PROGRAM IS INTENDED FOR USE ON REMOTE CP/M
  8. ;SYSTEMS WHERE IT IS IMPORTANT THAT THE INITIALIZATION
  9. ;OF THE MODEM NOT BE CHANGED, SUCH AS WHEN USING
  10. ;THE PMMIBYE PROGRAM. THE BAUD RATE AND NUMBER OF BITS
  11. ;REMAINS THE SAME AS WHATEVER WAS SET PREVIOUSLY.
  12. ;THERE IS NO DISCONNECT, TERMINAL OR ECHO OPTION.
  13. ;
  14. ;NOTE: THIS FILE WILL ASSEMBLE, WITHOUT NEED FOR
  15. ;EDITING, TO WORK WITH A PMMI MM-103 MODEM.  SEE
  16. ;EQUATES FOR OTHER OPTIONS INCLUDING SYSTEM CLOCK
  17. ;FREQUENCY AND OTHER TYPES OF MODEMS.
  18. ;
  19. ; Added conditional assembly to prevent filetypes
  20. ;'.COM' or '.??#' from being sent to distant end
  21. ;and added conditional assembly of test for '.COM'
  22. ;filetype on receive as well. See 'NOCOM' below.
  23. ; Any filetype ending in '#' will not be sent by
  24. ;this program if 'NOCOM' is set to TRUE.
  25. ;            9-SEP-80    J.SEYMOUR
  26. ;
  27. FALSE    EQU    0
  28. TRUE    EQU    NOT FALSE
  29. ;
  30. STDCPM    EQU    TRUE    ;TRUE, IS STANDARD CP/M
  31. ALTCPM    EQU    FALSE    ;TRUE, IS H8 OR TRS-80 CP/M
  32. ;
  33.     IF    STDCPM
  34. BASE    EQU    0    ;CP/M BASE ADDRESS
  35.     ENDIF
  36. ;
  37.     IF    ALTCPM
  38. BASE    EQU    4200H    ;ALTERNATE CP/M BASE ADDRESS
  39.     ENDIF
  40. ;
  41. PMMI    EQU    TRUE    ;TRUE, IS PMMI
  42. ;
  43. DCH    EQU    FALSE    ;TRUE, IS D.C. HAYES
  44. ;
  45. NOCOM    EQU    TRUE    ;TRUE, NO .COM OR .??# FILES
  46.             ;SENT OR '.COM' RECEIVED
  47. ;
  48.     IF    PMMI
  49. MODCTLP    EQU    0C0H    ;PMMI VALUES
  50. MODSNDB EQU    1    ;BIT TO TEST FOR SEND
  51. MODSNDR    EQU    1    ;VALUE WHEN READY
  52. MODRCVB EQU    2    ;BIT TO TEST FOR RECEIVE
  53. MODRCVR    EQU    2    ;VALUE WHEN READY
  54. MODDATP EQU    0C1H    ;DATA PORT
  55. BAUDRP    EQU    0C2H    ;BAUD RATE OUTPUT
  56. MODCTL2    EQU    0C3H    ;SECOND CTL PORT
  57.     ENDIF
  58. ;
  59.     IF    DCH
  60. MODCTLP    EQU    82H    ;D. C. HAYES VALUES
  61. MODSNDB EQU    2    ;BIT TO TEST FOR SEND
  62. MODSNDR    EQU    2    ;VALUE WHEN READY
  63. MODRCVB EQU    1    ;BIT TO TEST FOR RECEIVE
  64. MODRCVR    EQU    1    ;VALUE WHEN READY
  65. MODDATP EQU    80H    ;DATA PORT
  66. MODCTL2    EQU    81H    ;SECOND CTL PORT
  67.     ENDIF
  68. ;
  69. ;IF YOU ARE USING AN EXTERNAL MODEM (NOT S-100 PLUG-IN)
  70. ;CHANGE THESE EQUATES FOR YOUR MODEM PORT REQUIREMENTS
  71. ;
  72.     IF    NOT PMMI AND NOT DCH
  73. MODCTLP    EQU    02H    ;PUT YOUR MODEM CONTROL PORT HERE
  74. MODSNDB    EQU    80H    ;YOUR BIT TO TEST FOR SEND
  75. MODSNDR    EQU    80H    ;YOUR VALUE WHEN READY
  76. MODRCVB    EQU    40H    ;YOUR BIT TO TEST FOR RECEIVE
  77. MODRCVR    EQU    40H    ;YOUR VALUE WHEN READY
  78. MODDATP    EQU    03H    ;YOUR MODEM DATA PORT
  79.     ENDIF        ;END OF EXTERNAL MODEM EQUATES
  80. ;
  81. ERRLIM    EQU    10    ;MAX ALLOWABLE ERRORS
  82. ;
  83. FASTCLK    EQU    FALSE    ;PUT TRUE HERE FOR 4 MHZ CLOCK
  84. ;
  85. ;DEFINE ASCII CHARACTERS USED
  86. ;
  87. SOH    EQU    1    ;START OF HEADER
  88. EOT    EQU    4    ;END OF TRANSMISSION
  89. ACK    EQU    6    ;ACKNOWLEDGE
  90. NAK    EQU    15H    ;NEG ACKNOWLEDGE
  91. CAN    EQU    18H    ;CONTROL-X FOR CANCEL
  92. LF    EQU    10    ;LINEFEED
  93. CR    EQU    13    ;CARRIAGE RETURN
  94.     ORG    BASE+100H
  95. ;
  96. ;INIT PRIVATE STACK
  97.     LXI    H,0    ;HL=0
  98.     DAD    SP    ;HL=STACK FROM CP/M
  99.     SHLD    STACK    ;..SAVE IT
  100.     LXI    SP,STACK ;SP=MY STACK
  101.     CALL    ILPRT    ;PRINT:
  102.     DB    CR,LF
  103.     DB    'XMODEM ver 3.2',CR,LF,0
  104. ;
  105. ;GET OPTION
  106. ;
  107.     LDA    FCB+1    ;GET OPTION (S or R)
  108.     PUSH    PSW    ;SAVE OPTION
  109. ;
  110. ;MOVE THE FILENAME FROM FCB 2 TO FCB 1
  111. ;
  112.     CALL    MOVEFCB
  113. ;
  114. ;GOBBLE UP GARBAGE CHARS FROM THE LINE
  115. ;PRIOR TO RECEIVE OR SEND
  116. ;
  117.     IN    MODDATP
  118.     IN    MODDATP
  119. ;
  120. ;JMP TO APPROPRIATE FUNCTION
  121. ;
  122.     POP    PSW    ;GET OPTION
  123. ;
  124.            CPI    'S'    ;SEND..
  125.     JZ    SENDFIL    ;..A FILE?
  126. ;
  127.     CPI    'R'    ;RECEIVE..
  128.     JZ    RCVFIL    ;..A FILE?
  129. ;
  130. ;INVALID OPTION
  131.     CALL    ERXIT    ;EXIT W/ERROR
  132.     DB    '++INVALID OPTION ON XMODEM '
  133.     DB    'COMMAND++',CR,LF
  134.     DB    'Must be S for SEND or R for '
  135.     DB    'RECEIVE',CR,LF,'$'
  136. ;
  137. * * * * * * * * * * * * * * * * * * * * *
  138. *                    *
  139. *    SENDFIL: SENDS A CP/M FILE    *
  140. *                    *
  141. * * * * * * * * * * * * * * * * * * * * *
  142. ;
  143. ;THE CP/M FILE SPECIFIED IN THE MODEM COMMAND
  144. ;IS TRANSFERRED OVER THE PHONE TO ANOTHER
  145. ;COMPUTER RUNNING MODEM WITH THE "R" (RECEIVE)
  146. ;OPTION.  THE DATA IS SENT ONE SECTOR AT A
  147. ;TIME WITH HEADERS AND CHECKSUMS, AND RE-
  148. ;TRANSMISSION ON ERRORS.  
  149. ;
  150. ;
  151. SENDFIL    CALL    OPENFIL    ;OPEN THE FILE
  152.     MVI    E,80    ;WAIT 80 SEC..
  153.     CALL    WAITNAK    ;..FOR INITIAL NAK
  154. SENDLP    CALL    RDSECT    ;READ A SECTOR
  155.     JC    SENDEOF    ;SEND EOF IF DONE
  156.     CALL    INCRSNO    ;BUMP SECTOR #
  157.     XRA    A    ;ZERO ERROR..
  158.     STA    ERRCT    ;..COUNT
  159. SENDRPT    CALL    SENDHDR    ;SEND A HEADER
  160.     CALL    SENDSEC    ;SEND DATA SECTOR
  161.     CALL    SENDCKS    ;SEND CKSUM
  162.     CALL    GETACK    ;GET THE ACK
  163.     JC    SENDRPT    ;REPEAT IF NO ACK
  164.     JMP    SENDLP    ;LOOP UNTIL EOF
  165. ;
  166. ;FILE SENT, SEND EOT'S
  167. ;
  168. SENDEOF    MVI    A,EOT    ;SEND..
  169.     CALL    SEND    ;..AN EOT
  170.     CALL    GETACK    ;GET THE ACK
  171.     JC    SENDEOF    ;LOOP IF NO ACK
  172.     JMP    EXIT    ;ALL DONE
  173. ;
  174. * * * * * * * * * * * * * * * * * * * * *
  175. *                    *
  176. *    RCVFIL: RECEIVE A FILE        *
  177. *                    *
  178. * * * * * * * * * * * * * * * * * * * * *
  179. ;
  180. ;RECEIVES A FILE IN BLOCK FORMAT AS SENT
  181. ;BY ANOTHER PERSON DOING "MODEM S FN.FT".
  182. ;
  183. RCVFIL    EQU    $
  184. ;
  185.     IF    NOCOM
  186.     LXI    H,FCB+9    ;POINT TO FILETYPE
  187.     MVI    A,'C'    ;1ST LETTER
  188.     CMP    M    ;IS IT C ?
  189.     JNZ    CONTINU    ;IF NOT, CONTINUE NORMALLY
  190.     INX    H    ;GET 2ND LETTER
  191.     MVI    A,'O'    ;2ND LETTER
  192.     CMP    M    ;IS IT O ?
  193.     JNZ    CONTINU    ;IF NOT, CONTINUE NORMALLY
  194.     INX     H    ;GET 3RD LETTER
  195.     MVI    A,'M'    ;3RD LETTER
  196.     CMP    M    ;IS IT M ?
  197.     JNZ    CONTINU    ;IF NOT, CONTINUE NORMALLY
  198.     CALL    ERXIT    ;EXIT, PRINT ERROR MESSAGE
  199.     DB    '++CAN''T RECEIVE A .COM FILE++'
  200.     DB    CR,LF,CR,LF
  201.     DB    'Rename filetype ".OBJ" and try again'
  202.     DB    CR,LF,'$'
  203.     ENDIF
  204. ;
  205. CONTINU CALL    CHEKFIL    ;SEE IF FILE EXISTS
  206.     CALL    MAKEFIL    ;..THEN MAKE NEW
  207.     CALL    ILPRT    ;PRINT:
  208.     DB    'FILE OPEN, READY TO RECEIVE',CR,LF,0
  209. ;
  210. RCVLP    CALL    RCVSECT    ;GET A SECTOR
  211.     JC    RCVEOT    ;GOT EOT
  212.     CALL    WRSECT    ;WRITE THE SECTOR
  213.     CALL    INCRSNO    ;BUMP SECTOR #
  214.     CALL    SENDACK    ;ACK THE SECTOR
  215.     JMP    RCVLP    ;LOOP UNTIL EOF
  216. ;
  217. ;GOT EOT ON SECTOR - FLUSH BUFFERS, END
  218. ;
  219. RCVEOT    CALL    WRBLOCK    ;WRITE THE LAST BLOCK
  220.     CALL    SENDACK    ;ACK THE SECTOR
  221.     CALL    CLOSFIL    ;CLOSE THE FILE
  222.     JMP    EXIT    ;ALL DONE
  223. ;
  224. * * * * * * * * * * * * * * * * * * * * *
  225. *                    *
  226. *        SUBROUTINES        *
  227. *                    *
  228. * * * * * * * * * * * * * * * * * * * * *
  229. ;
  230. ;
  231. ;---->    RCVSECT: RECEIVE A SECTOR
  232. ;
  233. ;RETURNS WITH CARRY SET IF EOT RECEIVED.
  234. ;
  235. RCVSECT    XRA    A    ;GET 0
  236.     STA    ERRCT    ;INIT ERROR COUNT
  237. ;
  238. RCVRPT    MVI    B,10    ;10 SEC TIMEOUT
  239.     CALL    RECV    ;GET SOH/EOT
  240.     JC    RCVSTOT    ;TIMEOUT
  241.     CPI    SOH    ;GET SOH?
  242.     JZ    RCVSOH    ;..YES
  243. ;
  244. ;EARLIER VERS. OF MODEM PROG SENT SOME NULLS -
  245. ;IGNORE THEM
  246. ;
  247.     ORA    A    ;00 FROM SPEED CHECK?
  248.     JZ    RCVRPT    ;YES, IGNORE IT
  249.     CPI    EOT    ;END OF TRANSFER?
  250.     STC        ;RETURN WITH CARRY..
  251.     RZ        ;..SET IF EOT
  252. ;
  253. ;DIDN'T GET SOH  OR EOT - 
  254. ;
  255. ;DIDN'T GET VALID HEADER - PURGE THE LINE,
  256. ;THEN SEND NAK.
  257. ;
  258. RCVSERR    MVI    B,1    ;WAIT FOR 1 SEC..
  259.     CALL    RECV    ;..WITH NO CHARS
  260.     JNC    RCVSERR    ;LOOP UNTIL SENDER DONE
  261.     MVI    A,NAK    ;SEND..
  262.     CALL    SEND    ;..THE NAK
  263.     LDA    ERRCT    ;ABORT IF..
  264.     INR    A    ;..WE HAVE REACHED..
  265.     STA    ERRCT    ;..THE ERROR..
  266.     CPI    ERRLIM    ;..LIMIT?
  267.     JC    RCVRPT    ;..NO, TRY AGAIN
  268. ;
  269. ;10 ERRORS IN A ROW - 
  270. ;
  271. RCVSABT    CALL    CLOSFIL    ;KEEP WHATEVER WE GOT
  272.     CALL    ERXIT
  273.     DB    '++UNABLE TO RECEIVE BLOCK '
  274.     DB    '- ABORTING++',CR,LF,'$'
  275. ;
  276. ;TIMEDOUT ON RECEIVE
  277. ;
  278. RCVSTOT    JMP    RCVSERR    ;BUMP ERR CT, ETC.
  279. ;
  280. ;GOT SOH - GET BLOCK #, BLOCK # COMPLEMENTED
  281. ;
  282. RCVSOH    MVI    B,1    ;TIMEOUT = 1 SEC
  283.     CALL    RECV    ;GET SECTOR
  284.     JC    RCVSTOT    ;GOT TIMEOUT
  285.     MOV    D,A    ;D=BLK #
  286.     MVI    B,1    ;TIMEOUT = 1 SEC
  287.     CALL    RECV    ;GET CMA'D SECT #
  288.     JC    RCVSTOT    ;TIMEOUT
  289.     CMA        ;CALC COMPLEMENT
  290.     CMP    D    ;GOOD SECTOR #?
  291.     JZ    RCVDATA    ;YES, GET DATA
  292. ;
  293. ;GOT BAD SECTOR #
  294. ;
  295.     JMP    RCVSERR    ;BUMP ERROR CT.
  296. ;
  297. RCVDATA    MOV    A,D    ;GET SECTOR #
  298.     STA    RCVSNO    ;SAVE IT
  299.     MVI    C,0    ;INIT CKSUM
  300.     LXI    H,BASE+80H    ;POINT TO BUFFER
  301. ;
  302. RCVCHR    MVI    B,1    ;1 SEC TIMEOUT
  303.     CALL    RECV    ;GET CHAR
  304.     JC    RCVSTOT    ;TIMEOUT
  305.     MOV    M,A    ;STORE CHAR
  306.     INR    L    ;DONE?
  307.     JNZ    RCVCHR    ;NO, LOOP
  308. ;
  309. ;VERIFY CHECKSUM
  310. ;
  311.     MOV    D,C    ;SAVE CHECKSUM
  312.     MVI    B,1    ;TIMEOUT LEN.
  313.     CALL    RECV    ;GET CHECKSUM
  314.     JC    RCVSTOT    ;TIMEOUT
  315.     CMP    D    ;CHECKSUM OK?
  316.     JNZ    RCVSERR    ;NO, ERROR
  317. ;
  318. ;GOT A SECTOR, IT'S A DUP IF = PREV,
  319. ;    OR OK IF = 1 + PREV SECTOR
  320. ;
  321.     LDA    RCVSNO    ;GET RECEIVED
  322.     MOV    B,A    ;SAVE IT
  323.     LDA    SECTNO    ;GET PREV
  324.     CMP    B    ;PREV REPEATED?
  325.     JZ    RECVACK    ;ACK TO CATCH UP
  326.     INR    A    ;CALC NEXT SECTOR #
  327.     CMP    B    ;MATCH?
  328.     JNZ    ABORT    ;NO MATCH - STOP SENDER, EXIT
  329.     RET        ;CARRY OFF - NO ERRORS
  330. ;
  331. ;PREV SECT REPEATED, DUE TO THE LAST ACK
  332. ;BEING GARBAGED.  ACK IT SO SENDER WILL CATCH UP 
  333. ;
  334. RECVACK    CALL    SENDACK    ;SEND THE ACK,
  335.     JMP    RCVSECT    ;GET NEXT BLOCK
  336. ;
  337. ;SEND AN ACK FOR THE SECTOR
  338. ;
  339. SENDACK    MVI    A,ACK    ;GET ACK
  340.     CALL    SEND    ;..AND SEND IT
  341.     RET
  342. ;
  343. ;---->    SENDHDR: SEND THE SECTOR HEADER
  344. ;
  345. ;SEND: (SOH) (BLOCK #) (COMPLEMENTED BLOCK #)
  346. ;
  347. SENDHDR    MVI    A,SOH    ;SEND..
  348.     CALL    SEND    ;..SOH,
  349.     LDA    SECTNO    ;THEN SEND..
  350.     CALL    SEND    ;..SECTOR #
  351.     LDA    SECTNO    ;THEN SECTOR #
  352.     CMA        ;..COMPLEMENTED..
  353.     CALL    SEND    ;..SECTOR #
  354.     RET        ;FROM SENDHDR
  355. ;
  356. ;---->    SENDSEC: SEND THE DATA SECTOR
  357. ;
  358. SENDSEC    MVI    C,0    ;INIT CKSUM
  359.     LXI    H,BASE+80H    ;POINT TO BUFFER
  360. SENDC    MOV    A,M    ;GET A CHAR
  361.     CALL    SEND    ;SEND IT
  362.     INR    L    ;POINT TO NEXT CHAR
  363.     JNZ    SENDC    ;LOOP IF <100H
  364.     RET        ;FROM SENDSEC
  365. ;
  366. ;---->    SENDCKS: SEND THE CHECKSUM
  367. ;
  368. SENDCKS    MOV    A,C    ;SEND THE..
  369.     CALL    SEND    ;..CHECKSUM
  370.     RET        ;FROM SENDCKS
  371. ;
  372. ;---->    GETACK: GET THE ACK ON THE SECTOR
  373. ;
  374. ;RETURNS WITH CARRY CLEAR IF ACK RECEIVED.
  375. ;IF AN ACK IS NOT RECEIVED, THE ERROR COUNT
  376. ;IS INCREMENTED, AND IF LESS THAN "ERRLIM",
  377. ;CARRY IS SET AND CONTROL RETURNS.  IF THE
  378. ;ERROR COUNT IS AT "ERRLIM", THE PROGRAM
  379. ;ABORTS.
  380. ;
  381. GETACK    MVI    B,10    ;WAIT 10 SECONDS MAX
  382.     CALL    RECVDG    ;RECV W/GARBAGE COLLECT
  383.     JC    GETATOT    ;TIMED OUT
  384.     CPI    ACK    ;OK? (CARRY OFF IF =)
  385.     RZ        ;YES, RET FROM GETACK
  386. ;
  387. ;TIMEOUT OR ERROR ON ACK - BUMP ERROR COUNT
  388. ;
  389. ACKERR    LDA    ERRCT    ;GET COUNT
  390.     INR    A    ;BUMP IT
  391.     STA    ERRCT    ;SAVE BACK
  392.     CPI    ERRLIM    ;AT LIMIT?
  393.     RC        ;NOT AT LIMIT
  394. ;
  395. ;REACHED ERROR LIMIT
  396. ;
  397. CSABORT    CALL    ERXIT
  398.     DB    '++CAN''T SEND SECTOR '
  399.     DB    '- ABORTING++',CR,LF,'$'
  400. ;
  401. ;TIMEOUT GETTING ACK
  402. ;
  403. GETATOT    JMP    ACKERR    ;NO MSG
  404. ABORT    LXI    SP,STACK
  405. ;
  406. ABORTL    MVI    B,1    ;1 SEC. W/O CHARS.
  407.     CALL    RECV
  408.     JNC    ABORTL    ;LOOP UNTIL SENDER DONE
  409.     MVI    A,CAN    ;CONTROL X
  410.     CALL    SEND    ;STOP SENDING END
  411. ;
  412. ABORTW    MVI    B,1    ;1 SEC W/O CHARS.
  413.     CALL    RECV
  414.     JNC    ABORTW    ;LOOP UNTIL SENDER DONE
  415.     MVI    A,' '    ;GET A SPACE...
  416.     CALL    SEND    ;TO CLEAR OUT CONTROL X
  417.     CALL    ERXIT    ;EXIT WITH ABORT MSG
  418.     DB    'XMODEM PROGRAM CANCELLED',CR,LF,'$'
  419. ;
  420. ;---->    INCRSNO: INCREMENT SECTOR #
  421. ;
  422. INCRSNO    LDA    SECTNO    ;INCR..
  423.     INR    A    ;..SECT..
  424.     STA    SECTNO    ;..NUMBER
  425.     RET
  426. ;
  427. ;---->    CHEKFIL: SEE IF FILE EXISTS
  428. ;
  429. ;IF IT EXISTS, SAY IT MUST BE ERASED.
  430. ;
  431. CHEKFIL    LXI    D,FCB    ;POINT TO CTL BLOCK
  432.     MVI    C,SRCHF ;SEE IF IT..
  433.     CALL    BDOS    ;..EXISTS
  434.     INR    A    ;FOUND?
  435.     RZ        ;..NO, RETURN
  436.     CALL    ERXIT    ;EXIT, PRINT ERROR MESSAGE
  437.     DB    '++FILE EXISTS, USE A DIFFERENT NAME++'
  438.     DB    CR,LF,'$'
  439. ;
  440. ;---->    MAKEFIL: MAKES THE FILE TO BE RECEIVED
  441. ;
  442. MAKEFIL    LXI    D,FCB    ;POINT TO FCB
  443.     MVI    C,MAKE    ;GET BDOS FNC
  444.     CALL    BDOS    ;TO THE MAKE
  445.     INR    A    ;FF=BAD?
  446.     RNZ        ;OPEN OK
  447. ;DIRECTORY FULL - CAN'T MAKE FILE
  448.     CALL    ERXIT
  449.     DB    '++ERROR - CAN''T MAKE FILE++',CR,LF
  450.     DB    'Directory must be full',CR,LF,'$'
  451. ;
  452. ;---->    OPENFIL: OPENS THE FILE TO BE SENT
  453. ;
  454. OPENFIL    LXI    D,FCB    ;POINT TO FILE
  455.     MVI    C,OPEN    ;GET FUNCTION
  456.     CALL    BDOS    ;OPEN IT
  457.     INR    A    ;OPEN OK?
  458.     JNZ    OPENOK    ;..YES
  459.     CALL    ERXIT    ;..NO, ABORT
  460.     DB    '++FILE NOT FOUND++',CR,LF,'$'
  461. ;
  462. ;CHECK FOR DISTRIBUTION-PROTECTED FILE
  463. ;
  464. OPENOK    LDA    FCB+1    ;FIRST CHAR OF FILE NAME
  465.     ANI    80H    ;CHECK BIT 7
  466.     JZ    OPENOK2    ;IT WAS OFF, FILE CAN BE SENT
  467. ;
  468. OPENOT    CALL    ERXIT    ;EXIT W/MESSAGE
  469.     DB    '++THIS FILE IS NOT FOR DISTRIBUTION, SORRY++'
  470.     DB    CR,LF,'$'
  471. ;
  472. OPENOK2    EQU    $
  473. ;
  474.     IF    NOCOM
  475.     LXI    H,FCB+11
  476.     MOV    A,M    ;CHECK FOR PROTECT ATTR
  477.     ANI    7FH    ;REMOVE CP/M 2.x ATTRS
  478.     CPI    '#'    ;CHK FOR '#' AS LAST FIRST
  479.     JZ    OPENOT    ;IF '#', CAN'T SEND, SHOW WHY
  480.     CPI    'M'    ;IF NOT, CHK FOR '.COM'
  481.     JNZ    OPENOK3    ;IF NOT, OK TO SEND
  482.     DCX    H
  483.     MOV    A,M    ;CHK NEXT CHAR
  484.     ANI    7FH    ;STRIP ATTRIBUTES
  485.     CPI    'O'    ; 'O'?
  486.     JNZ    OPENOK3    ;IF NOT, OK TO SEND
  487.     DCX    H
  488.     MOV    A,M    ;NOW CHK FIRST CHAR
  489.     ANI    7FH    ;STRIP ATTRIBUTES
  490.     CPI    'C'    ; 'C' AS IN '.COM'?
  491.     JNZ    OPENOK3    ;IF NOT, CONTINUE
  492.     CALL    ERXIT    ;EXIT W/MESSAGE
  493.     DB    '++CAN''T SEND A .COM FILE++'
  494.     DB    CR,LF,'$'
  495.     ENDIF
  496. ;
  497. OPENOK3    CALL    ILPRT    ;PRINT:
  498.     DB    'FILE OPEN, EXTENT LENGTH: ',0
  499.     LDA    FCB+15    ;GET # SECTORS
  500.     CALL    HEXO    ;PRINT IN HEX
  501.     CALL    ILPRT    ;PRINT H AFTER NUMBER, THEN CR,LF
  502.     DB    'H',CR,LF,0
  503.     RET
  504. ;
  505. ;---->    CLOSFIL: CLOSES THE RECEIVED FILE
  506. ;
  507. CLOSFIL    LXI    D,FCB    ;POINT TO FILE
  508.     MVI    C,CLOSE    ;GET FUNCTION
  509.     CALL    BDOS    ;CLOSE IT
  510.     INR    A    ;CLOSE OK?
  511.     RNZ        ;..YES, RETURN
  512.     CALL    ERXIT    ;..NO, ABORT
  513.     DB    '++CAN''T CLOSE FILE++',CR,LF,'$'
  514. ;
  515. ;---->    RDSECT: READS A SECTOR
  516. ;
  517. ;FOR SPEED, THIS ROUTINE BUFFERS UP 16
  518. ;SECTORS AT A TIME.
  519. ;
  520. RDSECT    LDA    SECINBF    ;GET # SECT IN BUFF.
  521.     DCR    A    ;DECREMENT..
  522.     STA    SECINBF    ;..IT
  523.     JM    RDBLOCK    ;EXHAUSTED?  NEED MORE.
  524.     LHLD    SECPTR    ;GET POINTER
  525.     LXI    D,BASE+80H    ;TO DATA
  526.     CALL    MOVE128    ;MOVE TO BUFFER
  527.     SHLD    SECPTR    ;SAVE BUFFER POINTER
  528.     RET        ;FROM "READSEC"
  529. ;
  530. ;BUFFER IS EMPTY - READ IN ANOTHER BLOCK OF 16
  531. ;
  532. RDBLOCK    LDA    EOFLG    ;GED EOF FLAG
  533.     CPI    1    ;IS IT SET/
  534.     STC        ;TO SHOW EOF
  535.     RZ        ;GOT EOF
  536.     MVI    C,0    ;SECTORS IN BLOCK
  537.     LXI    D,DBUF    ;TO DISK BUFFER
  538. RDSECLP    PUSH    B
  539.     PUSH    D
  540.     MVI    C,STDMA    ;SET DMA..
  541.     CALL    BDOS    ;..ADDR
  542.     LXI    D,FCB
  543.     MVI    C,READ
  544.     CALL    BDOS
  545.     POP    D
  546.     POP    B
  547.     ORA    A    ;READ OK?
  548.     JZ    RDSECOK    ;YES
  549.     DCR    A    ;EOF?
  550.     JZ    REOF    ;GOT EOF
  551. ;
  552. ;READ ERROR
  553. ;
  554.     CALL    ERXIT
  555.     DB    '++FILE READ ERROR',CR,LF,'$'
  556. ;
  557. RDSECOK    LXI    H,80H    ;ADD LENGTH OF ONE SECTOR...
  558.     DAD    D    ;...TO NEXT BUFF
  559.     XCHG        ;BUFF TO DE
  560.     INR    C    ;MORE SECTORS?
  561.     MOV    A,C    ;GET COUNT
  562.     CPI    16    ;DONE?
  563.     JZ    RDBFULL    ;..YES, BUFF IS FULL
  564.     JMP    RDSECLP    ;READ MORE
  565. ;
  566. REOF    MVI    A,1
  567.     STA    EOFLG    ;SET EOF FLAG
  568.     MOV    A,C
  569. ;
  570. ;BUFFER IS FULL, OR GOT EOF
  571. ;
  572. RDBFULL    STA    SECINBF    ;STORE SECTOR COUNT
  573.     LXI    H,DBUF    ;INIT BUFFER..
  574.     SHLD    SECPTR    ;..POINTER
  575.     LXI    D,BASE+80H    ;RESET..
  576.     MVI    C,STDMA    ;..DMA..
  577.     CALL    BDOS    ;..ADDR
  578.     JMP    RDSECT    ;PASS SECT TO CALLER
  579. ;
  580. ;---->    WRSECT: WRITE A SECTOR
  581. ;
  582. ;WRITES THE SECTOR INTO A BUFFER.  WHEN 16
  583. ;HAVE BEEN WRITTEN, WRITES THE BLOCK TO DISK.
  584. ;
  585. ;ENTRY POINT "WRBLOCK" FLUSHES THE BUFFER AT EOF.
  586. ;
  587. WRSECT    LHLD    SECPTR    ;GET BUFF ADDR
  588.     XCHG        ;TO DE FOR MOVE
  589.     LXI    H,BASE+80H    ;FROM HERE
  590.     CALL    MOVE128    ;MOVE TO BUFFER
  591.     XCHG        ;SAVE NEXT..
  592.     SHLD    SECPTR    ;..BLOCK POINTER
  593.     LDA    SECINBF    ;BUMP THE..
  594.     INR    A    ;..SECTOR #..
  595.     STA    SECINBF    ;..IN DHE BUFF
  596.     CPI    16    ;HAVE WE 16?
  597.     RNZ        ;NO, RETURN
  598. ;
  599. ;---->    WRBLOCK: WRITES A BLOCK TO DISK
  600. ;
  601. WRBLOCK    LDA    SECINBF    ;# SECT IN BUFFER
  602.     ORA    A    ;0 MEANS END OF FILE
  603.     RZ        ;NONE TO WRITE
  604.     MOV    C,A    ;SAVE COUNT
  605.     LXI    D,DBUF    ;POINT TO DISK BUFF
  606. ;
  607. DKWRLP    PUSH    H
  608.     PUSH    D
  609.     PUSH    B
  610.     MVI    C,STDMA    ;SET DMA
  611.     CALL    BDOS    ;TO BUFFER
  612.     LXI    D,FCB    ;THEN WRITE
  613.     MVI    C,WRITE    ;..THE..
  614.     CALL    BDOS    ;..BLOCK
  615.     POP    B
  616.     POP    D
  617.     POP    H
  618.     ORA    A
  619.     JNZ    WRERR    ;OOPS, ERROR
  620.     LXI    H,80H    ;LENGTH OF 1 SECT
  621.     DAD    D    ;HL= NEXT BUFF
  622.     XCHG        ;TO DE FOR SETDMA
  623.     DCR    C    ;MORE SECTORS?
  624.     JNZ    DKWRLP    ;..YES, LOOP
  625.     XRA    A    ;GET A ZERO
  626.     STA    SECINBF    ;RESET # OF SECTORS
  627.     LXI    H,DBUF    ;RESET BUFFER..
  628.     SHLD    SECPTR    ;..POINTER
  629. ;
  630. RSDMA    LXI    D,BASE+80H ;RESET..
  631.     MVI    C,STDMA    ;..DMA..
  632.     CALL    BDOS    ;..ADDR
  633.     RET
  634. ;
  635. WRERR    CALL    RSDMA    ;RESET DMA TO NORM.
  636.     MVI    C,CAN    ;CANCEL..
  637.     CALL    SEND    ;..SENDER
  638.     CALL    ERXIT    ;EXIT W/MSG:
  639.     DB    '++ERROR WRITING FILE++',CR,LF,'$'
  640. ;
  641. ;---->    RECV: RECEIVE A CHARACTER
  642. ;
  643. ;TIMEOUT TIME IS IN B, IN SECONDS.  ENTRY VIA
  644. ;"RECVDG" DELETES GARBAGE CHARACTERS ON THE
  645. ;LINE.  FOR EXAMPLE, HAVING JUST SENT A SECTOR,
  646. ;CALLING RECVDG WILL DELETE ANY LINE-NOISE-INDUCED
  647. ;CHARACTERS "LONG" BEFORE THE ACK/NAK WOULD
  648. ;BE RECEIVED.
  649. ;
  650. RECVDG    EQU    $    ;RECEIVE W/GARBAGE DELETE
  651.     IN    MODDATP    ;GET A CHAR
  652.     IN    MODDATP    ;..TOTALLY PURGE UART
  653. ;
  654. RECV    PUSH    D    ;SAVE
  655. ;
  656.     IF    FASTCLK    ;4MHZ?
  657.     MOV    A,B    ;GET TIME REQUEST
  658.     ADD    A    ;DOUBLE IT
  659.     MOV    B,A    ;NEW TIME IN B
  660.     ENDIF
  661. ;
  662. MSEC    LXI    D,50000    ;1 SEC DCR COUNT
  663. ;
  664.     IF    NOT DCH
  665. MWTI    IN    MODCTLP    ;CHECK STATUS
  666.     ENDIF
  667. ;
  668.     IF    DCH
  669. MWTI    IN    MODCTL2    ;CHECK STATUS
  670.     ENDIF
  671. ;
  672.     ANI    MODRCVB    ;ISOLATE BIT
  673.     CPI    MODRCVR    ;READY?
  674.     JZ    MCHAR    ;GOT CHAR
  675.     DCR    E    ;COUNT..
  676.     JNZ    MWTI    ;..DOWN..
  677.     DCR    D    ;..FOR..
  678.     JNZ    MWTI    ;..TIMEOUT
  679.     DCR    B    ;MORE SECONDS?
  680.     JNZ    MSEC    ;YES, WAIT
  681. ;
  682. ;MODEM TIMED OUT RECEIVING
  683. ;
  684.     POP    D    ;RESTORE D,E
  685.     STC        ;CARRY SHOWS TIMEOUT
  686.     RET
  687. ;
  688. ;GOT CHAR FROM MODEM
  689. ;
  690. MCHAR    IN    MODDATP    ;READ THE CHAR
  691.     POP    D    ;RESTORE DE
  692. ;
  693. ;CALC CHECKSUM
  694. ;
  695.     PUSH    PSW    ;SAVE THE CHAR
  696.     ADD    C    ;ADD TO CHECKSUM
  697.     MOV    C,A    ;SAVE CHECKSUM
  698.     POP    PSW    ;RESTORE CHAR
  699.     ORA    A    ;CARRY OFF: NO ERROR
  700.     RET        ;FROM "RECV"
  701. ;
  702. ;---->    SEND: SEND A CHARACTER TO THE MODEM
  703. ;
  704. SEND    PUSH    PSW    ;SAVE THE CHAR
  705.     ADD    C    ;CALC CKSUM
  706.     MOV    C,A    ;SAVE CKSUM
  707. ;
  708.     IF    NOT DCH
  709. SENDW    IN    MODCTLP    ;GET STATUS
  710.     ENDIF
  711. ;
  712.     IF    DCH
  713. SENDW    IN    MODCTL2    ;GET STATUS
  714.     ENDIF
  715. ;
  716.     ANI    MODSNDB    ;ISOLATE READY BIT
  717.     CPI    MODSNDR    ;READY?
  718.     JNZ    SENDW    ;..NO, WAIT
  719.     POP    PSW    ;GET CHAR
  720.     OUT    MODDATP    ;OUTPUT IT
  721.     RET        ;FROM "SEND"
  722. ;
  723. ;---->    WAITNAK: WAITS FOR INITIAL NAK
  724. ;
  725. ;TO ENSURE NO DATA IS SENT UNTIL THE RECEIVING
  726. ;PROGRAM IS READY, THIS ROUTINE WAITS FOR THE
  727. ;THE FIRST TIMEOUT-NAK FROM THE RECEIVER.
  728. ;(E) CONTAINS THE # OF SECONDS TO WAIT.
  729. ;
  730. WAITNAK    MVI    B,1    ;TIMEOUT DELAY
  731.     CALL    RECV    ;DID WE GET..
  732.     CPI    NAK    ;..A NAK?
  733.     RZ        ;YES, SEND BLOCK
  734.     DCR    E    ;80 TRIES?
  735.     JZ    ABORT    ;YES, ABORT
  736.     JMP    WAITNAK    ;NO, LOOP
  737. ;
  738. ;---->    MOVEFCB: MOVES FCB(2) TO FCB
  739. ;
  740. ;I ATTEMPTED TO MAKE THE MODEM COMMAND 'NATURAL',
  741. ;I.E. MODEM SEND FILENAME (MODEM S FN.FT) RATHER
  742. ;THAN MODEM FILENAME SEND (MODEM FN.FT S) SO THIS
  743. ;ROUTINE MOVES THE FILENAME FROM THE SECOND FCB
  744. ;TO THE FIRST
  745. ;
  746. MOVEFCB    LXI    H,FCB+16 ;FROM
  747.     LXI    D,FCB    ;TO
  748.     MVI    B,16    ;LEN
  749.     CALL    MOVE    ;DO THE MOVE
  750.     XRA    A    ;GET 0
  751.     STA    FCBSNO    ;ZERO SECTOR #
  752.     STA    FCBEXT    ;..AND EXTENT
  753.     RET
  754. ;
  755. CTYPE    PUSH    B    ;SAVE..
  756.     PUSH    D    ;..ALL..
  757.     PUSH    H    ;..REGS
  758.     MOV    E,A    ;CHAR TO E
  759.     MVI    C,WRCON    ;GET BDOS FNC
  760.     CALL    BDOS    ;PRIN THE CHR
  761.     POP    H    ;RESTORE..
  762.     POP    D    ;..ALL..
  763.     POP    B    ;..REGS
  764.     RET        ;FROM "CTYPE"
  765. ;
  766. HEXO    PUSH    PSW    ;SAVE FOR RIGHT DIGIT
  767.     RAR        ;RIGHT..
  768.     RAR        ;..JUSTIFY..
  769.     RAR        ;..LEFT..
  770.     RAR        ;..DIGIT..
  771.     CALL    NIBBL    ;PRINT LEFT DIGIT
  772.     POP    PSW    ;RESTORE RIGHT
  773. ;
  774. NIBBL    ANI    0FH    ;ISOLATE DIGIT
  775.     CPI    10    ;IS IS <10?
  776.     JC    ISNUM    ;YES, NOT ALPHA
  777.     ADI    7    ;ADD ALPHA BIAS
  778. ;
  779. ISNUM    ADI    '0'    ;MAKE PRINTABLE
  780.     JMP    CTYPE    ;..THEN TYPE IT
  781. ;
  782. ;---->    ILPRT: INLINE PRINT OF MSG
  783. ;
  784. ;THE CALL TO ILPRT IS FOLLOWED BY A MESSAGE,
  785. ;BINARY 0 AS THE END.
  786. ;
  787. ILPRT    XTHL        ;SAVE HL, GET HL=MSG
  788. ;
  789. ILPLP    MOV    A,M    ;GET CHAR
  790.     ORA    A    ;END OF MSG?
  791.     JZ    ILPRET    ;..YES, RETURN
  792.     CALL    CTYPE    ;TYPE THE MSG
  793.     INX    H    ;TO NEXT CHAR
  794.     JMP    ILPLP    ;LOOP
  795. ;
  796. ILPRET    XTHL        ;RESTORE HL
  797.     RET        ;PAST MSG
  798. ;
  799. ;---->    ERXIT: EXIT PRINTING MSG FOLLOWING CALL
  800. ;
  801. ERXIT    POP    D    ;GET MESSAGE
  802.     MVI    C,PRINT    ;GET BDOS FNC
  803.     CALL    BDOS    ;PRINT MESSAGE
  804. ;
  805. EXIT    LHLD    STACK    ;GET ORIGINAL STACK
  806.     SPHL        ;RESTORE IT
  807.     RET        ;--EXIT-- TO CP/M
  808. ;
  809. ;MOVE 128 CHARACTERS
  810. ;
  811. MOVE128    MVI    B,128    ;SET MOVE COUNT
  812. ;
  813. ;MOVE FROM (HL) TO (DE) LENGTH IN (B)
  814. ;
  815. MOVE    MOV    A,M    ;GET A CHAR
  816.     STAX    D    ;STORE IT
  817.     INX    H    ;TO NEXT "FROM"
  818.     INX    D    ;TO NEXT "TO"
  819.     DCR    B    ;MORE?
  820.     JNZ    MOVE    ;..YES, LOOP
  821.     RET        ;..NO, RETURN
  822. ;
  823. ;TEMPORARY STORAGE AREA
  824. ;
  825. RCVSNO    DB    0    ;SECT # RECEIVED
  826. SECTNO    DB    0    ;CURRENT SECTOR NUMBER 
  827. ERRCT    DB    0    ;ERROR COUNT
  828. ;FOLLOWING 3 USED BY DISK BUFFERING ROUTINES
  829. EOFLG    DB    0    ;EOF FLAG (1=TRUE)
  830. SECPTR    DW    DBUF
  831. SECINBF    DB    0    ;# OF SECTORS IN BUFFER
  832.     DS    60    ;STACK AREA
  833. STACK    DS    2    ;STACK POINTER
  834. ;
  835. ;16 SECTOR DISK BUFFER
  836. ;
  837. DBUF    EQU    $    ;16 SECTOR DISK BUFFER
  838. ;
  839. ; BDOS EQUATES (VERSION 2)
  840. ;
  841. RDCON    EQU    1
  842. WRCON    EQU    2
  843. PRINT    EQU    9
  844. CONST    EQU    11    ;CONSOLE STAT
  845. OPEN    EQU    15    ;0FFH=NOT FOUND
  846. CLOSE    EQU    16    ;    "    "
  847. SRCHF    EQU    17    ;    "    "
  848. SRCHN    EQU    18    ;    "    "
  849. ERASE    EQU    19    ;NO RET CODE
  850. READ    EQU    20    ;0=OK, 1=EOF
  851. WRITE    EQU    21    ;0=OK, 1=ERR, 2=?, 0FFH=NO DIR SPC
  852. MAKE    EQU    22    ;0FFH=BAD
  853. REN    EQU    23    ;0FFH=BAD
  854. STDMA    EQU    26    ;SET DMA
  855. BDOS    EQU    BASE+5
  856. FCB    EQU    BASE+5CH ;SYSTEM FCB
  857. FCBEXT    EQU    FCB+12    ;FILE EXTENT
  858. FCBSNO    EQU    FCB+32    ;SECTOR #
  859. FCB2    EQU    BASE+6CH ;SECOND FCB
  860. ;
  861.     END
  862.  
  863.