home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / SIMTEL / CPMUG / CPMUG084.ARK / XMODEM50.ASM < prev    next >
Assembly Source File  |  1984-04-29  |  50KB  |  2,012 lines

  1. ;
  2. ;    XMODEM.ASM V5.0, by Keith Petersen, W8SDZ
  3. ;           (revised 6/8/82)
  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. ;Updates/fixes (in reverse order to minimize reading time):
  16. ;
  17. ;6/8/82    Added file transfer logging  feature. Enabled  with
  18. ;         the  equate  variable LOGCAL,  it uses  caller 
  19. ;        info   provided  by  the  RCPM  file   LASTCALR 
  20. ;        together with transferred file name,  size  and 
  21. ;        direction of transfer to append each successful 
  22. ;        transfer to new special file LOG.SYS.  The user 
  23. ;        area designation for LASTCALR must be specified 
  24. ;         by the variable LASTUSR and file is expected to 
  25. ;        reside on the DEFDRV drive. The support library 
  26. ;        SEQIO.LIB(vrs >=2.2) and the MAC assembler  are 
  27. ;        needed   ONLY if LOGCAL is true.  If logging is 
  28. ;        not desired,  or you don't have MAC then LOGCAL 
  29. ;        may  be  set false and the ASM  assembler  will 
  30. ;        work.  See  SEQIO.LIB for documentation on  the 
  31. ;        support  code.  Also made mods to  file  length 
  32. ;        printout  to  give  times for  600  baud  (PMMI 
  33. ;        only). This is optional with the LSPEED equate. 
  34. ;        If  used,  the baud rate of caller must be made 
  35. ;        available  thru  location  MSPEED(by  the   BYE 
  36. ;        program).             Jack Riley
  37. ;04/18/82 Corrected transfer time calculations. Added optional
  38. ;      equate, VOUT for sector count display to
  39. ;      console output. (Must be CRT type device)
  40. ;      Changed modem data port equates into 2 distinct
  41. ;      booleans to accomodate a wider variety of customized
  42. ;      EXTMOD equated modems.
  43. ;      Changed NOCOMR option on receive to  automatic
  44. ;      renaming of  .COM extents to .OBJ. (Howard Booker)
  45. ;
  46. ;04/01/82 Added routine to ERASE any file not properly received
  47. ;      (gets rid of all those damn 0K files) - thanks
  48. ;      to Skip Hansen for this one. - BHK
  49. ;
  50. ;03/28/82 Added cancel facility - if first char received 
  51. ;      when waiting for initial nak is control-X it will
  52. ;      cancel sending (useful for when the time estimate
  53. ;      is longer than you want to wait). - BHK
  54. ;
  55. ;03/22/82 Added calculation of estimated transmission time
  56. ;      when sending a file - divide # sectors by ~ 8 sectors
  57. ;      per minute transmission speed (at 300 baud) - BHK
  58. ;
  59. ;03/08/82 Added Bruce Wood's designated user and drive area
  60. ;         routines to the original ver. 46 which contained
  61. ;         the DCH modem updates which were first included
  62. ;         on 10/19/81.  Then renamed to ver. 48A to distinguish
  63. ;         from the first ver. 48.  (Bill Aten)
  64. ;
  65. ;01/06/82 Added code to implement designated user and drive
  66. ;       area to receive files on.  This was put in to
  67. ;      make it easier to locate new programs and for drives
  68. ;      that are write protected. This change will put the file
  69. ;      being sent into the designated area and when done return
  70. ;      to the orginal area.
  71. ;      SEE SETAREA LABEL IN THE CONDITIONAL SECTION  (Bruce Wood)
  72. ;
  73. ;10/19/81 Corrected numerous 'IN MODCTL2' errors for the DC
  74. ;      Hayes modem.  Added DC Hayes detection of framing
  75. ;      errors, overrun errors, and parity errors (if
  76. ;      parity is used) for the receive file routine.
  77. ;      (Bill Aten)
  78. ;
  79. ;10/12/81 Added code to implement Cyclic Redundancy
  80. ;      Checking for both receiving and sending files.
  81. ;      The CRC can only be specified by the operator
  82. ;      on the receive file option as a secondary
  83. ;      option of 'C' (XMODEM RC FN.FT).  When CRC is
  84. ;      in effect, an initial 'C' instead of a NAK will
  85. ;      be sent to the sender to start things off.
  86. ;      The 'C' will be the signal to the sender
  87. ;      (hopefully a version of MODEM that implements
  88. ;      this CRC convention) that CRC is in effect.
  89. ;      CRC will then take the place of the checksum
  90. ;      checking for data validity.  The CRC should
  91. ;      make file transfers as far as data integrity is
  92. ;      concerned better than 99.99% error free.  The
  93. ;      crc macro, CRC120, was used to implement CRC
  94. ;      in this program and its equivalent version of
  95. ;      MODEM.  Acknowledgements and thanks to Paul
  96. ;      Hansknecht who designed and wrote CRC120.
  97. ;
  98. ;07/01/81 REDID H8/H89 EQUATES TESTED PROGRAM USING BOTH
  99. ;      SYSTEMS AND CHANGED VER TO 4.4    (AL OLANDER)
  100. ;
  101. ;06/28/81 INSTALL H8/H89 EQUATES AND CHANGE EXTERNAL
  102. ;      MODEM EQUATES TO "EXTMOD". (L. SHIPINSKI)
  103. ;
  104. ;05/30/81 Added IF PMMI/ENDIF to RCVERR routine to eliminate
  105. ;      'undefined symbol' error when set for DCH modem.
  106. ;      (Dave Hardy)
  107. ;
  108. ;05/07/81 Changed signon revision number.
  109. ;      Cleaned up file. (KBP)
  110. ;
  111. ;05/01/81 Added detection of framing errors, overrun
  112. ;      errors, and parity errors (if parity is used)
  113. ;      for the receive file routine.  This feature
  114. ;      is only active for the PMMI modem, since I
  115. ;      do not know what the modem status bits are
  116. ;      for IDS and D.C. Hayes modems.  If there
  117. ;      is one of the above errors, the line will
  118. ;      be purged for that block and a NAK will be
  119. ;      sent to the sender for that block.  This was
  120. ;      added to help catch those transmission errors
  121. ;      that are not always caught by the checksum.
  122. ;      This error checking is in addition to the
  123. ;      checksum routine. (John Mahr)
  124. ;
  125. ;02/17/81 Added test for "f2" tagged files in OPENOK
  126. ;      for MP/M version 1.1 compatiblity, which
  127. ;      doesn't allow Ctl-C or Ctl-S in "f1" tagged
  128. ;      files. (Tim Nicholas)
  129. ;
  130. ;02/16/81 Added hex to file size display. Now reports
  131. ;      size in both decimal and (xxxxH) hex. Thanks
  132. ;      to Ben Bronson for the idea. (Tim Nicholas)
  133. ;
  134. ;02/15/81 Added a software timer to the carrier test
  135. ;      added in SEND and RECV routines. This will
  136. ;      now abort only if carrier is lost for a 
  137. ;      period of 15 seconds. This is only essential
  138. ;      for those using external modems with certain
  139. ;      SIO's, but will provide the PMMI/DCH user
  140. ;      faster recovery in a lost carrier situation
  141. ;      as well. Approx 15 seconds plus 15 seconds
  142. ;      in BYE.COM, compared to 3 minutes at 300
  143. ;      baud with earlier revisions. Thanks to Ben
  144. ;      Bronson for his aid in developing this
  145. ;      revision. (Tim Nicholas)
  146. ;
  147. ;02/14/81 Corrected error in last update which read
  148. ;      the incorrect port for PMMI in the added
  149. ;      carrier test. (Tim Nicholas)
  150. ;    
  151. ;01/31/81 Added equates and code for a carrier test.
  152. ;      Test performed in modem I/O routines. This
  153. ;      is required since loss of carrier will go
  154. ;      undetected by BYE.COM, if the loss occurs
  155. ;      after a sucessful XMODEM signon, when using
  156. ;      an external modem and SIO. (Tim Nicholas)
  157. ;
  158. ;01/17/81 Re-wrote routine to calculate file size so
  159. ;         that it works correctly on v2.X systems with
  160. ;         extent folding (non-zero extent mask). (BRR)
  161. ;
  162. ;12/06/80 Re-wrote routine to calculate file size,
  163. ;      added decimal print of file size. (KBP)
  164. ;
  165. ;12/05/80 Corrected error in use of ext byte that pre-
  166. ;      vented files greater than one extent from 
  167. ;      being sent.     Ron Fowler
  168. ;
  169. ;12/03/80 Corrected file extent length display. Now
  170. ;      reports correct number of records for files
  171. ;      longer than one extent. Display is now
  172. ;      double precision (xxxxH). Also made some
  173. ;      cosmetic changes by re-arranging the equates.
  174. ;      By Tim Nicholas
  175. ;
  176. ;10/28/80 Cleaned up file. (KBP)
  177. ;
  178. ;10/23/80 Expanded conditional assembly of NOCOM routines
  179. ;      into NOCOMS, NOLBS, and NOCOMR equates, to allow
  180. ;      separate conditional assembly of tests for sending
  181. ;      .COM files, sending .??# files, and receiving .COM
  182. ;      files, respectively.    (Dave Hardy)
  183. ;
  184. ;10/15/80 Added traps for ambiguous file name or
  185. ;      none at all. (KBP)
  186. ;
  187. ;09/09/80 Added conditional assembly to prevent filetypes
  188. ;      '.COM' or '.??#' from being sent to distant end
  189. ;      and added conditional assembly of test for '.COM'
  190. ;      filetype on receive as well. See 'NOCOM' below.
  191. ;      Any filetype ending in '#' will not be sent by
  192. ;      this program if 'NOCOM' is set to TRUE.  J.SEYMOUR
  193. ;
  194. ;NOTE: If you add improvements or otherwise update
  195. ;this program, please modem a copy of the new file
  196. ;to "TECHNICAL CBBS" in Dearborn, Michigan - phone
  197. ;313-846-6127 (110, 300, 450 or 600 baud).  Use the
  198. ;filename XMODEM.NEW.    (KBP)
  199. ;
  200. FALSE    EQU    0
  201. TRUE    EQU    NOT FALSE
  202. ;
  203. ;-----------------------------------------------------
  204. ;     --- Conditional Assembly Options ---          ;
  205. ;------------------------------------------------------
  206. ;
  207. STDCPM    EQU    TRUE    ;TRUE, IS STANDARD CP/M
  208. ALTCPM    EQU    FALSE    ;TRUE, IS TRS-80 OR H8 W/O 0-ORG
  209. ;
  210. PMMI    EQU    TRUE    ;TRUE, IS PMMI
  211. DCH    EQU    FALSE    ;TRUE, IS D.C. HAYES
  212. H8    EQU    FALSE    ;TRUE, IS H8/H89 W/INS8250 MODEM CHIP
  213. EXTMOD    EQU    FALSE    ;TRUE, IS NONE OF THE ABOVE!
  214. ;
  215. NOCOMS    EQU    TRUE    ;TRUE, NO .COM FILES SENT
  216. NOLBS    EQU    TRUE    ;TRUE, NO .??# FILES SENT
  217. NOCOMR    EQU    TRUE    ;TRUE, CHANGE.COM TO.OBJ ON RECEIVE
  218. ;
  219. FASTCLK EQU    TRUE    ;PUT TRUE HERE FOR 4 MHZ CLOCK
  220. ;
  221. FRNTPNL    EQU    FALSE    ;TO DISPLAY STATUS ON FRONT PANEL
  222. PANEL    EQU    0FFH    ;DEFAULT ADDRESS OF FRONT PANEL
  223. ;
  224. SETAREA    EQU    TRUE    ;TRUE, IF USING DESIGNATED AREA TO RECEIVE 
  225. RECU    EQU    0    ;USER AREA TO REC IN (NOT GREATER THAN 9)
  226. DEFDRV    EQU    'A'    ;DRIVE TO REC TO
  227. ;
  228. ;    FILE TRANSFER LOGGING OPTIONS    (J. Riley)
  229. LOGCAL    EQU    true     ;IF USING LOGGING OF XMODEM TRANSFERS
  230. LASTUSR    EQU    15    ;USER AREA OF 'LASTCALR' FILE (IF 'LOGCAL' ONLY)
  231. ;
  232. LSPEED    EQU    true     ;REPORT DIFFERENCES IN BAUD RATES IN PRINTOUT
  233. MSPEED    EQU    3EH    ;LOCATION OF CURRENT BAUD RATE FACTOR(set by BYE)
  234. ;
  235. VOUT    EQU    00000H    ;ADR OF VIDEO DRIVER IF OPTIONAL SECTOR
  236.             ;COUNT TO CONSOLE, ELSE LEAVE AS 0000H
  237. ;
  238. ;
  239. ;------------------------------------------------------
  240. ;         --- Modem Port Equates ---           ;
  241. ;------------------------------------------------------
  242. ;
  243.     IF    PMMI
  244. MODCTLP EQU    0C0H    ;PMMI VALUES(base port addr)
  245. MODSNDB EQU    1    ;BIT TO TEST FOR SEND
  246. MODSNDR EQU    1    ;VALUE WHEN READY
  247. MODRCVB EQU    2    ;BIT TO TEST FOR RECEIVE
  248. MODRCVR EQU    2    ;VALUE WHEN READY
  249. MODDCDB    EQU    4    ;CARRIER DETECT BIT
  250. MODDCDA    EQU    0    ;VALUE WHEN ACTIVE
  251. MODPARE    EQU    08H    ;VALUE FOR PARITY ERROR
  252. MODOVRE    EQU    10H    ;VALUE FOR OVERRUN ERROR
  253. MODFRME    EQU    20H    ;VALUE FOR FRAMING ERROR
  254. MODDATP EQU    MODCTLP+1;DATA PORT, RECEIVE
  255. MODDATO    EQU    MODCTLP+1;DATA PORT, SEND
  256. BAUDRP    EQU    MODCTLP+2;BAUD RATE OUTPUT/MODEM STATUS
  257. B600    EQU    1AH    ;FACTOR FOR B600 BAUD
  258. MODCTL2 EQU    MODCTLP+3;SECOND CTL PORT
  259.     ENDIF
  260. ;
  261.     IF    H8
  262. MODCTLP    EQU    0DDH    ;H8/H89 VALUES (LSR-LINE STATUS REG.)
  263. MODSNDB    EQU    20H    ;TEST FOR SEND (LSR-THRE)
  264. MODSNDR    EQU    20H    ;VALUE WHEN READY
  265. MODRCVB    EQU    01H    ;TEST FOR RECIEVE (LSR-DR)
  266. MODRCVR    EQU    01H    ;VALUE WHEN READY
  267. MODDCDB    EQU    20H    ;CARRIER DETECT BIT (MSR-CTS)
  268. MODDCDA    EQU    20H    ;VALUE WHEN ACTIVE
  269. MODPARE    EQU    04H    ;VALUE FOR PARITY ERROR (LSR-PE)
  270. MODOVRE    EQU    02H    ;VALUE FOR OVERRUN ERROR (LSR-OR)
  271. MODFRME    EQU    08H    ;VALUE FOR FRAMING ERROE (LSR-FE)
  272. MODDATP    EQU    0D8H    ;DATA PORT, RECIEVE
  273. MODDATO    EQU    0D8H    ;DATA PORT, SEND
  274. BAUDRP    EQU    0DDH    ;BAUD RATE PORT (DALB IN LCR MUST=1)
  275. MODCTL2    EQU    0DEH    ;MODEM STATUS REGISTER (MSR)
  276. MODCTL1    EQU    0DBH    ;LINE CONTROL REGISTER (LCR)
  277.     ENDIF
  278. ;
  279.     IF    DCH
  280. MODCTLP EQU    82H    ;D. C. HAYES VALUES
  281. MODSNDB EQU    2    ;BIT TO TEST FOR SEND
  282. MODSNDR EQU    2    ;VALUE WHEN READY
  283. MODRCVB EQU    1    ;BIT TO TEST FOR RECEIVE
  284. MODRCVR EQU    1    ;VALUE WHEN READY
  285. MODDCDB    EQU    40H    ;CARRIER DETECT BIT
  286. MODDCDA    EQU    40H    ;VALUE WHEN ACTIVE
  287. MODPARE    EQU    04H    ;VALUE FOR PARITY ERROR
  288. MODOVRE    EQU    10H    ;VALUE FOR OVERRUN ERROR
  289. MODFRME    EQU    08H    ;VALUE FOR FRAMING ERROR
  290. MODDATP EQU    80H    ;DATA PORT IN PORT
  291. MODDATO    EQU    80H    ;DATA OUT PORT
  292. MODCTL2 EQU    81H    ;SECOND CTL PORT
  293.     ENDIF
  294. ;
  295. ;If you are using an external modem (not S-100 plug-in)
  296. ;change these equates for your modem port requirements
  297. ;
  298.     IF    EXTMOD
  299. MODCTLP EQU    0C3H    ;PUT YOUR MODEM STATUS PORT HERE
  300. MODSNDB EQU    10H    ;YOUR BIT TO TEST FOR SEND
  301. MODSNDR EQU    10H    ;YOUR VALUE WHEN READY
  302. MODRCVB EQU    01H    ;YOUR BIT TO TEST FOR RECEIVE
  303. MODRCVR EQU    01H    ;YOUR VALUE WHEN READY
  304. MODDCDB    EQU    02H    ;CARRIER DETECT BIT
  305. MODDCDA    EQU    02H    ;VALUE WHEN ACTIVE
  306. MODDATP EQU    0C0H    ;YOUR MODEM DATA IN PORT
  307. MODDATO    EQU    0C2H    ;YOUR MODEM DATA OUT PORT
  308. MODCTL2    EQU    0C1H    ;SECOND CONTROL/STATUS PORT.
  309.     ENDIF        ;END OF EXTERNAL MODEM EQUATES
  310. ;
  311. ;        --- End of Options ---
  312. ;------------------------------------------------------
  313. ;
  314. ERRLIM    EQU    10    ;MAX ALLOWABLE ERRORS (10 STANDARD)
  315. ;
  316. ;Define ASCII characters used
  317. ;
  318. SOH    EQU    1    ;START OF HEADER
  319. EOT    EQU    4    ;END OF TRANSMISSION
  320. ACK    EQU    6    ;ACKNOWLEDGE
  321. NAK    EQU    15H    ;NEG ACKNOWLEDGE
  322. CRC    EQU    'C'    ;CRC REQUEST CHARACTER
  323. CAN    EQU    18H    ;CONTROL-X FOR CANCEL
  324. LF    EQU    10    ;LINEFEED
  325. CR    EQU    13    ;CARRIAGE RETURN
  326.     IF    STDCPM
  327. BASE    EQU    0    ;CP/M BASE ADDRESS
  328.     ENDIF
  329. ;
  330.     IF    ALTCPM
  331. BASE    EQU    4200H    ;ALTERNATE CP/M BASE ADDRESS
  332.     ENDIF
  333. ;
  334.     ORG    BASE+100H
  335. ;
  336. ;
  337. ;Init private stack
  338. BEGIN    LXI    H,0    ;HL=0
  339.     DAD    SP    ;HL=STACK FROM CP/M
  340.     SHLD    STACK    ;..SAVE IT
  341.     LXI    SP,STACK ;SP=MY STACK
  342. ;
  343.     if    setarea
  344.     mvi    e,0ffh        ;get the current user area     a 01/06/82
  345.     mvi    c,user                        ;a 01/06/82
  346.     call    bdos                        ;a 01/06/82
  347.     sta    olduser        ;save user number here         a 01/06/82
  348.     mvi    c,curdrv    ;get the current drive         a 01/06/82
  349.     call    bdos                        ;a 01/06/82
  350.     sta    olddrv        ;save drive here         a 01/06/82
  351.     endif
  352. ;
  353.     CALL    ILPRT    ;PRINT:
  354.     DB    CR,LF
  355.     DB    'XMODEM ver 5.0V [CRC capable]',CR,LF,0
  356. ;
  357. ;GET OPTION
  358. ;
  359.     LDA    FCB+2    ;SECONDARY OPTION?
  360.     CPI    'C'    ;CRC CHECKING REQUESTED?
  361.     JNZ    CHKOPTN    ;NO, GO CHECK PRIMARY
  362.     LDA    FCB+1    ;GET PRIMARY OPTION
  363.     CPI    'R'    ;CRC VALID ONLY FOR RECEIVE
  364.     JNZ    OPTNERR    ;PRT MSG, ABORT
  365.     XRA    A    ;ZERO ACCUM
  366.     STA    CRCFLG    ;TURN ON CRC FLAG
  367. ;
  368. CHKOPTN    LDA    FCB+1    ;GET OPTION (S or R)
  369.     PUSH    PSW    ;SAVE OPTION
  370. ;
  371. ;Move the filename from FCB2 to FCB1
  372. ;
  373.     CALL    MOVEFCB
  374. ;
  375. ;Gobble up garbage chars from the line
  376. ;prior to receive or send
  377. ;
  378.     IN    MODDATP
  379.     IN    MODDATP
  380. ;
  381. ;Jump to appropriate function
  382. ;
  383.     POP    PSW    ;GET OPTION
  384.     IF    LOGCAL
  385.     PUSH    PSW    ;BUT SAVE IT
  386.     ENDIF
  387. ;
  388.     CPI    'S'    ;SEND..
  389.     JZ    SENDFIL ;..A FILE?
  390. ;
  391.     CPI    'R'    ;RECEIVE..
  392.     JZ    RCVFIL    ;..A FILE?
  393. ;
  394. ;Invalid option
  395. ;
  396. OPTNERR    CALL    ERXIT    ;EXIT W/ERROR
  397.     DB    '++INVALID OPTION ON XMODEM '
  398.     DB    'COMMAND++',CR,LF
  399.     DB    'Must be S for SEND; R or RC '
  400.     DB    'for RECEIVE',CR,LF,'$'
  401.  
  402.     IF    LOGCAL
  403.     MACLIB SEQIO22
  404.  
  405. BSIZE    EQU    80H
  406. FILERR    SET    EXIT
  407. BUFFERS    SET    DBUF
  408.  
  409. ;        THE FOLLOWING ALLOCATIONS ARE USED BY THE 'FILE' MACROS
  410. DEFAULT$USER:
  411.     DB    LASTUSR
  412. CUR$USER:
  413.     DB    0FFH
  414. DEFAULT$DISK:
  415.     DB    DEFDRV-'A'
  416. CUR$DISK:
  417.     DB    0FFH
  418. PGSIZE:    DW    0
  419.  
  420. LOGCALL    FILE    INFILE,CALLER,,LASTCALR,,BSIZE,,PUBLIC,TRUE
  421.     MVI    A,RECU
  422.     STA    DEFAULT$USER
  423.     FILE    APPEND,LOG,,LOG,SYS,BSIZE,,PUBLIC,TRUE
  424.  
  425.     POP    PSW    ; GET OPTION
  426.     PUT    LOG    ; PUT IT OUT TO LOG
  427.  
  428.     LDA    MSPEED    ; GET SPEED FACTOR
  429.     CMA
  430.     ADI    7EH    ; MAGIC NUMBER FOR PMMI MODEM SO WE CAN
  431.     PUT    LOG    ; PUT OUT A SINGLE LETTER CODE
  432.     LDA    PGSIZE    ; NOW THE PROGRAM SIZE(IN MINUTES TRANSFER TIME)
  433.     CALL    PNDEC
  434.     MVI    A,' '    ; BLANK
  435.     PUT    LOG
  436.  
  437. ;            LOG THE DRIVE AND USER AREA AS A PROMPT
  438.     LDA    FCB
  439.     ORA    A
  440.     JNZ    WDRV
  441.     MVI    C,25
  442.     CALL    @BDOS
  443.     INR    A
  444. WDRV:    ADI    'A'-1
  445.     PUT    LOG
  446.  
  447.     MVI    C,32        ; NOW THE USER AREA(AS DECIMAL NUMBER)
  448.     MVI    E,0FFH
  449.     CALL    @BDOS
  450.     CALL    PNDEC
  451.     MVI    A,'>'        ; MAKE IT LOOK LIKE A PROMPT
  452.     PUT    LOG
  453.  
  454.     LXI    H,FCB+1        ; NOW THE NAME OF THE FILE
  455.     MVI    B,11
  456.     CALL    PUTSTR
  457.  
  458.     MVI    A,' '        ; BLANK
  459.     PUT    LOG
  460.  
  461. CLOOP:    GET    CALLER        ; AND THE CALLER
  462.     CPI    EOF
  463.     JZ    QUIT
  464.     PUT    LOG
  465.     JMP    CLOOP
  466.  
  467. PNDEC:    CPI    10        ; TWO COLUMN DECIMAL FORMAT ROUTINE
  468.     JC    ONE        ; ONE OR TWO DIGITS TO AREA #?
  469.     JMP    TWO
  470. ONE:    PUSH    PSW
  471.     MVI    A,'0'
  472.     PUT    LOG
  473.     POP    PSW
  474. TWO:    MVI    H,0
  475.     MOV    L,A
  476.     CALL    DECOT
  477.     RET
  478.  
  479. DECOT:    PUSH    B
  480.     PUSH    D
  481.     PUSH    H
  482.     LXI    B,-10
  483.     LXI    D,-1
  484. ;
  485. DECOT2:    DAD    B
  486.     INX    D
  487.     JC    DECOT2
  488.     LXI    B,10
  489.     DAD    B
  490.     XCHG
  491.     MOV    A,H
  492.     ORA    L
  493.     CNZ    DECOT
  494.     MOV    A,E
  495.     ADI    '0'
  496.     PUT    LOG
  497.     POP    H
  498.     POP    D
  499.     POP    B
  500.     RET
  501.  
  502. PUTSTR:    MOV    A,M
  503.     PUSH    H
  504.     PUSH    B
  505.     PUT    LOG
  506.     POP    B
  507.     POP    H
  508.     INX    H
  509.     DCR    B
  510.     JNZ    PUTSTR
  511.     RET
  512.  
  513. QUIT:    FINIS    LOG
  514.     JMP    EXIT
  515.     ENDIF        ; LOGCAL
  516. ;
  517. * * * * * * * * * * * * * * * * * * * * *
  518. *                    *
  519. *    SENDFIL: SENDS A CP/M FILE    *
  520. *                    *
  521. * * * * * * * * * * * * * * * * * * * * *
  522. ;
  523. ;The CP/M file specified in the XMODEM command
  524. ;is transferred over the phone to another
  525. ;computer running MODEM with the "R" (receive)
  526. ;option.  The data is sent one sector at a
  527. ;time with headers and checksums, and re-
  528. ;transmission on errors.  
  529. ;
  530. SENDFIL CALL    TRAP    ;CHECK FOR NO NAME OR AMBIG. NAME
  531.     CALL    CNREC    ;COMPUTE # OF RECORDS.
  532.     CALL    OPENFIL ;OPEN THE FILE
  533.     MVI    E,80    ;WAIT 80 SEC..
  534.     CALL    WAITNAK ;..FOR INITIAL NAK
  535. ;
  536. SENDLP    CALL    RDSECT    ;READ A SECTOR
  537.     JC    SENDEOF ;SEND EOF IF DONE
  538.     CALL    INCRSNO ;BUMP SECTOR #
  539.     XRA    A    ;ZERO ERROR..
  540.     STA    ERRCT    ;..COUNT
  541. ;
  542. SENDRPT CALL    SENDHDR ;SEND A HEADER
  543.     CALL    SENDSEC ;SEND DATA SECTOR
  544.     LDA    CRCFLG    ;GET CRC FLAG
  545.     ORA    A    ;CRC IN EFFECT?
  546.     CZ    SENDCRC    ;YES, SEND CRC
  547.     CNZ    SENDCKS ;NO, SEND CKSUM
  548.     CALL    GETACK    ;GET THE ACK
  549.     JC    SENDRPT ;REPEAT IF NO ACK
  550.     JMP    SENDLP    ;LOOP UNTIL EOF
  551. ;
  552. ;File sent, send EOT's
  553. ;
  554. SENDEOF MVI    A,EOT    ;SEND..
  555.     CALL    SEND    ;..AN EOT
  556.     CALL    GETACK    ;GET THE ACK
  557.     JC    SENDEOF ;LOOP IF NO ACK
  558.     JMP    EXITLG    ;ALL DONE
  559. ;
  560. * * * * * * * * * * * * * * * * * * * * *
  561. *                    *
  562. *    RCVFIL: RECEIVE A FILE        *
  563. *                    *
  564. * * * * * * * * * * * * * * * * * * * * *
  565. ;
  566. ;Receives a file in block format as sent
  567. ;by another person doing "MODEM S FN.FT".
  568. ;Can be invoked by 'XMODEM R FN.FT' or
  569. ;by 'XMODEM RC FN.FT' if CRC is to be used.
  570. ;
  571. RCVFIL    CALL    TRAP    ;CHECK FOR NO NAME OR AMBIG. NAME
  572. ;
  573.     IF    NOCOMR
  574.     LXI    H,FCB+9 ;POINT TO FILETYPE
  575.     MVI    A,'C'    ;1ST LETTER
  576.     CMP    M    ;IS IT C ?
  577.     JNZ    CONTINU ;IF NOT, CONTINUE NORMALLY
  578.     INX    H    ;GET 2ND LETTER
  579.     MVI    A,'O'    ;2ND LETTER
  580.     CMP    M    ;IS IT O ?
  581.     JNZ    CONTINU ;IF NOT, CONTINUE NORMALLY
  582.     INX    H    ;GET 3RD LETTER
  583.     MVI    A,'M'    ;3RD LETTER
  584.     CMP    M    ;IS IT M ?
  585.     JNZ    CONTINU ;IF NOT, CONTINUE NORMALLY
  586.  
  587.     CALL    ILPRT    ; PRINT RENAMING MESSAGE
  588.     DB    'Auto Renaming Filetype To ".OBJ" '
  589.     DB    CR,LF,CR,LF,0
  590. ;
  591.     LXI    H,OBJEXT
  592.     LXI    D,FCB+9
  593.     MVI    B,3
  594. ALTEXT    MOV    A,M
  595.     STAX    D
  596.     INX    H
  597.     INX    D
  598.     DCR    B
  599.     JNZ    ALTEXT
  600.     JMP    CONTINU
  601.  
  602. OBJEXT    DB    'OBJ'
  603.     ENDIF
  604. ;
  605. CONTINU CALL    CHEKFIL ;SEE IF FILE EXISTS
  606.     CALL    MAKEFIL ;..THEN MAKE NEW
  607.     CALL    ILPRT    ;PRINT:
  608. ;
  609.     if    setarea
  610.     db    'NOTE: File Will Be Received On',cr,lf    ;         a 01/06/81
  611.     db    'Drive ',defdrv,' User ',recu+30H,cr,lf    ; tell this .a 01/06/81
  612.     endif
  613. ;
  614.     DB    'FILE OPEN - READY TO RECEIVE',CR,LF,0
  615. ;
  616. RCVLP    CALL    RCVSECT ;GET A SECTOR
  617.     JC    RCVEOT    ;GOT EOT
  618.     CALL    WRSECT    ;WRITE THE SECTOR
  619.     CALL    INCRSNO ;BUMP SECTOR #
  620.     CALL    SENDACK ;ACK THE SECTOR
  621.     JMP    RCVLP    ;LOOP UNTIL EOF
  622. ;
  623. ;Got EOT on sector - flush buffers, end
  624. ;
  625. RCVEOT    CALL    WRBLOCK ;WRITE THE LAST BLOCK
  626.     CALL    SENDACK ;ACK THE SECTOR
  627.     CALL    CLOSFIL ;CLOSE THE FILE
  628.     JMP    EXITLG    ;ALL DONE
  629. ;
  630. * * * * * * * * * * * * * * * * * * * * *
  631. *                    *
  632. *        SUBROUTINES        *
  633. *                    *
  634. * * * * * * * * * * * * * * * * * * * * *
  635. ;
  636. ;---->    TRAP: Check for no file name or ambiguous name
  637. ;
  638. TRAP    LXI    H,FCB+1 ;POINT TO FILE NAME
  639.     MOV    A,M    ;GET FIRST CHAR OF FILE NAME
  640.     CPI    ' '    ;ANY THERE?
  641.     JNZ    ATRAP    ;YES, CHECK FOR AMBIGOUS FILE NAME
  642.     CALL    ERXIT    ;PRINT MSG, EXIT
  643.     DB    '++NO FILE NAME SPECIFIED++',CR,LF,'$'
  644. ;
  645. ATRAP    MVI    B,11    ;11 CHARS TO CHECK
  646. ;
  647. TRLOOP    MOV    A,M    ;GET CHAR FROM FCB
  648.     CPI    '?'    ;AMBIGUOUS?
  649.     JZ    TRERR    ;YES, EXIT WITH ERROR MSG
  650.     INX    H    ;POINT TO NEXT CHAR
  651.     DCR    B    ;ONE LESS TO GO
  652.     JNZ    TRLOOP    ;NOT DONE, CHECK SOME MORE
  653.     RET        ;NO AMBIGUOUS NAME, RETURN
  654. ;
  655. TRERR    CALL    ERXIT    ;PRINT MSG, EXIT
  656.     DB    '++CAN''T USE WILD CARD OPTIONS++',CR,LF,'$'
  657. ;
  658. ;---->    RCVSECT: Receive a sector
  659. ;
  660. ;Returns with carry set if EOT received.
  661. ;
  662. RCVSECT XRA    A    ;GET 0
  663.     STA    ERRCT    ;INIT ERROR COUNT
  664. ;
  665. RCVRPT:
  666.     IF    PMMI OR H8 OR DCH
  667.     XRA    A    ;GET 0
  668.     STA    ERRCDE    ;CLEAR RECEIVE ERROR CODE
  669.     ENDIF
  670. ;
  671.     MVI    B,10    ;10 SEC TIMEOUT
  672.     CALL    RECV    ;GET SOH/EOT
  673.     JC    RCVSTOT ;TIMEOUT
  674. ;
  675.     IF    PMMI OR H8 OR DCH
  676.     CALL    RCVERR    ;TRANS ERROR?
  677.     JC    RCVSERR    ;CARRY SET IF ERROR
  678.     ENDIF
  679. ;
  680.     CPI    SOH    ;GET SOH?
  681.     JZ    RCVSOH    ;..YES
  682. ;
  683. ;Earlier versions of MODEM program send some nulls -
  684. ;ignore them
  685. ;
  686.     ORA    A    ;00 FROM SPEED CHECK?
  687.     JZ    RCVRPT    ;YES, IGNORE IT
  688.     CPI    EOT    ;END OF TRANSFER?
  689.     STC        ;RETURN WITH CARRY..
  690.     RZ        ;..SET IF EOT
  691. ;
  692. ;Didn't get SOH or EOT - 
  693. ;    -or-
  694. ;Didn't get valid header - purge the line,
  695. ;then send NAK.
  696. ;
  697. RCVSERR MVI    B,1    ;WAIT FOR 1 SEC..
  698.     CALL    RECV    ;..WITH NO CHARS
  699.     JNC    RCVSERR ;LOOP UNTIL SENDER DONE
  700.     LDA    CRCFLG    ;GET CRC FLAG
  701.     ORA    A    ;CRC IN EFFECT?
  702.     MVI    A,NAK    ;PUT NAK IN ACCUM
  703.     JNZ    RCVSER2    ;NO, SEND THE NAK
  704.     LDA    FIRSTIME;GET FIRST TIME SWITCH
  705.     ORA    A    ;HAS FIRST SOH BEEN RECEIVED?
  706.     MVI    A,NAK    ;PUT NAK IN ACCUM
  707.     JZ    RCVSER2    ;YES, THEN SEND NAK
  708.     MVI    A,CRC    ;TELL SENDER CRC IS IN EFFECT
  709. ;
  710. RCVSER2    CALL    SEND    ;..THE NAK or CRC request
  711.     LDA    ERRCT    ;ABORT IF..
  712.     INR    A    ;..WE HAVE REACHED..
  713.     STA    ERRCT    ;..THE ERROR..
  714.     CPI    ERRLIM    ;..LIMIT?
  715.     JC    RCVRPT    ;..NO, TRY AGAIN
  716. ;
  717. ;10 errors in a row -
  718. ;
  719. RCVSABT CALL    CLOSFIL ;KEEP WHATEVER WE GOT
  720.     CALL    ILPRT
  721.     DB    '++UNABLE TO RECEIVE BLOCK '
  722.     DB    '- ABORTING++',CR,LF,0
  723.     CALL    DELFILE    ;DELETE RECEIVED FILE            ; v48c smh
  724.     CALL    ILPRT    ;PRINT SECOND HALF OF MESSAGE
  725.     DB    '++INCOMPLETELY RECEIVED FILE '
  726.     DB    'DELETED++',CR,LF,0
  727.     JMP    EXIT    ;GIVE UP
  728. ;
  729. ;---->    DELFILE: Deletes the received file (used if receive aborts)
  730. ;                            ; v48c smh
  731. DELFILE LXI    D,FCB    ;POINT TO FILE            ; (whole routine)
  732.     MVI    C,ERASEF ;GET FUNCTION
  733.     CALL    BDOS    ;DELETE IT
  734.     INR    A    ;DELETE OK?
  735.     RNZ        ;..YES, RETURN
  736.     CALL    ERXIT    ;..NO, ABORT
  737.     DB    '++CAN''T DELETE RECEIVED FILE++',CR,LF,'$',0
  738. ;
  739. ;Timed out on receive
  740. ;
  741. RCVSTOT JMP    RCVSERR ;BUMP ERR CT, ETC.
  742. ;
  743. ;---->RCVERR: Checks to see if framing error, overrun, or
  744. ;        parity error occurred.
  745. ;    1. Error code (ERRCDE) was set in recv routine
  746. ;    2. ERRCDE=0 for no errors, ERRCDE<>0 for errors
  747. ;    3. If there has been an error, this routine sets
  748. ;        the carry bit on.
  749. ;
  750.     IF    PMMI OR H8 OR DCH
  751. RCVERR    PUSH    PSW    ;SAVE CHAR TRANSMITTED
  752.     LDA    ERRCDE    ;GET RECEIVE ERR CODE
  753.     ANA    A    ;IS IT ZERO?
  754.     JZ    RCVERR2    ;YES, NO ERROR
  755.     POP    PSW    ;RESTORE CHAR TRANSMITTED
  756.     STC        ;SET CARRY ON FOR ERROR
  757.     RET
  758. ;
  759. RCVERR2    POP    PSW    ;RESTORE CHAR TRANSMITTED
  760.     ORA    A    ;CLEAR CARRY BIT
  761.     RET
  762.     ENDIF
  763. ;
  764. ;Got SOH - get block #, block # complemented
  765. ;
  766. RCVSOH    XRA    A    ;ZERO ACCUM
  767.     STA    FIRSTIME;INDICATE FIRST SOH RECV'D
  768.     MVI    B,1    ;TIMEOUT = 1 SEC
  769.     CALL    RECV    ;GET SECTOR
  770.     JC    RCVSTOT ;GOT TIMEOUT
  771. ;
  772.     IF    PMMI OR H8 OR DCH
  773.     CALL    RCVERR    ;TRANS ERROR?
  774.     JC    RCVSERR    ;CARRY SET IF ERROR
  775.     ENDIF
  776. ;
  777.     MOV    D,A    ;D=BLK #
  778.     MVI    B,1    ;TIMEOUT = 1 SEC
  779.     CALL    RECV    ;GET CMA'D SECT #
  780.     JC    RCVSTOT ;TIMEOUT
  781. ;
  782.     IF    PMMI OR H8 OR DCH
  783.     CALL    RCVERR    ;TRANS ERROR?
  784.     JC    RCVSERR    ;CARRY SET IF ERROR
  785.     ENDIF
  786. ;
  787.     CMA        ;CALC COMPLEMENT
  788.     CMP    D    ;GOOD SECTOR #?
  789.     JZ    RCVDATA ;YES, GET DATA
  790. ;
  791. ;Got bad sector #
  792. ;
  793.     JMP    RCVSERR ;BUMP ERROR CT.
  794. ;
  795. RCVDATA MOV    A,D    ;GET SECTOR #
  796.     STA    RCVSNO    ;SAVE IT
  797.     MVI    C,0    ;INIT CKSUM
  798.     CALL    CLRCRC    ;CLEAR CRC COUNTER
  799.     LXI    H,BASE+80H ;POINT TO BUFFER
  800. ;
  801. RCVCHR    MVI    B,1    ;1 SEC TIMEOUT
  802.     CALL    RECV    ;GET CHAR
  803.     JC    RCVSTOT ;TIMEOUT
  804. ;
  805.     IF    PMMI OR H8 OR DCH
  806.     CALL    RCVERR    ;TRANS ERROR?
  807.     JC    RCVSERR    ;CARRY SET IF ERROR
  808.     ENDIF
  809. ;
  810.     MOV    M,A    ;STORE CHAR
  811.     INR    L    ;DONE?
  812.     JNZ    RCVCHR    ;NO, LOOP
  813.     LDA     CRCFLG    ;GET CRC FLAG
  814.     ORA    A    ;CRC IN EFFECT?
  815.     JZ    RCVCRC    ;YES, TO RECEIVE CRC
  816. ;
  817. ;Verify checksum
  818. ;
  819.     MOV    D,C    ;SAVE CHECKSUM
  820.     MVI    B,1    ;TIMEOUT LEN.
  821.     CALL    RECV    ;GET CHECKSUM
  822.     JC    RCVSTOT ;TIMEOUT
  823. ;
  824.     IF    PMMI OR H8 OR DCH
  825.     CALL    RCVERR    ;TRANS ERROR?
  826.     JC    RCVSERR    ;CARRY SET IF ERROR
  827.     ENDIF
  828. ;
  829.     CMP    D    ;CHECKSUM OK?
  830.     JNZ    RCVSERR ;NO, ERROR
  831. ;
  832. ;Got a sector, it's a duplicate if = previous,
  833. ;    or OK if = 1 + previous sector
  834. ;
  835. CHKSNUM    LDA    RCVSNO    ;GET RECEIVED
  836.     MOV    B,A    ;SAVE IT
  837.     LDA    SECTNO    ;GET PREV
  838.     CMP    B    ;PREV REPEATED?
  839.     JZ    RECVACK ;ACK TO CATCH UP
  840.     INR    A    ;CALC NEXT SECTOR #
  841.     CMP    B    ;MATCH?
  842.     JNZ    ABORT    ;NO MATCH - STOP SENDER, EXIT
  843.     RET        ;CARRY OFF - NO ERRORS
  844. ;
  845. ;---->    RCVCRC:    Receive the cyclic redundancy check
  846. ;        characters (2 bytes), and see if the crc
  847. ;        received matches the one calculated.
  848. ;        If they match, get next sector, else
  849. ;        send a NAK requesting the sector be
  850. ;        resent.
  851. ;
  852. RCVCRC    MVI    E,2    ;NUMBER OF BYTES TO RECEIVE
  853. ;
  854. RCVCRC2    MVI    B,1    ;1 SEC TIMEOUT
  855.     CALL    RECV    ;GET CRC BYTE
  856.     JC    RCVSTOT    ;TIMEOUT
  857. ;
  858.     IF    PMMI OR H8 OR DCH
  859.     CALL    RCVERR    ;TRANSMISSION ERROR?
  860.     JC    RCVSERR    ;YES, IF CARRY IS ON
  861.     ENDIF
  862. ;
  863.     DCR    E    ;DECREMENT NUM OF BYTES
  864.     JNZ    RCVCRC2    ;GET BOTH BYTES
  865.     CALL    CHKCRC    ;CHECK RCVD CRC AGAINST CALC'D CRC
  866.     ORA    A    ;IS CRC OKAY?
  867.     JZ    CHKSNUM    ;YES, GO CHECK SECTOR NUMBERS
  868.     JMP    RCVSERR    ;GO CHECK ERROR LIMIT AND SEND NAK
  869. ;
  870. ;Previous sector repeated, due to the last ACK
  871. ;being garbaged.  ACK it so sender will catch up 
  872. ;
  873. RECVACK CALL    SENDACK ;SEND THE ACK,
  874.     JMP    RCVSECT ;GET NEXT BLOCK
  875. ;
  876. ;Send an ACK for the sector
  877. ;
  878. SENDACK MVI    A,ACK    ;GET ACK
  879.     CALL    SEND    ;..AND SEND IT
  880.     RET
  881. ;
  882. ;---->    SENDHDR: Send the sector header
  883. ;
  884. ;SEND: (SOH) (block #) (complemented block #)
  885. ;
  886. SENDHDR MVI    A,SOH    ;SEND..
  887.     CALL    SEND    ;..SOH,
  888.     LDA    SECTNO    ;THEN SEND..
  889.     CALL    SEND    ;..SECTOR #
  890.     LDA    SECTNO    ;THEN SECTOR #
  891.     CMA        ;..COMPLEMENTED..
  892.     CALL    SEND    ;..SECTOR #
  893.     RET        ;FROM SENDHDR
  894. ;
  895. ;---->    SENDSEC: Send the data sector
  896. ;
  897. SENDSEC MVI    C,0    ;INIT CKSUM
  898.     CALL    CLRCRC    ;CLEAR THE CRC COUNTER
  899.     LXI    H,BASE+80H ;POINT TO BUFFER
  900. ;
  901. SENDC    MOV    A,M    ;GET A CHAR
  902.     CALL    SEND    ;SEND IT
  903.     INR    L    ;POINT TO NEXT CHAR
  904.     JNZ    SENDC    ;LOOP IF <100H
  905.     RET        ;FROM SENDSEC
  906. ;
  907. ;---->    SENDCKS: Send the checksum
  908. ;
  909. SENDCKS MOV    A,C    ;SEND THE..
  910.     CALL    SEND    ;..CHECKSUM
  911.     RET        ;FROM SENDCKS
  912. ;
  913. ;---->    SENDCRC: Send the two Cyclic Redundancy
  914. ;         Check characters.  Call FINCRC
  915. ;         to calc the CRC which will be in
  916. ;         d,e regs upon return.
  917. ;
  918. SENDCRC    CALL    FINCRC    ;CALC THE CRC FOR THIS SECTOR
  919.     MOV    A,D    ;PUT FIRST CRC BYTE IN ACCUM
  920.     CALL    SEND    ;SEND IT
  921.     MOV    A,E    ;PUT SECOND CRC BYTE IN ACCUM
  922.     CALL    SEND    ;SEND IT
  923.     XRA    A    ;SET ZERO RETURN CODE
  924.     RET
  925. ;
  926. ;---->    GETACK: Get the ACK on the sector
  927. ;
  928. ;Returns with carry clear if ACK received.
  929. ;If an ACK is not received, the error count
  930. ;is incremented, and if less than "ERRLIM",
  931. ;carry is set and control returns.  If the
  932. ;error count is at "ERRLIM", the program
  933. ;aborts.
  934. ;
  935. GETACK    MVI    B,10    ;WAIT 10 SECONDS MAX
  936.     CALL    RECVDG    ;RECV W/GARBAGE COLLECT
  937.     JC    GETATOT ;TIMED OUT
  938.     CPI    ACK    ;OK? (CARRY OFF IF =)
  939.     RZ        ;YES, RET FROM GETACK
  940. ;
  941. ;Timeout or error on ACK - bump error count
  942. ;
  943. ACKERR    LDA    ERRCT    ;GET COUNT
  944.     INR    A    ;BUMP IT
  945.     STA    ERRCT    ;SAVE BACK
  946.     CPI    ERRLIM    ;AT LIMIT?
  947.     RC        ;NOT AT LIMIT
  948. ;
  949. ;Reached error limit
  950. ;
  951. CSABORT CALL    ERXIT
  952.     DB    '++CAN''T SEND SECTOR '
  953.     DB    '- ABORTING++',CR,LF,'$'
  954. ;
  955. ;Timeout getting ACK
  956. ;
  957. GETATOT JMP    ACKERR    ;NO MSG
  958. ABORT    LXI    SP,STACK
  959. ;
  960. ABORTL    MVI    B,1    ;1 SEC. W/O CHARS.
  961.     CALL    RECV
  962.     JNC    ABORTL    ;LOOP UNTIL SENDER DONE
  963.     MVI    A,CAN    ;CONTROL X
  964.     CALL    SEND    ;STOP SENDING END
  965. ;
  966. ABORTW    MVI    B,1    ;1 SEC W/O CHARS.
  967.     CALL    RECV
  968.     JNC    ABORTW    ;LOOP UNTIL SENDER DONE
  969.     MVI    A,' '    ;GET A SPACE...
  970.     CALL    SEND    ;TO CLEAR OUT CONTROL X
  971.     CALL    ERXIT    ;EXIT WITH ABORT MSG
  972.     DB    'XMODEM PROGRAM CANCELLED',CR,LF,'$'
  973. ;
  974. ;---->    INCRSNO: Increment sector #
  975. ;
  976. INCRSNO LDA    SECTNO    ;INCR..
  977.     INR    A    ;..SECT..
  978.     STA    SECTNO    ;..NUMBER
  979.     PUSH    H
  980.     LXI    H,VOUT    ;CK FOR OPTIONAL COUNT TO CONSOLE
  981.     MOV    A,H
  982.     ORA    L
  983.     JNZ    CONSEC
  984.     POP    H
  985.     RET
  986. ;
  987. CONSEC:    MVI    A,CR
  988.     CALL    VOUT
  989.     LHLD    SECCNT    ;UPDATE TOTAL SECTOR COUNT
  990.     INX    H
  991.     SHLD    SECCNT
  992.     CALL    DECOUTX    ;DISPLAY COUNT
  993.     POP    H
  994.     RET
  995. ;
  996. DECOUTX    PUSH    B
  997.     PUSH    D
  998.     PUSH    H
  999.     LXI    B,-10
  1000.     LXI    D,-1
  1001. ;
  1002. DECOU2X    DAD    B
  1003.     INX    D
  1004.     JC    DECOU2X
  1005.     LXI    B,10
  1006.     DAD    B
  1007.     XCHG
  1008.     MOV    A,H
  1009.     ORA    L
  1010.     CNZ    DECOUTX
  1011.     MOV    A,E
  1012.     ADI    '0'
  1013.     CALL    VOUT
  1014.     POP    H
  1015.     POP    D
  1016.     POP    B
  1017.     RET
  1018. ;
  1019. ;---->    CHEKFIL: See if file exists
  1020. ;
  1021. ;If it exists, say use a different name.
  1022. ;
  1023. CHEKFIL
  1024.     if    setarea        
  1025.     call    recarea        ;set the designated area up     a 01/06/81
  1026.     endif
  1027. ;
  1028.     LXI    D,FCB    ;POINT TO CTL BLOCK
  1029.     MVI    C,SRCHF ;SEE IF IT..
  1030.     CALL    BDOS    ;..EXISTS
  1031.     INR    A    ;FOUND?
  1032.     RZ        ;..NO, RETURN
  1033.     CALL    ERXIT    ;EXIT, PRINT ERROR MESSAGE
  1034.     DB    '++FILE EXISTS - USE A DIFFERENT NAME++'
  1035.     DB    CR,LF,'$'
  1036. ;
  1037. ;---->    MAKEFIL: Makes the file to be received
  1038. ;
  1039. MAKEFIL    XRA    A    ;SET EXT & REC # TO 0
  1040.     STA    FCBEXT
  1041.     STA    FCBSNO
  1042.     LXI    D,FCB    ;POINT TO FCB
  1043.     MVI    C,MAKE    ;GET BDOS FNC
  1044.     CALL    BDOS    ;TO THE MAKE
  1045.     INR    A    ;FF=BAD?
  1046.     RNZ        ;OPEN OK
  1047. ;Directory full - can't make file
  1048.     CALL    ERXIT
  1049.     DB    '++ERROR - CAN''T MAKE FILE++',CR,LF
  1050.     DB    'Directory must be full',CR,LF,'$'
  1051. ;
  1052. ;---->    CNREC: Computes record count, and saves it
  1053. ;           until successful file OPEN.
  1054. ;
  1055. ;LOOK UP THE FCB IN THE DIRECTORY
  1056. CNREC    MVI    A,'?'    ;MATCH ALL EXTENTS
  1057.     STA    FCBEXT
  1058.     MVI    A,0FFH
  1059.     STA    MAXEXT    ;INIT MAX EXT NO.
  1060.     MVI    C,SRCHF ;GET 'SEARCH FIRST' FNC
  1061.     LXI    D,FCB
  1062.     CALL    BDOS    ;READ FIRST
  1063.     INR    A    ;WERE THERE ANY?
  1064.     JNZ    SOME    ;GOT SOME
  1065.     CALL    ERXIT
  1066.     DB    '++FILE NOT FOUND++$'
  1067. ;
  1068. ;READ MORE DIRECTORY ENTRIES
  1069. MOREDIR    MVI    C,SRCHN ;SEARCH NEXT
  1070.     LXI    D,FCB
  1071.     CALL    BDOS    ;READ DIR ENTRY
  1072.     INR    A    ;CHECK FOR END (0FFH)
  1073.     JNZ    SOME    ;NOT END OF DIR...PROCESS EXTENT
  1074.     LDA    MAXEXT    ;HIT END...GET HIGHEST EXTENT NO. SEEN
  1075.     MOV    L,A    ;WHICH GIVES EXTENT COUNT - 1
  1076.     MVI    H,0
  1077.     MOV    D,H
  1078.     LDA    RCNT    ;GET RECORD COUNT OF MAX EXTENT SEEN
  1079.     MOV    E,A    ;SAVE IT IN DE
  1080.     DAD    H
  1081.     DAD    H    ;MULTIPLY # OF EXTENTS - 1
  1082.     DAD    H    ; TIMES 128
  1083.     DAD    H
  1084.     DAD    H
  1085.     DAD    H
  1086.     DAD    H
  1087.     DAD    D    ;ADD IN SIZE OF LAST EXTENT
  1088.     SHLD    RCNT    ;SAVE TOTAL RECORD COUNT
  1089.     RET        ;AND EXIT
  1090. ;
  1091. ;POINT TO DIRECTORY ENTRY 
  1092. SOME    DCR    A    ;UNDO PREV 'INR A'
  1093.     ANI    3    ;MAKE MODULUS 4
  1094.     ADD    A    ;MULTIPLY...
  1095.     ADD    A    ;..BY 32 BECAUSE
  1096.     ADD    A    ;..EACH DIRECTORY
  1097.     ADD    A    ;..ENTRY IS 32
  1098.     ADD    A    ;..BYTES LONG
  1099.     LXI    H,BASE+80H ;POINT TO BUFFER
  1100.     ADD    L    ;POINT TO ENTRY
  1101.     ADI    15    ;OFFSET TO RECORD COUNT
  1102.     MOV    L,A    ;HL NOW POINTS TO REC COUNT
  1103.     MOV    B,M    ;GET RECORD COUNT
  1104.     DCX    H
  1105.     DCX    H    ;BACK DOWN TO EXTENT NUMBER
  1106.     DCX    H
  1107.     LDA    MAXEXT    ;COMPARE WITH CURRENT MAX.
  1108.     ORA    A    ;IF NO MAX YET
  1109.     JM    BIGGER    ;THEN SAVE RECORD COUNT ANYWAY
  1110.     CMP    M
  1111.     JNC    MOREDIR
  1112. ;
  1113. BIGGER:    MOV    A,B    ;SAVE NEW RECORD COUNT
  1114.     STA    RCNT
  1115.     MOV    A,M    ;SAVE NEW MAX. EXTENT NO.
  1116.     STA    MAXEXT
  1117.     JMP    MOREDIR    ;GO FIND MORE EXTENTS
  1118. ;
  1119. ;---->    OPENFIL: Opens the file to be sent
  1120. ;
  1121. OPENFIL    XRA    A    ;SET EXT & REC # TO 0 FOR PROPER OPEN
  1122.     STA    FCBEXT
  1123.     STA    FCBSNO
  1124.     LXI    D,FCB    ;POINT TO FILE
  1125.     MVI    C,OPEN    ;GET FUNCTION
  1126.     CALL    BDOS    ;OPEN IT
  1127.     INR    A    ;OPEN OK?
  1128.     JNZ    OPENOK    ;..YES
  1129.     CALL    ERXIT    ;..NO, ABORT
  1130.     DB    '++OPEN ERROR++',CR,LF,'$'
  1131. ;
  1132. ;Check for distribution-protected file
  1133. ;
  1134. OPENOK    LDA    FCB+1    ;FIRST CHAR OF FILE NAME
  1135.     ANI    80H    ;CHECK BIT 7
  1136.     JNZ    OPENOT    ;If on, file can't be sent.
  1137.     LDA    FCB+2    ;Also check "f2" for tag.
  1138.     ANI    80H    ;Is it set?
  1139.     JZ    OPENOK2    ;If not, ok to send file.
  1140. ;
  1141. OPENOT    CALL    ERXIT    ;EXIT W/MESSAGE
  1142.     DB    '++THIS FILE IS NOT FOR DISTRIBUTION, SORRY++'
  1143.     DB    CR,LF,'$'
  1144. ;
  1145. OPENOK2 EQU    $
  1146. ;
  1147.     IF    NOLBS OR NOCOMS ;CHECK FOR SEND RESTRICTIONS
  1148.     LXI    H,FCB+11
  1149.     MOV    A,M    ;CHECK FOR PROTECT ATTR
  1150.     ANI    7FH    ;REMOVE CP/M 2.x ATTRS
  1151.     ENDIF        ;NOLBS OR NOCOMS
  1152. ;
  1153.     IF    NOLBS    ;DON'T ALLOW '#' TO BE SENT.
  1154.     CPI    '#'    ;CHK FOR '#' AS LAST FIRST
  1155.     JZ    OPENOT    ;IF '#', CAN'T SEND, SHOW WHY
  1156.     ENDIF        ;NOLBS
  1157. ;
  1158.     IF    NOCOMS    ;DON'T ALLOW .COM TO BE SENT
  1159.     CPI    'M'    ;IF NOT, CHK FOR '.COM'
  1160.     JNZ    OPENOK3 ;IF NOT, OK TO SEND
  1161.     DCX    H
  1162.     MOV    A,M    ;CHK NEXT CHAR
  1163.     ANI    7FH    ;STRIP ATTRIBUTES
  1164.     CPI    'O'    ; 'O'?
  1165.     JNZ    OPENOK3 ;IF NOT, OK TO SEND
  1166.     DCX    H
  1167.     MOV    A,M    ;NOW CHK FIRST CHAR
  1168.     ANI    7FH    ;STRIP ATTRIBUTES
  1169.     CPI    'C'    ; 'C' AS IN '.COM'?
  1170.     JNZ    OPENOK3 ;IF NOT, CONTINUE
  1171.     CALL    ERXIT    ;EXIT W/MESSAGE
  1172.     DB    '++CAN''T SEND A .COM FILE++'
  1173.     DB    CR,LF,'$'
  1174.     ENDIF        ;NOCOMS
  1175. ;
  1176. OPENOK3 CALL    ILPRT    ;PRINT:
  1177.     DB    'File Open -  ',0            ; v48b bhk
  1178.     LHLD    RCNT    ; Get record count.
  1179.     CALL    DECOUT    ;PRINT DECIMAL NUMBER OF SECTORS
  1180.     CALL    ILPRT
  1181.     DB    ' (',0
  1182.     CALL    DHXOUT    ;Now print size in hex.
  1183.     CALL    ILPRT
  1184.     DB    ' Hex) Sectors',CR,LF            ; v48b bhk
  1185.     db    '(approximately ',0            ; v48b bhk
  1186.     lhld    rcnt    ; get # of sectors        ; v48b bhk
  1187.     IF    LSPEED
  1188.     LDA    MSPEED                    ; V50  JPR
  1189.     CPI    B600                    ;  "
  1190.     PUSH    PSW                    ;  "
  1191.     JNZ    S300                    ;  "
  1192.     XRA    A    ; DIVIDE HL BY 2           "
  1193.     MOV    A,H                    ;  "
  1194.     RAR                        ;  "
  1195.     MOV    H,A                    ;  "
  1196.     MOV    A,L                    ;  "
  1197.     RAR                        ;  "
  1198.     MOV    L,A                    ;  "
  1199.  
  1200. S300
  1201.     ENDIF
  1202.     call    divhl14    ; divide HL by 14 (sectors/min)    ; v48b bhk
  1203.     PUSH    H
  1204.     IF    LOGCAL
  1205.     SHLD    PGSIZE                    ; V50  JPR
  1206.     ENDIF
  1207.     MVI    H,0
  1208.     call    decout    ; print decimal # of minutes    ; v48b bhk
  1209.     call    ilprt                    ; v48b bhk
  1210.     db    ' mins, ',0
  1211.  
  1212.     POP    H
  1213.     MOV    A,H        ;REMAINDER X 4 = SECONDS
  1214.     RLC
  1215.     RLC
  1216.     MOV    L,A
  1217.     MVI    H,0
  1218.     CALL    DECOUT
  1219.     IF    LSPEED
  1220.     POP    PSW                    ; V50 JPR
  1221.     JNZ    MS300
  1222.     CALL    ILPRT
  1223.     DB    ' secs to send at 600 baud).',cr,lf        ; v48b bhk
  1224.     db    '[Control-X to cancel.]',cr,lf,0    ; v48c bhk
  1225.     RET
  1226. MS300
  1227.     ENDIF
  1228.     CALL    ILPRT
  1229.     DB    ' secs to send at 300 baud).',cr,lf        ; v48b bhk
  1230.     db    '[Control-X to cancel.]',cr,lf,0    ; v48c bhk
  1231.     RET
  1232. ;
  1233. ;---->  DIVHL14: Divides HL by 14, 
  1234. ;    UPON EXIT: L=QUOTIENT,H=REMAINDER
  1235. ;
  1236. divhl14    push    b
  1237.     MVI    B,8    ;SHIFT FACTOR TO B
  1238.     MVI    C,14    ;DIVISOR TO C
  1239. div2    xra    a    ; clear carry flag and accumulator
  1240.     DAD    H
  1241.     MOV    A,H
  1242.     SUB    C
  1243.     JM    DIV3    ;DONT BORROW ON NEG RESULTS
  1244.     MOV    H,A
  1245.     MOV    A,L
  1246.     ORI    1    ;BORROW 1
  1247.     MOV    L,A
  1248. DIV3    dcr    b
  1249.     jnz    div2
  1250.     pop    b
  1251.     ret
  1252. ;
  1253. ;---->    CLOSFIL: Closes the received file
  1254. ;
  1255. CLOSFIL LXI    D,FCB    ;POINT TO FILE
  1256.     MVI    C,CLOSE ;GET FUNCTION
  1257.     CALL    BDOS    ;CLOSE IT
  1258.     INR    A    ;CLOSE OK?
  1259.     RNZ        ;..YES, RETURN
  1260.     CALL    ERXIT    ;..NO, ABORT
  1261.     DB    '++CAN''T CLOSE FILE++',CR,LF,'$'
  1262. ;
  1263. ;
  1264. ;----> DECOUT: Decimal output routine
  1265. ;
  1266. DECOUT:    PUSH    B
  1267.     PUSH    D
  1268.     PUSH    H
  1269.     LXI    B,-10
  1270.     LXI    D,-1
  1271. ;
  1272. DECOU2:    DAD    B
  1273.     INX    D
  1274.     JC    DECOU2
  1275.     LXI    B,10
  1276.     DAD    B
  1277.     XCHG
  1278.     MOV    A,H
  1279.     ORA    L
  1280.     CNZ    DECOUT
  1281.     MOV    A,E
  1282.     ADI    '0'
  1283.     CALL    CTYPE
  1284.     POP    H
  1285.     POP    D
  1286.     POP    B
  1287.     RET
  1288. ;
  1289. ;---->    DHXOUT: - double precision hex output routine.
  1290. ;    Call with hex value in HL.
  1291. ;
  1292. DHXOUT    PUSH    H    ;Save H,L
  1293.     PUSH    PSW    ;Save A
  1294.     MOV    A,H    ;Get MS byte.
  1295.     CALL    HEXO    ;Output hi order byte.
  1296.     MOV    A,L    ;Get LS byte.
  1297.     CALL    HEXO    ;Output lo order byte.
  1298.     POP    PSW    ;Restore A
  1299.     POP    H    ;Restore H,L
  1300.     RET        ;Return to caller.
  1301. ;
  1302. ;
  1303. ;---->    RDSECT: Reads a sector
  1304. ;
  1305. ;For speed, this routine buffers up 16
  1306. ;sectors at a time.
  1307. ;
  1308. RDSECT    LDA    SECINBF ;GET # SECT IN BUFF.
  1309.     DCR    A    ;DECREMENT..
  1310.     STA    SECINBF ;..IT
  1311.     JM    RDBLOCK ;EXHAUSTED?  NEED MORE.
  1312.     LHLD    SECPTR    ;GET POINTER
  1313.     LXI    D,BASE+80H ;TO DATA
  1314.     CALL    MOVE128 ;MOVE TO BUFFER
  1315.     SHLD    SECPTR    ;SAVE BUFFER POINTER
  1316.     RET        ;FROM "READSEC"
  1317. ;
  1318. ;Buffer is empty - read in another block of 16
  1319. ;
  1320. RDBLOCK LDA    EOFLG    ;GED EOF FLAG
  1321.     CPI    1    ;IS IT SET?
  1322.     STC        ;TO SHOW EOF
  1323.     RZ        ;GOT EOF
  1324.     MVI    C,0    ;SECTORS IN BLOCK
  1325.     LXI    D,DBUF    ;TO DISK BUFFER
  1326. ;
  1327. RDSECLP PUSH    B
  1328.     PUSH    D
  1329.     MVI    C,STDMA ;SET DMA..
  1330.     CALL    BDOS    ;..ADDR
  1331.     LXI    D,FCB
  1332.     MVI    C,READ
  1333.     CALL    BDOS
  1334.     POP    D
  1335.     POP    B
  1336.     ORA    A    ;READ OK?
  1337.     JZ    RDSECOK ;YES
  1338.     DCR    A    ;EOF?
  1339.     JZ    REOF    ;GOT EOF
  1340. ;
  1341. ;Read error
  1342. ;
  1343.     CALL    ERXIT
  1344.     DB    '++FILE READ ERROR++',CR,LF,'$'
  1345. ;
  1346. RDSECOK LXI    H,80H    ;ADD LENGTH OF ONE SECTOR...
  1347.     DAD    D    ;...TO NEXT BUFF
  1348.     XCHG        ;BUFF TO DE
  1349.     INR    C    ;MORE SECTORS?
  1350.     MOV    A,C    ;GET COUNT
  1351.     CPI    16    ;DONE?
  1352.     JZ    RDBFULL ;..YES, BUFF IS FULL
  1353.     JMP    RDSECLP ;READ MORE
  1354. ;
  1355. REOF    MVI    A,1
  1356.     STA    EOFLG    ;SET EOF FLAG
  1357.     MOV    A,C
  1358. ;
  1359. ;Buffer is full, or got EOF
  1360. ;
  1361. RDBFULL STA    SECINBF ;STORE SECTOR COUNT
  1362.     LXI    H,DBUF    ;INIT BUFFER..
  1363.     SHLD    SECPTR    ;..POINTER
  1364.     LXI    D,BASE+80H ;RESET..
  1365.     MVI    C,STDMA ;..DMA..
  1366.     CALL    BDOS    ;..ADDR
  1367.     JMP    RDSECT    ;PASS SECT TO CALLER
  1368. ;
  1369. ;---->    WRSECT: Write a sector
  1370. ;
  1371. ;Writes the sector into a buffer.  When 16
  1372. ;have been written, writes the block to disk.
  1373. ;
  1374. ;Entry point "WRBLOCK" flushes the buffer at EOF.
  1375. ;
  1376. WRSECT    LHLD    SECPTR    ;GET BUFF ADDR
  1377.     XCHG        ;TO DE FOR MOVE
  1378.     LXI    H,BASE+80H    ;FROM HERE
  1379.     CALL    MOVE128 ;MOVE TO BUFFER
  1380.     XCHG        ;SAVE NEXT..
  1381.     SHLD    SECPTR    ;..BLOCK POINTER
  1382.     LDA    SECINBF ;BUMP THE..
  1383.     INR    A    ;..SECTOR #..
  1384.     STA    SECINBF ;..IN THE BUFF
  1385.     CPI    16    ;HAVE WE 16?
  1386.     RNZ        ;NO, RETURN
  1387. ;
  1388. ;---->    WRBLOCK: Writes a block to disk
  1389. ;
  1390. WRBLOCK LDA    SECINBF ;# SECT IN BUFFER
  1391.     ORA    A    ;0 MEANS END OF FILE
  1392.     RZ        ;NONE TO WRITE
  1393.     MOV    C,A    ;SAVE COUNT
  1394.     LXI    D,DBUF    ;POINT TO DISK BUFF
  1395. ;
  1396. DKWRLP    PUSH    H
  1397.     PUSH    D
  1398.     PUSH    B
  1399.     MVI    C,STDMA ;SET DMA
  1400.     CALL    BDOS    ;TO BUFFER
  1401.     LXI    D,FCB    ;THEN WRITE
  1402.     MVI    C,WRITE ;..THE..
  1403.     CALL    BDOS    ;..BLOCK
  1404.     POP    B
  1405.     POP    D
  1406.     POP    H
  1407.     ORA    A
  1408.     JNZ    WRERR    ;OOPS, ERROR
  1409.     LXI    H,80H    ;LENGTH OF 1 SECT
  1410.     DAD    D    ;HL= NEXT BUFF
  1411.     XCHG        ;TO DE FOR SETDMA
  1412.     DCR    C    ;MORE SECTORS?
  1413.     JNZ    DKWRLP    ;..YES, LOOP
  1414.     XRA    A    ;GET A ZERO
  1415.     STA    SECINBF ;RESET # OF SECTORS
  1416.     LXI    H,DBUF    ;RESET BUFFER..
  1417.     SHLD    SECPTR    ;..POINTER
  1418. ;
  1419. RSDMA    LXI    D,BASE+80H ;RESET..
  1420.     MVI    C,STDMA ;..DMA..
  1421.     CALL    BDOS    ;..ADDR
  1422.     RET
  1423. ;
  1424. WRERR    CALL    RSDMA    ;RESET DMA TO NORM.
  1425.     MVI    C,CAN    ;CANCEL..
  1426.     CALL    SEND    ;..SENDER
  1427.     CALL    ERXIT    ;EXIT W/MSG:
  1428.     DB    '++ERROR WRITING FILE++',CR,LF,'$'
  1429. ;
  1430. ;---->    RECV: Receive a character
  1431. ;
  1432. ;Timeout time is in B, in seconds.  Entry via
  1433. ;"RECVDG" deletes garbage characters on the
  1434. ;line.    For example, having just sent a sector,
  1435. ;calling RECVDG will delete any line-noise-induced
  1436. ;characters "long" before the ACK/NAK would
  1437. ;be received.
  1438. ;
  1439. RECVDG    EQU    $    ;RECEIVE W/GARBAGE DELETE
  1440.     IN    MODDATP ;GET A CHAR
  1441.     IN    MODDATP ;..TOTALLY PURGE UART
  1442. ;
  1443. RECV    PUSH    D    ;SAVE
  1444. ;
  1445.     IF    FASTCLK ;4MHZ?
  1446.     MOV    A,B    ;GET TIME REQUEST
  1447.     ADD    A    ;DOUBLE IT
  1448.     MOV    B,A    ;NEW TIME IN B
  1449.     ENDIF
  1450. ;
  1451. MSEC    LXI    D,50000 ;1 SEC DCR COUNT
  1452. ;
  1453.     IF    NOT DCH
  1454. MWTI    IN    MODCTLP ;CHECK STATUS
  1455.     ENDIF
  1456. ;
  1457.     IF    DCH
  1458. MWTI    IN    MODCTL2 ;CHECK STATUS
  1459.     ENDIF
  1460. ;
  1461.     IF    PMMI AND FRNTPNL
  1462.     OUT    PANEL    ;DISPLAY STATUS ON PANEL LIGHTS
  1463.     ENDIF
  1464. ;
  1465.     ANI    MODRCVB ;ISOLATE BIT
  1466.     CPI    MODRCVR ;READY?
  1467.     JZ    MCHAR    ;GOT CHAR
  1468.     DCR    E    ;COUNT..
  1469.     JNZ    MWTI    ;..DOWN..
  1470.     DCR    D    ;..FOR..
  1471.     JNZ    MWTI    ;..TIMEOUT
  1472.     DCR    B    ;MORE SECONDS?
  1473.     JNZ    MSEC    ;YES, WAIT
  1474. ;
  1475. ;Test for the presence of carrier - if none, go to 
  1476. ;CARCK and continue testing for 15 seconds. If carrier
  1477. ;returns, continue. If is doesn't return, exit.
  1478. ;
  1479.     IF    EXTMOD OR H8 OR DCH
  1480.     IN    MODCTL2    ;READ MODEM STATUS
  1481.     ENDIF
  1482. ;
  1483.     IF    PMMI
  1484.     IN    BAUDRP    ;READ MODEM STATUS
  1485.     ENDIF
  1486. ;
  1487.     IF    PMMI AND FRNTPNL
  1488.     OUT    PANEL    ;DISPLAY STATUS ON PANEL LIGHTS
  1489.     ENDIF
  1490. ;
  1491.     ANI    MODDCDB    ;CARRIER DETECT MASK
  1492.     CPI    MODDCDA    ;IS IT STILL ON?
  1493.     CNZ    CARCK    ;IF NOT, TEST FOR 15 SECONDS
  1494. ;
  1495. ;Modem timed out receiving - but carrier still on.
  1496. ;
  1497.     POP    D    ;RESTORE D,E
  1498.     STC        ;CARRY SHOWS TIMEOUT
  1499.     RET
  1500. ;
  1501. ;Got character from modem
  1502. ;
  1503. MCHAR:
  1504. ;Check to see if there was a framing error,
  1505. ;overrun, or parity error.
  1506. ;
  1507.     IF    PMMI OR H8
  1508.     IN    MODCTLP    ;GET MODEM STATUS
  1509.     ENDIF
  1510. ;
  1511.     IF    DCH
  1512.     IN    MODCTL2    ;GET MODEM STATUS
  1513.     ENDIF
  1514. ;
  1515.     IF    PMMI OR H8 OR DCH
  1516.     MOV    D,A    ;SAVE STATUS
  1517.     ANI    MODFRME    ;FRAMING ERROR?
  1518.     CPI    MODFRME
  1519.     JNZ    MCHAR2    ;NO, CHECK FOR OVERRUN
  1520.     LDA    ERRCDE    ;GET RECV ERR CODE
  1521.     ORI    MODFRME    ;TURN ON RECV ERR CODE
  1522.     STA    ERRCDE    ;PUT IT BACK
  1523. ;
  1524. MCHAR2:    MOV    A,D    ;RESTORE MODEM STATUS
  1525.     ANI    MODOVRE    ;OVERRUN?
  1526.     CPI    MODOVRE
  1527.     JNZ    MCHAR3    ;NO, CHECK FOR PARITY ERROR
  1528.     LDA    ERRCDE
  1529.     ORI    MODOVRE    ;TURN ON RECV ERR CODE
  1530.     STA    ERRCDE
  1531. ;
  1532. MCHAR3:    MOV    A,D    ;RESTORE MODEM STATUS
  1533.     ANI    MODPARE    ;PARITY ERROR?
  1534.     CPI    MODPARE
  1535.     JNZ    MCHAR4    ;NO, GET DATA CHAR
  1536.     LDA    ERRCDE
  1537.     ORI    MODPARE
  1538.     STA    ERRCDE
  1539. ;
  1540. MCHAR4:
  1541.     ENDIF        ;PMMI OR H8 OR DCH
  1542. ;
  1543. ;Get data char
  1544. ;
  1545.     IN    MODDATP ;READ THE CHAR
  1546.     POP    D    ;RESTORE DE
  1547. ;
  1548. ;Calc checksum and CRC
  1549. ;
  1550.     PUSH    PSW    ;SAVE THE CHAR
  1551.     CALL    UPDCRC    ;CALC CRC
  1552.     ADD    C    ;ADD TO CHECKSUM
  1553.     MOV    C,A    ;SAVE CHECKSUM
  1554.     POP    PSW    ;RESTORE CHAR
  1555.     ORA    A    ;CARRY OFF: NO ERROR
  1556.     RET        ;FROM "RECV"
  1557. ;
  1558. ;CARCK - common 15 second carrier test for RECV and
  1559. ;SEND. If carrier returns within 15 seconds, normal
  1560. ;program execution continues. Else, it will abort
  1561. ;to CP/M via EXIT.
  1562. ;
  1563. CARCK    MVI    E,150    ;VALUE FOR 15 SECOND DELAY
  1564. ;
  1565. CARCK1    CALL    DELAY    ;KILL .1 SECONDS
  1566. ;
  1567.     IF    EXTMOD OR H8 OR DCH
  1568.     IN    MODCTL2    ;READ MODEM STATUS
  1569.     ENDIF
  1570. ;
  1571.     IF    PMMI
  1572.     IN    BAUDRP    ;READ MODEM STATUS
  1573.     ENDIF
  1574. ;
  1575.     IF    PMMI AND FRNTPNL
  1576.     OUT    PANEL    ;DISPLAY STATUS
  1577.     ENDIF
  1578. ;
  1579.     ANI    MODDCDB    ;CARRIER DETECT MASK
  1580.     CPI    MODDCDA    ;IS IT STILL ON?
  1581.     RZ        ;RETURN IF CARRIER ON
  1582.     DCR    E    ;HAS 15 SECONDS EXPIRED?
  1583.     JNZ    CARCK1    ;IF NOT, CONTINUE TESTING
  1584.     JMP    EXIT    ;ELSE, ABORT TO CP/M.
  1585. ;
  1586. ;DELAY - 100 millisecond delay.
  1587. ;
  1588. DELAY    PUSH    B    ;SAVE B,C
  1589. ;
  1590.     IF    FASTCLK    ;IF 4MHZ CLOCK
  1591.     LXI    B,16667    ;VALUE FOR 100MS DELAY
  1592.     ENDIF
  1593. ;
  1594.     IF    NOT FASTCLK
  1595.     LXI    B,8334    ;VALUE FOR 100MS DELAY
  1596.     ENDIF
  1597. ;
  1598. DELAY2    DCX    B    ;UPDATE COUNT
  1599.     MOV    A,B    ;GET MS BYTE
  1600.     ORA    C    ;COUNT = ZERO?
  1601.     JNZ    DELAY2    ;IF NOT, CONTINUE
  1602.     POP    B    ;RESTORE B,C
  1603.     RET        ;RETURN TO CARCK1.
  1604. ;
  1605. ;---->    SEND: Send a character to the modem
  1606. ;
  1607. SEND    PUSH    PSW    ;SAVE THE CHARACTER
  1608.     CALL    UPDCRC    ;calc the crc
  1609.     ADD    C    ;CALC CKSUM
  1610.     MOV    C,A    ;SAVE CKSUM
  1611. ;
  1612.     IF    NOT DCH
  1613. SENDW    IN    MODCTLP ;GET STATUS
  1614.     ENDIF
  1615. ;
  1616.     IF    DCH
  1617. SENDW    IN    MODCTL2 ;GET STATUS
  1618.     ENDIF
  1619. ;
  1620.     IF    PMMI AND FRNTPNL
  1621.     OUT    PANEL    ;DISPLAY STATUS
  1622.     ENDIF
  1623. ;
  1624.     ANI    MODSNDB ;ISOLATE READY BIT
  1625.     CPI    MODSNDR ;READY?
  1626.     JZ    SENDR    ;..YES, GO SEND
  1627. ;
  1628. ;Xmit status not ready, so test for carrier before
  1629. ;looping - if lost, go to CARCK and give it up to 15
  1630. ;seconds to return. If it doesn't return abort via
  1631. ;EXIT.
  1632. ;
  1633.     PUSH    D    ;Save D,E
  1634. ;
  1635.     IF    EXTMOD OR H8 OR DCH
  1636.     IN    MODCTL2    ;READ MODEM STATUS
  1637.     ENDIF
  1638. ;
  1639.     IF    PMMI
  1640.     IN    BAUDRP    ;READ MODEM STATUS
  1641.     ENDIF
  1642. ;
  1643.     IF    PMMI AND FRNTPNL
  1644.     OUT    PANEL    ;DISPLAY STATUS
  1645.     ENDIF
  1646. ;
  1647.     ANI    MODDCDB    ;CARRIER DETECT MASK
  1648.     CPI    MODDCDA    ;IS IT STILL ON?
  1649.     CNZ    CARCK    ;IF NOT, CONTINUE TESTING IT
  1650.     POP    D    ;RESTORE D,E
  1651.     JMP    SENDW    ;ELSE, WAIT FOR XMIT READY.
  1652. ;
  1653. ;Xmit status ready, carrier still on - send the data.
  1654. ;
  1655. SENDR    POP    PSW    ;GET CHAR
  1656.     OUT    MODDATP ;OUTPUT IT
  1657.     RET        ;FROM "SEND"
  1658. ;
  1659. ;---->    WAITNAK: Waits for initial NAK
  1660. ;
  1661. ;To ensure no data is sent until the receiving
  1662. ;program is ready, this routine waits for the
  1663. ;first timeout-NAK or the letter 'C' for CRC
  1664. ;from the receiver.  If CRC is in effect, then
  1665. ;Cyclic Redundancy Checks are used instead of
  1666. ;checksums.
  1667. ;(E) contains the # of seconds to wait.
  1668. ;
  1669. ; If the first character received is a CAN (control-X)
  1670. ; then the send will be aborted as though it had timed out.
  1671. ; 04/01/82 BHK 
  1672. ;
  1673. WAITNAK MVI    B,1    ;TIMEOUT DELAY
  1674.     CALL    RECV    ;DID WE GET..
  1675.     CPI    NAK    ;..A NAK?
  1676.     RZ        ;YES, SEND BLOCK
  1677.     CPI    CRC    ;CRC INDICATED?
  1678.     JZ    WAITCRC    ;YES, GO PUT CRC IN EFFECT
  1679.     CPI    CAN    ;WAS IT A CANCEL (CONTROL-X)?        ; v48c bhk
  1680.     JZ    ABORT    ;YES, ABORT                ; v48c bhk
  1681.     DCR    E    ;80 TRIES?
  1682.     JZ    ABORT    ;YES, ABORT
  1683.     JMP    WAITNAK ;NO, LOOP
  1684. ;
  1685. ;----> WAITCRC: Turn on CRC Flag
  1686. ;
  1687. WAITCRC    XRA    A    ;ZERO ACCUM
  1688.     STA    CRCFLG    ;TURN ON CRC OPT
  1689.     RET
  1690. ;
  1691. ;---->    MOVEFCB: Moves FCB(2) to FCB
  1692. ;
  1693. ;In order to make the XMODEM command 'natural',
  1694. ;i.e. XMODEM SEND FILENAME (MODEM S FN.FT) rather
  1695. ;than XMODEM FILENAME SEND (MODEM FN.FT S), this
  1696. ;routine moves the filename from the second FCB
  1697. ;to the first.
  1698. ;
  1699. MOVEFCB LXI    H,FCB+16 ;FROM
  1700.     LXI    D,FCB    ;TO
  1701.     MVI    B,16    ;LEN
  1702.     CALL    MOVE    ;DO THE MOVE
  1703.     XRA    A    ;GET 0
  1704.     STA    FCBSNO    ;ZERO SECTOR #
  1705.     STA    FCBEXT    ;..AND EXTENT
  1706.     RET
  1707. ;
  1708. CTYPE    PUSH    B    ;SAVE..
  1709.     PUSH    D    ;..ALL..
  1710.     PUSH    H    ;..REGS
  1711.     MOV    E,A    ;CHAR TO E
  1712.     MVI    C,WRCON ;GET BDOS FNC
  1713.     CALL    BDOS    ;PRIN THE CHR
  1714.     POP    H    ;RESTORE..
  1715.     POP    D    ;..ALL..
  1716.     POP    B    ;..REGS
  1717.     RET        ;FROM "CTYPE"
  1718. ;
  1719. HEXO    PUSH    PSW    ;SAVE FOR RIGHT DIGIT
  1720.     RAR        ;RIGHT..
  1721.     RAR        ;..JUSTIFY..
  1722.     RAR        ;..LEFT..
  1723.     RAR        ;..DIGIT..
  1724.     CALL    NIBBL    ;PRINT LEFT DIGIT
  1725.     POP    PSW    ;RESTORE RIGHT
  1726. ;
  1727. NIBBL    ANI    0FH    ;ISOLATE DIGIT
  1728.     CPI    10    ;IS IT <10?
  1729.     JC    ISNUM    ;YES, NOT ALPHA
  1730.     ADI    7    ;ADD ALPHA BIAS
  1731. ;
  1732. ISNUM    ADI    '0'    ;MAKE PRINTABLE
  1733.     JMP    CTYPE    ;..THEN TYPE IT
  1734. ;
  1735. ;---->    ILPRT: Inline print of message
  1736. ;
  1737. ;The call to ILPRT is followed by a message,
  1738. ;binary 0 as the end.
  1739. ;
  1740. ILPRT    XTHL        ;SAVE HL, GET HL=MSG
  1741. ;
  1742. ILPLP    MOV    A,M    ;GET CHAR
  1743.     ORA    A    ;END OF MSG?
  1744.     JZ    ILPRET    ;..YES, RETURN
  1745.     CALL    CTYPE    ;TYPE THE MSG
  1746.     INX    H    ;TO NEXT CHAR
  1747.     JMP    ILPLP    ;LOOP
  1748. ;
  1749. ILPRET    XTHL        ;RESTORE HL
  1750.     RET        ;PAST MSG
  1751. ;
  1752. EXITLG                ; SPECIAL LOG CALLER EXIT
  1753.     IF    LOGCAL
  1754.     JMP    LOGCALL
  1755.     ENDIF
  1756.     JMP    EXIT
  1757. ;
  1758. ;---->    ERXIT: Exit printing message following call
  1759. ;
  1760. ERXIT    POP    D    ;GET MESSAGE
  1761.     MVI    C,PRINT ;GET BDOS FNC
  1762.     CALL    BDOS    ;PRINT MESSAGE
  1763. ;
  1764. EXIT    LHLD    STACK    ;GET ORIGINAL STACK
  1765.     SPHL        ;RESTORE IT
  1766. ;
  1767.     if    setarea
  1768.     call    restu        ; restore old area user & drive ..a 01/06/81
  1769.     endif
  1770. ;
  1771.     RET        ;--EXIT-- TO CP/M
  1772. ;
  1773.     if    setarea
  1774. ;
  1775. ;------> RESTORE THE OLD USER AREA AND DRIVE FROM A RECEIVED FILE
  1776. ;
  1777. RESTU    lda    olddrv        ;RESTORE THE OLD DRIVE        ;a 01/06/81
  1778.     mov    e,a                        ;a 01/06/81
  1779.     call    recdrx                        ;a 01/06/81
  1780.     lda    olduser        ;RESTORE THE OLD USER NUMBER    ;a 01/06/81
  1781.     mov    e,a                        ;a 01/06/81
  1782.     jmp    recare                        ;a 01/06/81
  1783. ;
  1784. ;--------> SET USER AREA TO RECEIVE FILE
  1785. RECAREA    call    recdrv        ;ok set the drive to its place    ;a 01/06/81
  1786.     mvi    e,recu        ;ok now set the user area    ;a 01/06/81
  1787. RECARE    mvi    c,user        ;tell bdos what we want to do    ;a 01/06/81
  1788.     call    bdos        ;do it                ;a 01/06/81
  1789.     RET
  1790. ;
  1791. RECDRV    mvi    e,defdrv-41h    ;make drive cp/m number        ;a 01/06/81
  1792. RECDRX    mvi    c,seldrv    ;tell bdos            ;a 01/06/81
  1793.     call    bdos        ;do it                ;a 01/06/81
  1794.     ret            ;back                ;a 01/06/81
  1795.     endif
  1796. ;
  1797. ;Move 128 characters
  1798. ;
  1799. MOVE128 MVI    B,128    ;SET MOVE COUNT
  1800. ;
  1801. ;Move from (HL) to (DE) length in (B)
  1802. ;
  1803. MOVE    MOV    A,M    ;GET A CHAR
  1804.     STAX    D    ;STORE IT
  1805.     INX    H    ;TO NEXT "FROM"
  1806.     INX    D    ;TO NEXT "TO"
  1807.     DCR    B    ;MORE?
  1808.     JNZ    MOVE    ;..YES, LOOP
  1809.     RET        ;..NO, RETURN
  1810. ;
  1811. ;************************************************************************
  1812. ;* CRCSUBS (Cyclic Redundancy Code Subroutines) version 1.20        *
  1813. ;* 8080 Mnemonics                            *
  1814. ;*                                    *
  1815. ;*         These subroutines will compute and check a true 16-bit        *
  1816. ;*    Cyclic Redundancy Code for a message of arbitrary length.    *
  1817. ;*                                    *
  1818. ;*    The  use  of this scheme will guarantee detection of all    *
  1819. ;*    single and double bit errors, all  errors  with  an  odd    *
  1820. ;*    number  of  error bits, all burst errors of length 16 or    *
  1821. ;*    less, 99.9969% of all 17-bit error bursts, and  99.9984%    *
  1822. ;*    of  all  possible  longer  error bursts.  (Ref: Computer    *
  1823. ;*    Networks, Andrew S.  Tanenbaum, Prentiss-Hall, 1981)        *
  1824. ;*                                    *
  1825. ;*                                    *
  1826. ;*    There are four entry points, which are used as follows:        *
  1827. ;*                                    *
  1828. ;*    CLRCRC - A call to this entry resets the CRC accumulator.    *
  1829. ;*         It must be called at the start of each message.    *
  1830. ;*                                    *
  1831. ;*         Entry Parameters: None.                *
  1832. ;*                                    *
  1833. ;*         Exit Conditions:  CRC accumulator cleared.        *
  1834. ;*                   All registers preserved.        *
  1835. ;*                                    *
  1836. ;*                                    *
  1837. ;*    UPDCRC - A call to this entry updates the CRC accumulator.    *
  1838. ;*         It must be called once for each byte in the        *
  1839. ;*         message for which the CRC is being calculated.        *
  1840. ;*                                    *
  1841. ;*         Entry Parameters: (A) = a byte to be included        *
  1842. ;*                     in the CRC calculation.    *
  1843. ;*                                    *
  1844. ;*         Exit Conditions:  CRC accumulator updated.        *
  1845. ;*                   All registers preserved.        *
  1846. ;*                                    *
  1847. ;*                                    *
  1848. ;*    FINCRC - A call to this entry finishes the CRC calculation    *
  1849. ;*         for a message which is to be TRANSMITTED. It must    *
  1850. ;*         be called after the last byte of the message has    *
  1851. ;*         been passed thru UPDCRC. It returns the calculated    *
  1852. ;*         CRC bytes, which must be transmitted as the final    *
  1853. ;*         two bytes of the message (first D, then E).        *
  1854. ;*                                    *
  1855. ;*         Entry Parameters: None.                *
  1856. ;*                                    *
  1857. ;*         Exit Conditions:  (DE) = calculated CRC bytes.        *
  1858. ;*                   All other registers preserved.    *
  1859. ;*                                    *
  1860. ;*                                    *
  1861. ;*    CHKCRC - A call to this routine checks the CRC bytes of        *
  1862. ;*         a RECEIVED message and returns a code to indicate    *
  1863. ;*         whether the message was received correctly. It must    *
  1864. ;*         be called after the message AND the two CRC bytes    *
  1865. ;*         have been received AND passed thru UPDCRC.        *
  1866. ;*                                    *
  1867. ;*         Entry Parameters: None.                *
  1868. ;*                                    *
  1869. ;*         Exit Conditions:  (A) =  0 if message ok.        *
  1870. ;*                   (A) = -1 if message garbled.        *
  1871. ;*                   All other registers preserved.    *
  1872. ;*                                    *
  1873. ;************************************************************************
  1874. ;*                                    *
  1875. ;*    Designed & coded by Paul Hansknecht, June 13, 1981        *
  1876. ;*                                    *
  1877. ;*                                    *
  1878. ;*    Copyright (c) 1981, Carpenter Associates            *
  1879. ;*                Box 451                    *
  1880. ;*                Bloomfield Hills, MI 48013            *
  1881. ;*                313/855-3074                *
  1882. ;*                                    *
  1883. ;*    This program may be freely reproduced for non-profit use.    *
  1884. ;*                                    *
  1885. ;************************************************************************
  1886. ;
  1887. ;    ENTRY    CLRCRC,UPDCRC,FINCRC,CHKCRC
  1888. ;
  1889. CLRCRC:    EQU    $        ; Reset CRC Accumulator for a new message.
  1890.     PUSH    H
  1891.     LXI    H,0
  1892.     SHLD    CRCVAL
  1893.     POP    H
  1894.     RET
  1895. ;
  1896. UPDCRC:    EQU    $        ; Update CRC Accumulator using byte in (A).
  1897.     PUSH    PSW
  1898.     PUSH    B
  1899.     PUSH    H
  1900.     MVI    B,8
  1901.     MOV    C,A
  1902.     LHLD    CRCVAL
  1903. UPDLOOP:MOV    A,C
  1904.     RLC
  1905.     MOV    C,A
  1906.     MOV    A,L
  1907.     RAL
  1908.     MOV    L,A
  1909.     MOV    A,H
  1910.     RAL
  1911.     MOV    H,A
  1912.     JNC    SKIPIT
  1913.     MOV    A,H        ; The generator is X^16 + X^12 + X^5 + 1
  1914.     XRI    10H        ; as recommended by CCITT.
  1915.     MOV    H,A        ; An alternate generator which is often
  1916.     MOV    A,L        ; used in synchronous transmission protocols
  1917.     XRI    21H        ; is X^16 + X^15 + X^2 + 1. This may be
  1918.     MOV    L,A        ; used by substituting XOR 80H for XOR 10H
  1919. SKIPIT:    DCR    B        ; and XOR 05H for XOR 21H in the adjacent code.
  1920.     JNZ    UPDLOOP
  1921.     SHLD    CRCVAL
  1922.     POP    H
  1923.     POP    B
  1924.     POP    PSW
  1925.     RET
  1926. ;
  1927. FINCRC:    EQU    $        ; Finish CRC calc for outbound message.
  1928.     PUSH    PSW
  1929.     XRA    A
  1930.     CALL    UPDCRC
  1931.     CALL    UPDCRC
  1932.     PUSH    H
  1933.     LHLD    CRCVAL
  1934.     MOV    D,H
  1935.     MOV    E,L
  1936.     POP    H
  1937.     POP    PSW
  1938.     RET
  1939. ;
  1940. CHKCRC:    EQU    $        ; Check CRC bytes of received message.
  1941.     PUSH    H
  1942.     LHLD    CRCVAL
  1943.     MOV    A,H
  1944.     ORA    L
  1945.     POP    H
  1946.     RZ
  1947.     MVI    A,0FFh
  1948.     RET
  1949. ;
  1950. ;
  1951. CRCVAL    DW    0
  1952. ;
  1953. ;
  1954. ;
  1955. ;Temporary storage area
  1956. ;
  1957. MAXEXT    DB    0    ;HIGHEST EXTENT NO. SEEN IN FILE SIZE CALC.
  1958. RCNT    DW    0    ;RECORD COUNT
  1959. RCVSNO    DB    0    ;SECT # RECEIVED
  1960. SECTNO    DB    0    ;CURRENT SECTOR NUMBER 
  1961. SECCNT    DW    0    ;TOTAL SECTOR COUNT
  1962. ERRCT    DB    0    ;ERROR COUNT
  1963. olduser db    0    ;save the org user number
  1964. olddrv    db    0    ;save the org drive number
  1965. ;
  1966.     IF    PMMI OR H8 OR DCH
  1967. ERRCDE    DB    0    ;RECEIVE ERROR CODE
  1968.     ENDIF
  1969. ;
  1970. CRCFLG    DB    'C'    ;SET TO NULL IF CRC USED
  1971. FIRSTIME DB    1    ;TURNED OFF AFTER FIRST SOH RECEIVED
  1972. ;
  1973. ;Following 3 used by disk buffering routines
  1974. EOFLG    DB    0    ;EOF FLAG (1=TRUE)
  1975. SECPTR    DW    DBUF
  1976. SECINBF DB    0    ;# OF SECTORS IN BUFFER
  1977.     DS    60    ;STACK AREA
  1978. STACK    DS    2    ;STACK POINTER
  1979. ;
  1980. ;16 sector disk buffer
  1981. ;
  1982. DBUF    EQU    $    ;16 SECTOR DISK BUFFER
  1983. ;
  1984. ;BDOS equates
  1985. ;
  1986. RDCON    EQU    1
  1987. WRCON    EQU    2
  1988. PRINT    EQU    9
  1989. CONST    EQU    11    ;CONSOLE STAT
  1990. SELDRV    EQU    14    ;SELECT DRIVE
  1991. OPEN    EQU    15    ;0FFH = NOT FOUND
  1992. CLOSE    EQU    16    ;    "       "
  1993. SRCHF    EQU    17    ;    "       "
  1994. SRCHN    EQU    18    ;    "       "
  1995. ERASEF    EQU    19    ;NO RET CODE
  1996. READ    EQU    20    ;0=OK, 1=EOF
  1997. WRITE    EQU    21    ;0=OK, 1=ERR, 2=?, 0FFH=NO DIR SPC
  1998. MAKE    EQU    22    ;0FFH=BAD
  1999. REN    EQU    23    ;0FFH=BAD
  2000. CURDRV    EQU    25    ;GET CURRENT DRIVE
  2001. STDMA    EQU    26    ;SET DMA
  2002. USER    EQU    32    ;SET USER AREA TO RECEIVE FILE
  2003. BDOS    EQU    BASE+5
  2004. FCB    EQU    BASE+5CH ;SYSTEM FCB
  2005. FCBEXT    EQU    FCB+12    ;FILE EXTENT
  2006. FCBSNO    EQU    FCB+32    ;SECTOR #
  2007. FCB2    EQU    BASE+6CH ;SECOND FCB
  2008. ;
  2009.     END
  2010.