home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / sigm / vol119 / lm16.asm < prev    next >
Encoding:
Assembly Source File  |  1984-04-29  |  30.6 KB  |  1,629 lines

  1. ;        LMODEM.ASM  by S. Kluger, N5NX
  2. ;
  3. ;    Developed from XMODEM56.ASM by Keith Petersen, W8SDZ
  4. ;    The basic idea on how to access the LBR file was taken from
  5. ;    LRUN.ASM by G. Novosielski, but no code was copied therefrom.
  6. ;    Error checking is not done as extensively as in LRUN.
  7. ;    Note that this is an EXPERIMENTAL version and could most
  8. ;    definitely be improved by a more experienced programmer.
  9. ;    (This doesn't mean I'm incompetent. I made it work, didn't I???)
  10. ;
  11. ;-----------------------------------------------------------------
  12. ; Modifications/updates: (in reverse order to minimize reading time)
  13. ; 1.6  12/26/82 Finally fixed send bug. Changed end-of-member detect
  14. ;        routine and placement of RCNT. (SFK)
  15. ; 1.5  12/25/82 Fixed bug which kept LMODEM from sending files larger
  16. ;        than 255 sectors (bug made file size modulo 255) (SFK)
  17. ; 1.4  12/22/82 Incorporated directory check to make sure LBR directory
  18. ;        is not corrupt. Changed program to accept either a file name
  19. ;        defaulting to .LBR or any full file name, in case the library
  20. ;        file has a different type. (SFK)
  21. ; 1.3  12/03/82 Added EQU to version no.,and changed sign-on message.
  22. ;        (Tim Hancock  Walled Lake, Mich)
  23. ; 1.2  11/29/82 Fixed RECU and DEFDRV labels (for LOGCAL only) (SFK)
  24. ; 1.1  11/27/82 Fixed bug where sometimes the end-of-member would not
  25. ;               be detected; LMODEM kept going until EOF on the LBR (SFK)
  26. ; 1.0  11/27/82 Original distribution version
  27. ;
  28. ;
  29. ;        REMOTE LBR - CP/M FILE TRANSFER PROGRAM
  30. ;
  31. ; Based on MODEM.ASM V2.0, by Ward Christensen.  This program is in-
  32. ; tended for use on remote CP/M systems where it is important that the
  33. ; initialization of the modem not be changed, such as when using the
  34. ; BYE program.  The baud rate and number of bits remains the same as
  35. ; whatever was set previously.  There is no disconnect, terminal or echo
  36. ; option.
  37. ;
  38. ;       NOTE:  REQUIRES SEQIO22.LIB if "LOGCAL" is set TRUE
  39. ;
  40. ;*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
  41. ;
  42. ;
  43. ;    NOTE:  If you add improvements or otherwise update
  44. ;          this program, please modem a copy of the
  45. ;          new file to "El Paso RCPM" in El Paso, TX
  46. ;          (915)-598-1668.
  47. ;
  48. ;
  49. ;*   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *
  50. ;
  51. ;
  52. FALSE    EQU    0
  53. TRUE    EQU    NOT FALSE
  54. ;
  55. ;
  56. ;-----------------------------------------------------------------------
  57. ;
  58. ;        --- Conditional Assembly Options ---
  59. ;
  60. ;-----------------------------------------------------------------------
  61. ;
  62. ;
  63. VERSION    EQU    1
  64. MODLEV    EQU    6
  65. ;
  66. STDCPM    EQU    TRUE    ;TRUE, IS STANDARD CP/M
  67. ALTCPM    EQU    FALSE    ;TRUE, IS TRS-80 OR H8 W/O 0-ORG
  68. ;
  69. DCH    EQU    FALSE    ;TRUE, IS D.C. HAYES
  70. PMMI    EQU    TRUE    ;TRUE, IS PMMI
  71. H8    EQU    FALSE    ;TRUE, IS H8/H89 W/INS8250 MODEM CHIP
  72. EXTMOD    EQU    FALSE    ;TRUE, IS NONE OF THE ABOVE!
  73. ;
  74. FASTCLK EQU    TRUE    ;PUT TRUE HERE FOR 4 MHZ CLOCK
  75. ;
  76. FRNTPNL    EQU    FALSE    ;TO DISPLAY STATUS ON FRONT PANEL
  77. PANEL    EQU    0FFH    ;DEFAULT ADDRESS OF FRONT PANEL
  78. ;
  79. ;
  80. ;    FILE TRANSFER LOGGING OPTIONS
  81. ;
  82. LOGCAL    EQU    false    ;IF USING LOGGING OF LMODEM TRANSFERS
  83. LASTUSR    EQU    14    ;USER AREA OF 'LASTCALR' FILE(IF 'LOGCAL' ONLY)
  84. RECU    EQU    0    ;user area for .LOG file
  85. DEFDRV    EQU    'A'    ;LOG file drive
  86. ;
  87. LSPEED    EQU    true    ;TRUE IF USING BYE WITH SPEED SELECTION
  88. MSPEED    EQU    3DH    ;LOCATION OF BAUD RATE FACTOR  (SET BY BYE)
  89. CONOUT    EQU    0000H    ;ADDRESS OF BIOS 'C' REGISTER OUTPUT.  THIS WILL
  90. ;            ;BE THE 5TH ENTRY IN THE CP/M JUMP TABLE.  ENTER
  91. ;            ;YOUR OWN BIOS ADDRESS HERE IF YOU WISH TO HAVE
  92. ;            ;THE RECORD COUNT ON YOUR LOCAL CRT CONSOLE.
  93. ;
  94. ;-----------------------------------------------------------------------
  95. ;
  96. ;         --- Modem Port Equates ---
  97. ;
  98. ;-----------------------------------------------------------------------
  99. ;
  100.     IF    PMMI
  101. MODCTLP    EQU    0E0H        ;PMMI VALUES (BASE PORT ADDRESS)
  102. MODSNDB    EQU    1        ;BIT TO TEST FOR SEND
  103. MODSNDR    EQU    1        ;VALUE WHEN READY
  104. MODRCVB    EQU    2        ;BIT TO TEST FOR RECEIVE
  105. MODRCVR    EQU    2        ;VALUE WHEN READY
  106. MODDCDB    EQU    4        ;CARRIER DETECT BIT
  107. MODDCDA    EQU    0        ;VALUE WHEN ACTIVE
  108. MODPARE    EQU    08H        ;VALUE FOR PARITY ERROR
  109. MODOVRE    EQU    10H        ;VALUE FOR OVERRUN ERROR
  110. MODFRME    EQU    20H        ;VALUE FOR FRAMING ERROR
  111. MODDATP    EQU    MODCTLP+1    ;DATA PORT, RECEIVE
  112. MODDATO    EQU    MODCTLP+1    ;DATA PORT, SEND
  113. BAUDRP    EQU    MODCTLP+2    ;BAUD RATE OUTPUT/MODEM STATUS
  114. MODCTL2    EQU    MODCTLP+3    ;SECOND CTL PORT
  115.     ENDIF
  116. ;
  117.     IF    H8
  118. MODCTLP    EQU    0E5H    ;H8/H89 VALUES (LSR-LINE STATUS REG.)
  119. MODSNDB    EQU    20H    ;TEST FOR SEND (LSR-THRE)
  120. MODSNDR    EQU    20H    ;VALUE WHEN READY
  121. MODRCVB    EQU    01H    ;TEST FOR RECIEVE (LSR-DR)
  122. MODRCVR    EQU    01H    ;VALUE WHEN READY
  123. MODDCDB    EQU    80H    ;CARRIER DETECT BIT (MSR-CTS)
  124. MODDCDA    EQU    80H    ;VALUE WHEN ACTIVE
  125. MODPARE    EQU    04H    ;VALUE FOR PARITY ERROR (LSR-PE)
  126. MODOVRE    EQU    02H    ;VALUE FOR OVERRUN ERROR (LSR-OR)
  127. MODFRME    EQU    08H    ;VALUE FOR FRAMING ERROE (LSR-FE)
  128. MODDATP    EQU    0E0H    ;DATA PORT, RECIEVE
  129. MODDATO    EQU    0E0H    ;DATA PORT, SEND
  130. BAUDRP    EQU    0E6H    ;BAUD RATE PORT (DALB IN LCR MUST=1)
  131. MODCTL2    EQU    0E6H    ;MODEM STATUS REGISTER (MSR)
  132. MODCTL1    EQU    0E3H    ;LINE CONTROL REGISTER (LCR)
  133.     ENDIF
  134. ;
  135.     IF    DCH
  136. MODCTLP    EQU    92H    ;D. C. HAYES VALUES
  137. MODSNDB    EQU    2    ;BIT TO TEST FOR SEND
  138. MODSNDR    EQU    2    ;VALUE WHEN READY
  139. MODRCVB    EQU    1    ;BIT TO TEST FOR RECEIVE
  140. MODRCVR    EQU    1    ;VALUE WHEN READY
  141. MODDCDB    EQU    40H    ;CARRIER DETECT BIT
  142. MODDCDA    EQU    40H    ;VALUE WHEN ACTIVE
  143. MODPARE    EQU    04H    ;VALUE FOR PARITY ERROR
  144. MODOVRE    EQU    10H    ;VALUE FOR OVERRUN ERROR
  145. MODFRME    EQU    08H    ;VALUE FOR FRAMING ERROR
  146. MODDATP    EQU    90H    ;DATA PORT IN PORT
  147. MODDATO    EQU    90H    ;DATA OUT PORT
  148. MODCTL2    EQU    91H    ;SECOND CTL PORT
  149.     ENDIF
  150. ;
  151. ; If you are using an external modem (not S-100 plug-in) change these
  152. ; equates for your modem port requirements
  153. ;
  154.     IF    EXTMOD
  155. MODCTLP    EQU    0C3H    ;PUT YOUR MODEM STATUS PORT HERE
  156. MODSNDB    EQU    10H    ;YOUR BIT TO TEST FOR SEND
  157. MODSNDR    EQU    10H    ;YOUR VALUE WHEN READY
  158. MODRCVB    EQU    01H    ;YOUR BIT TO TEST FOR RECEIVE
  159. MODRCVR    EQU    01H    ;YOUR VALUE WHEN READY
  160. MODDCDB    EQU    02H    ;CARRIER DETECT BIT
  161. MODDCDA    EQU    02H    ;VALUE WHEN ACTIVE
  162. MODDATP    EQU    0C0H    ;YOUR MODEM DATA IN PORT
  163. MODDATO    EQU    0C2H    ;YOUR MODEM DATA OUT PORT
  164. MODCTL2    EQU    0C1H    ;SECOND CONTROL/STATUS PORT.
  165.     ENDIF        ;END OF EXTERNAL MODEM EQUATES
  166. ;
  167. ;
  168. ;-----------------------------------------------------------------------
  169. ;
  170. ;            --- End of Options ---
  171. ;
  172. ;-----------------------------------------------------------------------
  173. ;
  174. ;
  175. ERRLIM    EQU    10    ;MAX ALLOWABLE ERRORS (10 STANDARD)
  176. ;
  177. ;
  178. ; Define ASCII characters used
  179. ;
  180. SOH    EQU    1    ;START OF HEADER
  181. EOT    EQU    4    ;END OF TRANSMISSION
  182. ACK    EQU    6    ;ACKNOWLEDGE
  183. NAK    EQU    15H    ;NEG ACKNOWLEDGE
  184. CRC    EQU    'C'    ;CRC REQUEST CHARACTER
  185. CAN    EQU    18H    ;CONTROL-X FOR CANCEL
  186. LF    EQU    10    ;LINEFEED
  187. CR    EQU    13    ;CARRIAGE RETURN
  188.     IF    STDCPM
  189. BASE    EQU    0    ;CP/M BASE ADDRESS
  190.     ENDIF
  191. ;
  192.     IF    ALTCPM
  193. BASE    EQU    4200H    ;ALTERNATE CP/M BASE ADDRESS
  194.     ENDIF
  195. ;
  196.     ORG    BASE+100H
  197. ;
  198. ;
  199.     JMP    BEGIN
  200.  
  201. SPEED    DB    1    ;SPEED FOR FILE TIME TRANSFER WITHOUT AUTO-SET
  202. ;            ;0=110, 1=300, 2=450, 3=600, 4=710, 5=1200
  203. ;
  204. ; INIT PRIVATE STACK
  205. ;
  206.  
  207. BEGIN:
  208.     LXI    H,0        ;HL=0
  209.     DAD    SP        ;HL=STACK FROM CP/M
  210.     SHLD    STACK        ;   SAVE IT
  211.     LXI    SP,STACK     ;SP=MY STACK
  212.     CALL    ILPRT    ;PRINT:
  213.     DB    CR,LF
  214.     DB    'LMODEM V'
  215.     DB    VERSION+'0'    ;VERSION #
  216.     DB    '.',MODLEV+'0'    ;MODIFICATION LEVEL
  217.     DB    '[CRC capable]',CR,LF,0
  218.     MVI    A,'S'
  219.     PUSH    PSW        ;SAVE OPTION
  220. ;
  221. ;
  222. ; MOVE THE FILENAME FROM FCB2 TO MEMFCB
  223. ;
  224.     CALL    MOVEFCB
  225. ;
  226. ;
  227. ; GOBBLE UP GARBAGE CHARACTERS FROM THE LINE PRIOR TO RECEIVER OR SEND
  228. ;
  229.     IN    MODDATP
  230.     IN    MODDATP
  231. ;
  232.     POP    PSW        ;GET OPTION
  233.     IF    LOGCAL
  234.     PUSH    PSW        ;BUT SAVE IT
  235.     ENDIF
  236. ;
  237.     STA    OPTSAV        ;SAVE OPTION IN CASE WE LOSE CARRIER
  238.     JMP    SENDFIL
  239. ;
  240.     IF    LOGCAL
  241. ;
  242.     MACLIB SEQIO22
  243. ;
  244. BSIZE    EQU    80H
  245. FILERR    SET    EXIT
  246. BUFFERS    SET    DBUF
  247. ;
  248. ;
  249. ; THE FOLLOWING ALLOCATIONS ARE USED BY THE 'FILE' MACROS
  250. ;
  251. DEFAULT$USER:
  252.     DB    LASTUSR
  253. CUR$USER:
  254.     DB    0FFH
  255. DEFAULT$DISK:
  256.     DB    DEFDRV-'A'
  257. CUR$DISK:
  258.     DB    0FFH
  259. PGSIZE:
  260.     DW    0
  261. LOGCALL:
  262.     FILE    INFILE,CALLER,,LASTCALR,,BSIZE,,PUBLIC,TRUE
  263. ;
  264.     MVI    A,RECU
  265.     STA    DEFAULT$USER
  266. ;
  267.     FILE    APPEND,LOG,,LOG,SYS,BSIZE,,PUBLIC,TRUE
  268. ;
  269.     POP    PSW        ;GET OPTION
  270.     PUT    LOG        ;PUT IT OUT TO LOG
  271.     LDA    MSPEED        ;GET SPEED FACTOR
  272.     ADI    30H
  273.     PUT    LOG        ;PUT OUT A SINGLE LETTER CODE
  274.     LDA    PGSIZE        ;NOW THE PRGM SIZE IN MINS TRANSFER TIME
  275.     CALL    PNDEC
  276.     MVI    A,' '        ;BLANK
  277.     PUT    LOG
  278. ;
  279. ;
  280. ; LOG THE DRIVE AND USER AREA AS A PROMPT
  281. ;
  282.     LDA    FCB
  283.     ORA    A
  284.     JNZ    WDRV
  285.     MVI    C,25
  286.     CALL    @BDOS
  287.     INR    A
  288. WDRV:
  289.     ADI    'A'-1
  290.     PUT    LOG
  291.     MVI    C,32        ;NOW THE USER AREA (AS DECIMAL NUMBER)
  292.     MVI    E,0FFH
  293.     CALL    @BDOS
  294.     CALL    PNDEC
  295.     MVI    A,'>'        ;MAKE IT LOOK LIKE A PROMPT
  296.     PUT    LOG
  297.     LXI    H,FCB+1        ;NOW THE NAME OF THE FILE
  298.     MVI    B,11
  299.     CALL    PUTSTR
  300.     MVI    A,' '        ;BLANK
  301.     PUT    LOG
  302. CLOOP:
  303.     GET    CALLER        ;AND THE CALLER
  304.     CPI    EOF
  305.     JZ    QUIT
  306.     PUT    LOG
  307.     JMP    CLOOP
  308. ;.....
  309. ;
  310. ;
  311. PNDEC:
  312.     CPI    10        ;TWO COLUMN DECIMAL FORMAT ROUTINE
  313.     JC    ONE        ;ONE OR TWO DIGITS TO AREA #?
  314.     JMP    TWO
  315. ;...
  316. ;
  317. ;
  318. ONE:
  319.     PUSH    PSW
  320.     MVI    A,'0'
  321.     PUT    LOG
  322.     POP    PSW
  323. TWO:
  324.     MVI    H,0
  325.     MOV    L,A
  326.     CALL    DECOT
  327.     RET
  328. ;.....
  329. ;
  330. ;
  331. DECOT:
  332.     PUSH    B
  333.     PUSH    D
  334.     PUSH    H
  335.     LXI    B,-10
  336.     LXI    D,-1
  337. ;
  338. DECOT2:    DAD    B
  339.     INX    D
  340.     JC    DECOT2
  341.     LXI    B,10
  342.     DAD    B
  343.     XCHG
  344.     MOV    A,H
  345.     ORA    L
  346.     CNZ    DECOT
  347.     MOV    A,E
  348.     ADI    '0'
  349.     PUT    LOG
  350.     POP    H
  351.     POP    D
  352.     POP    B
  353.     RET
  354. ;.....
  355. ;
  356. ;
  357. PUTSTR:
  358.     MOV    A,M
  359.     PUSH    H
  360.     PUSH    B
  361.     PUT    LOG
  362.     POP    B
  363.     POP    H
  364.     INX    H
  365.     DCR    B
  366.     JNZ    PUTSTR
  367.     RET
  368. ;.....
  369. ;
  370. ;
  371. QUIT:    FINIS    LOG
  372.     JMP    EXIT
  373. ;.....
  374. ;
  375.     ENDIF            ;LOGCAL
  376. ;
  377. ;
  378. ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  379. ;
  380. ;        SENDFIL: SENDS A MEMBER OF A LBR FILE
  381. ;
  382. ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  383. ;
  384. ; The LBR member specified in the LMODEM command is transferred over the
  385. ; phone to another computer running MODEM with the "R" (receive) option.
  386. ; The data is sent one record at a time with headers and checksums, and
  387. ; re transmission on errors.  
  388. ;
  389. SENDFIL:
  390.     CALL    TRAP        ;CHECK FOR NO NAME OR AMBIG. NAME
  391.     CALL    OPENFIL     ;OPEN THE FILE
  392.     MVI    E,80        ;WAIT 80 SEC FOR INITIAL NAK
  393.     CALL    WAITNAK
  394. ;
  395. SENDLP:
  396.     CALL    RDSECT        ;READ A SECTOR    
  397.     JC    SENDEOF        ;SEND 'EOF' IF DONE
  398.     CALL    INCRSNO     ;BUMP SECTOR #
  399.     XRA    A        ;ZERO ERROR COUNT
  400.     STA    ERRCT
  401. ;
  402. SENDRPT:
  403.     CALL    SENDHDR     ;SEND A HEADER
  404.     CALL    SENDSEC     ;SEND DATA SECTOR
  405.     LDA    CRCFLG        ;GET CRC FLAG
  406.     ORA    A        ;CRC IN EFFECT?
  407.     CZ    SENDCRC        ;YES, SEND CRC
  408.     CNZ    SENDCKS     ;NO, SEND CKSUM
  409.     CALL    GETACK        ;GET THE ACK
  410.     JC    SENDRPT     ;REPEAT IF NO ACK
  411.     lhld    rcnt
  412.     mov    a,h
  413.     ora    l
  414.     jz    sendeof
  415.     dcx    h
  416.     shld    rcnt
  417.     JMP    SENDLP        ;LOOP UNTIL EOF
  418. ;.....
  419. ;
  420. ;
  421. ; FILE SENT, SEND EOT's
  422. ;
  423. SENDEOF:
  424.     MVI    A,EOT        ;SEND AN 'EOT'
  425.     CALL    SEND
  426.     CALL    GETACK        ;GET THE ACK
  427.     JC    SENDEOF     ;LOOP IF NO ACK
  428.     JMP    EXITLG        ;ALL DONE
  429. ;.....
  430. ;
  431. ;
  432. ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  433. ;
  434. ;            SUBROUTINES
  435. ;
  436. ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  437. ;
  438. ;
  439. ; ---> TRAP:  Check for no file name or ambiguous name
  440. ;
  441. TRAP    LXI    H,FCB+1     ;POINT TO FILE NAME
  442.     MOV    A,M        ;GET FIRST CHAR OF FILE NAME
  443.     CPI    ' '        ;ANY THERE?
  444.     JNZ    ATRAP        ;YES, CHECK FOR AMBIGOUS FILE NAME
  445.     CALL    ERXIT        ;PRINT MSG, EXIT
  446.     DB    CR,LF,'++No File Name Specified++',CR,LF
  447.     DB    'SYNTAX:',CR,LF
  448.     DB    'LMODEM <library> <member>',CR,LF
  449.     DB    'Where <library> is the file name for a '
  450.     DB    '.LBR file, i.e. "TEST.LBR" or "TEST"',CR,LF
  451.     DB    'and <member> is the FULL file name for a '
  452.     DB    'member of that LBR file.',CR,LF
  453.     DB    '(Find <member> with LDIR <library>).',CR,LF,'$'
  454. ;
  455. ATRAP:
  456.     MVI    B,11        ;11 CHARS TO CHECK
  457. TRLOOP:
  458.     MOV    A,M        ;GET CHAR FROM FCB
  459.     CPI    '?'        ;AMBIGUOUS?
  460.     JZ    TRERR        ;YES, EXIT WITH ERROR MSG
  461.     INX    H        ;POINT TO NEXT CHAR
  462.     DCR    B        ;ONE LESS TO GO
  463.     JNZ    TRLOOP        ;NOT DONE, CHECK SOME MORE
  464. ;
  465. ; Now see if he specified a LBR file.
  466. ; If not and if the type is empty, make it LBR.
  467. ;
  468.     LXI    H,FCB+9
  469.     MOV    A,M
  470.     CPI    ' '
  471.     JZ    NOXT        ;no extension in file name, make one.
  472.     RET            ;NO AMBIGUOUS NAME, RETURN
  473. ;
  474. ; NOXT: The file he specified didn't have an extension. Make it LBR.
  475. ;
  476. NOXT:    LXI    D,LBRTYP
  477.     MVI    B,3
  478. NXLP:    LDAX    D
  479.     MOV    M,A
  480.     INX    D
  481.     INX    H
  482.     DCR    B
  483.     JNZ    NXLP
  484.     RET
  485. ;
  486. LBRTYP:    DB    'LBR'
  487. ;
  488. TRERR:
  489.     CALL    ERXIT        ;PRINT MSG, EXIT
  490.     DB    CR,LF,'++Wild Card Options not allowed++',CR,LF,'$'
  491. ;
  492. ;
  493. ; ---> SENDHDR:  Send the sector header
  494. ;
  495. ; SEND: (SOH) (block #) (complemented block #)
  496. ;
  497. SENDHDR:
  498.     MVI    A,SOH        ;SEND
  499.     CALL    SEND        ;   SOH,
  500.     LDA    SECTNO        ;THEN SEND
  501.     CALL    SEND        ;   SECTOR #
  502.     LDA    SECTNO        ;THEN SECTOR #
  503.     CMA            ;   COMPLEMENTED
  504.     JMP    SEND        ;   SECTOR #
  505. ;.....
  506. ;
  507. ;
  508. ; ---> SENDSEC:  Send the data sector
  509. ;
  510. SENDSEC:
  511.     MVI    C,0        ;INIT CKSUM
  512.     CALL    CLRCRC        ;CLEAR THE CRC COUNTER
  513.     LXI    H,BASE+80H    ;POINT TO BUFFER
  514. SENDC:
  515.     MOV    A,M        ;GET A CHAR
  516.     CALL    SEND        ;SEND IT
  517.     INR    L        ;POINT TO NEXT CHAR
  518.     JNZ    SENDC        ;LOOP IF <100H
  519.     RET            ;FROM SENDSEC
  520. ;.....
  521. ;
  522. ;
  523. ; ---> SENDCKS:  Send the checksum
  524. ;
  525. SENDCKS:
  526.     MOV    A,C        ;SEND THE
  527.     JMP    SEND        ;   CHECKSUM
  528. ;.....
  529. ;
  530. ;
  531. ; ---> SENDCRC:  Send the two Cyclic Redundancy Check characters.  Call
  532. ;         FINCRC to calculate the CRC which will be in 'DE' upon
  533. ;         return.
  534. ;
  535. SENDCRC:
  536.     CALL    FINCRC        ;CALC THE CRC FOR THIS SECTOR
  537.     MOV    A,D        ;PUT FIRST CRC BYTE IN ACCUM
  538.     CALL    SEND        ;SEND IT
  539.     MOV    A,E        ;PUT SECOND CRC BYTE IN ACCUM
  540.     CALL    SEND        ;SEND IT
  541.     XRA    A        ;SET ZERO RETURN CODE
  542.     RET
  543. ;.....
  544. ;
  545. ;
  546. ; ---> GETACK:  Get the ACK on the sector
  547. ;
  548. ; Returns with carry clear if ACK received.  If an ACK is not received,
  549. ; the error count is incremented, and if less than "ERRLIM", carry is
  550. ; set and control returns.  If the error count is at "ERRLIM", the pro-
  551. ; gram aborts.
  552. ;
  553. GETACK:
  554.     MVI    B,10        ;WAIT 10 SECONDS MAX
  555.     CALL    RECVDG        ;RECV W/GARBAGE COLLECT
  556.     JC    GETATOT     ;TIMED OUT
  557.     CPI    ACK        ;OK? (CARRY OFF IF =)
  558.     RZ            ;YES, RET FROM GETACK
  559. ;
  560. ;
  561. ; Timeout or error on ACK - bump error count
  562. ;
  563. ACKERR:
  564.     LDA    ERRCT        ;GET COUNT
  565.     INR    A        ;BUMP IT
  566.     STA    ERRCT        ;SAVE BACK
  567.     CPI    ERRLIM        ;AT LIMIT?
  568.     RC            ;NOT AT LIMIT
  569.     CALL    ERXIT
  570.     DB    CR,LF,'++Can''t send sector - Aborting++',CR,LF,'$'
  571. ;
  572. ; Timeout getting ACK
  573. ;
  574. GETATOT:
  575.     JMP    ACKERR    ;NO MSG
  576. ABORT:
  577.     LXI    SP,STACK
  578. ABORTL:
  579.     MVI    B,1        ;1 SECOND WITHOUT CHARACTERS
  580.     CALL    RECV
  581.     JNC    ABORTL        ;LOOP UNTIL SENDER DONE
  582.     MVI    A,CAN        ;CTL- X
  583.     CALL    SEND        ;STOP SENDING END
  584. ABORTW:
  585.     MVI    B,1        ;1 SECOND WITHOUT CHRACTERS
  586.     CALL    RECV
  587.     JNC    ABORTW        ;LOOP UNTIL SENDER DONE
  588.     MVI    A,' '        ;GET A SPACE...
  589.     CALL    SEND        ;TO CLEAR OUT CONTROL X
  590.     CALL    ERXIT        ;EXIT WITH ABORT MSG
  591.     DB    CR,LF,'++LMODEM Program Cancelled++',CR,LF,'$'
  592. ;
  593. ;
  594. ; ---> INCRSNO:  Increment sector #
  595. ;
  596. INCRSNO:
  597.     PUSH    H        ;INCREMENT RECORD NUMBER
  598.     LHLD    SECTNO
  599.     INX    H
  600.     SHLD    SECTNO
  601.     LXI    H,CONOUT    ;CHECK FOR OPTIONAL COUNT TO CONSOLE
  602.     MOV    A,H
  603.     ORA    L        ;IF 0, THEN NOPE, SO
  604.     POP    H
  605.     RZ            ;RETURN
  606. ;...
  607. ;
  608. ;
  609. DSPLY:
  610.     MVI    A,1
  611.     STA    CONONL        ;SET LOCAL ONLY
  612.     CALL    ILPRT
  613.     DB    CR,'Record #',0
  614.     LHLD    SECTNO
  615.     CALL    DECOUT
  616.     CALL    ILPRT
  617.     DB    '  (',0
  618.     CALL    DHXOUT
  619.     CALL    ILPRT
  620.     DB    'H)',0
  621.     ORA    A
  622.     STA    CONONL        ;RESET LOCAL ONLY
  623.     RET
  624. ;.....
  625. ;
  626. ; ---> OPENFIL:  Opens the file to be sent
  627. ;
  628. OPENFIL:
  629.     XRA    A        ;SET EXT & REC # TO 0 FOR PROPER OPEN
  630.     STA    FCBEXT
  631.     STA    FCBSNO
  632.     LXI    D,FCB        ;POINT TO FILE
  633.     MVI    C,OPEN        ;GET FUNCTION
  634.     CALL    BDOS        ;OPEN IT
  635.     INR    A        ;OPEN OK?
  636.     JNZ    OPENOK        ;   YES
  637.     CALL    ERXIT        ;   NO, ABORT
  638.     DB    CR,LF,'++Unable to open the file++',CR,LF,'$'
  639. ;
  640. ;
  641. ; Check for distribution-protected file
  642. ;
  643. OPENOK:
  644.     LDA    FCB+1        ;FIRST CHAR OF FILE NAME
  645.     ANI    80H        ;CHECK BIT 7
  646.     JNZ    OPENOT        ;IF ON, FILE CAN'T BE SENT
  647.     LDA    FCB+2        ;ALSO CHECK "F2" FOR TAB
  648.     ANI    80H        ;IS IS SET?
  649.     JZ    OPENOK2        ;IF NOT, OK TO SEND FILE
  650. OPENOT:
  651.     CALL    ERXIT    ;EXIT W/MESSAGE
  652.     DB    CR,LF,'++File is Not for Distribution, Sorry++'
  653.     DB    CR,LF,'$'
  654. OPENOK2:
  655.     LXI    D,80H
  656.     MVI    C,STDMA
  657.     CALL    BDOS
  658.     MVI    C,READ
  659.     LXI    D,FCB
  660.     CALL    BDOS
  661.     LHLD    8EH
  662.     SHLD    DIRSZ
  663.     LXI    D,MEMFCB
  664.     LDAX    D
  665.     CPI    ' '
  666.     JNZ    MOK
  667.     CALL    ERXIT
  668.     DB    '++No member name specified!++',CR,LF,'$'
  669. ;
  670. MOK:    LXI    H,80H
  671.     MOV    A,M
  672.     ORA    A
  673.     JZ    CKDIR        ;check directory present?
  674. BADLBR:    CALL    ERXIT
  675.     DB    '++The file specified is not recognized '
  676.     DB    'as LBR file!++',CR,LF,'$'
  677. ;
  678. ; CKDIR - check to see if there indeed is a LBR file
  679. ;      directory and barf if not!
  680. ;
  681. CKDIR:    MVI    B,11        ;len of file name
  682.     MVI    A,' '        ;space
  683.     INX    H
  684. CKDLP:    CMP    M
  685.     JNZ    BADLBR
  686.     DCR    B
  687.     INX    H
  688.     JNZ    CKDLP
  689. ;
  690. ; The first entry in the LBR directory is indeed blank.
  691. ; Now see if the directory size is >0
  692. ;
  693.     MOV    D,M
  694.     INX    H
  695.     MOV    A,M
  696.     ORA    D
  697.     JNZ    BADLBR
  698.     INX    H
  699.     MOV    A,M
  700.     INX    H
  701.     ORA    M
  702.     JZ    BADLBR
  703.     LXI    H,80H
  704. ;
  705. ; The next routine checks the LBR directory for the
  706. ; specified member name 1 sector at a time.
  707. ;
  708. CMLP:    MOV    A,M
  709.     ORA    A
  710.     MVI    B,11
  711.     INX    H
  712.     JNZ    NOMTCH
  713. CKLP:    LDAX    D
  714.     CMP    M
  715.     JNZ    NOMTCH
  716.     INX    H
  717.     INX    D
  718.     DCR    B
  719.     JNZ    CKLP
  720.     MOV    E,M
  721.     INX    H
  722.     MOV    D,M
  723.     XCHG
  724.     SHLD    INDEX
  725.     XCHG
  726.     INX    H
  727.     MOV    E,M
  728.     INX    H
  729.     MOV    D,M
  730.     XCHG
  731.     DCX    H
  732.     SHLD    RCNT
  733.     LHLD    INDEX
  734.     DAD    H
  735.     MOV    A,H
  736.     STA    FCBEXT
  737.     MOV    A,L
  738.     RRC
  739.     STA    FCBSNO
  740.     LXI    D,FCB
  741.     MVI    C,OPEN
  742.     CALL    BDOS
  743.     CPI    0FFH
  744.     JZ    WHAT
  745.     JMP    OPENOK3
  746. ;
  747. WHAT:    CALL    ERXIT
  748.     DB    '++Impossible error - notify SYSOP++',CR,LF,'$'
  749. ;
  750. NOMTCH:    INX    H
  751.     DCR    B
  752.     JNZ    NOMTCH
  753.     LXI    B,20
  754.     DAD    B
  755.     LXI    D,MEMFCB
  756.     MOV    A,H
  757.     ORA    A
  758.     JZ    CMLP
  759.     LHLD    DIRSZ
  760.     MOV    A,H
  761.     ORA    L
  762.     JZ    NFOUND
  763.     DCX    H
  764.     SHLD    DIRSZ
  765.     MVI    C,READ
  766.     LXI    D,FCB
  767.     CALL    BDOS
  768.     LXI    H,80H
  769.     LXI    D,MEMFCB
  770.     JMP    CMLP
  771. ;
  772. NFOUND:    CALL    ERXIT
  773.     DB    '++Member file not in library++',CR,LF
  774.     DB    'Run LDIR on the file and try again.',CR,LF,'$'
  775. ;
  776. OPENOK3:
  777.     CALL    ILPRT    ;PRINT:
  778.     DB    'File Open:  ',0
  779.     LHLD    RCNT        ;GET RECORD COUNT
  780.     INX    H
  781.     CALL    DECOUT        ;PRINT DECIMAL NUMBER OF RECORDS
  782.     CALL    ILPRT
  783.     DB    ' (',0
  784.     CALL    DHXOUT        ;NOW PRINT SIZE IN HEX
  785.     CALL    ILPRT
  786.     DB    ' Hex) Records',CR,LF
  787.     DB    'Send Time:  ',0
  788.  
  789.     IF    LSPEED
  790.     LDA    MSPEED        ;GET THE SPEED INDICATOR
  791.     ENDIF
  792. ;
  793.     IF    NOT LSPEED
  794.     LDA    SPEED        ;DEFAULT TO PRESET SPEED AT 0103H
  795.     ENDIF
  796. ;    
  797.     LXI    D,0
  798.     MOV    E,A        ;SET UP FOR TABLE ACCESS
  799.     LXI    H,BTABLE    ;POINT TO BAUD FACTOR TABLE
  800.     DAD    D        ;INDEX TO PROPER FACTOR
  801.     MOV    A,M        ;FACTOR IN 'A'
  802. ;    
  803.     LHLD    RCNT        ;GET NUMBER OF RECORDS
  804.     INX    H
  805.     CALL    DIVHLA        ;DIVIDE HL BY VALUE IN A (RECORDS/MIN)    
  806.     PUSH    H
  807. ;
  808.     IF    LOGCAL
  809.     SHLD    PGSIZE
  810.     ENDIF
  811. ;
  812.     MVI    H,0
  813.     CALL    DECOUT        ;PRINT DECIMAL NUMBER OF MINUTES
  814.     CALL    ILPRT
  815.     DB    ' mins, ',0
  816.     LXI    H,SECTBL    ;POINT TO DIVISORS FOR SECONDS CALC.
  817.     LXI    D,0
  818. ;
  819.     IF    LSPEED
  820.     LDA    MSPEED        ;GET INDEX FOR BAUD RATE
  821.     ENDIF
  822. ;
  823.     IF    NOT LSPEED
  824.     LDA    SPEED
  825.     ENDIF
  826. ;
  827.     MOV    E,A
  828.     DAD    D        ;INDEX INTO TABLE
  829.     MOV    A,M        ;GET MULTIPLIER
  830.     POP    H        ;GET REMAINDER
  831.     CALL    MULHA        ;MULTIPLY 'H' BY 'A'
  832.     CALL    SHFTHL
  833.     CALL    SHFTHL
  834.     CALL    SHFTHL
  835.     CALL    SHFTHL    
  836. ;
  837.     MVI    H,0
  838.     CALL    DECOUT
  839. ;
  840.     IF    LSPEED
  841.     LDA    MSPEED        ;GET BAUD RATE CODE
  842.     ENDIF
  843. ;
  844.     IF    NOT LSPEED
  845.     LDA    SPEED        ;DEFAULT TO PRESET SPEED AT 0103H
  846.     ENDIF
  847. ;
  848.     CPI    0        ;110 BAUD?
  849.     JNZ    MS300        ;NO-CHECK 300
  850. MS110:
  851.     CALL    ILPRT
  852.     DB    ' secs at 110 Baud',CR,LF,0
  853.     JMP    MSCTLX
  854. ;...
  855. ;
  856. ;
  857. MS300:
  858.     CPI    1        ;300 BAUD?
  859.     JNZ    MS450        ;NO-CHECK 450
  860.     CALL    ILPRT
  861.     DB    ' secs at 300 Baud',CR,LF,0
  862.     JMP    MSCTLX
  863. ;...
  864. ;
  865. ;
  866. MS450
  867.     CPI    2        ;450 BAUD?
  868.     JNZ    MS600        ;NO-CHECK 600
  869.     CALL    ILPRT
  870.     DB    ' secs at 450 Baud',CR,LF,0
  871.     JMP    MSCTLX
  872. ;.....
  873. ;
  874. ;
  875. MS600:
  876.     CPI    3        ;600 BAUD?
  877.     JNZ    MS710        ;NO-CHECK 710
  878.     CALL    ILPRT
  879.     DB    ' secs at 600 Baud',CR,LF,0
  880.     JMP    MSCTLX
  881. ;...
  882. ;
  883. ;
  884. MS710:
  885.     CPI    4        ;710 BAUD?
  886.     JNZ    MS1200        ;NO-MUST BE 1200
  887.     CALL    ILPRT
  888.     DB    ' secs at 710 Baud',CR,LF,0
  889.     JMP    MSCTLX
  890. ;...
  891. ;
  892. ;
  893. MS1200:
  894.     CALL    ILPRT        ;MUST BE 1200 - NO OTHERS SUPPORTED
  895.     DB    ' secs at 1200 Baud',CR,LF,0
  896. ;...
  897. ;
  898. ;
  899. MSCTLX    CALL    ILPRT
  900.     DB    'Use CTL-X to Cancel',CR,LF,0
  901.     RET
  902. ;...
  903. ;
  904. ;
  905. BTABLE:    DB    5,13,19,25,29,49,0
  906. SECTBL:    DB    192,74,51,38,33,20,0
  907. ;...
  908. ;
  909. ;
  910. ; ---> DIVHL-A:  Divides 'HL' by value in 'A',
  911. ;     UPON EXIT: L=QUOTIENT,H=REMAINDER
  912. ;
  913. DIVHLA:
  914.     PUSH    B
  915.     MVI    B,8        ;SHIFT FACTOR TO 'B'
  916.     MOV    C,A        ;DIVISOR TO 'C'
  917. DIV2:
  918.     XRA    A        ;CLEAR CARRY FLAG AND ACCUMULATOR
  919.     DAD    H
  920.     MOV    A,H
  921.     SUB    C
  922.     JM    DIV3        ;DONT BORROW ON NEG RESULTS
  923.     MOV    H,A
  924.     MOV    A,L
  925.     ORI    1        ;BORROW 1
  926.     MOV    L,A
  927. DIV3:
  928.     DCR    B
  929.     JNZ    DIV2
  930.     POP    B
  931.     RET
  932. ;...
  933. ;
  934. ;
  935. ; ---> MULHA:  Multiply the value in 'H' by the value in 'A'
  936. ;     Return with answer in 'HL'.
  937. ;
  938. MULHA:
  939.     MOV    B,A        ;PUT LOOP COUNT IN 'B'
  940.     MVI    D,0
  941.     MOV    E,H
  942.     MOV    L,H
  943.     MVI    H,0
  944. MULLP:
  945.     DCR    B
  946.     RZ
  947.     DAD    D
  948.     JMP    MULLP
  949.     RET
  950. ;
  951. ;
  952. ; Shift the 'HL' pair one bit to the right
  953. ;
  954. SHFTHL:
  955.     MOV    A,L
  956.     RAR
  957.     MOV    L,A
  958.     ORA    A        ;CLEAR THE CARRY BIT
  959.     MOV    A,H
  960.     RAR
  961.     MOV    H,A
  962.     RNC
  963.     MVI    A,80h
  964.     ORA    L
  965.     MOV    L,A
  966.     RET
  967. ;.....
  968. ;
  969. ; ---> DECOUT:  Decimal output routine
  970. ;
  971. DECOUT:
  972.     PUSH    B
  973.     PUSH    D
  974.     PUSH    H
  975.     LXI    B,-10
  976.     LXI    D,-1
  977. DECOU2:
  978.     DAD    B
  979.     INX    D
  980.     JC    DECOU2
  981.     LXI    B,10
  982.     DAD    B
  983.     XCHG
  984.     MOV    A,H
  985.     ORA    L
  986.     CNZ    DECOUT
  987.     MOV    A,E
  988.     ADI    '0'
  989.     CALL    CTYPE
  990.     POP    H
  991.     POP    D
  992.     POP    B
  993.     RET
  994. ;.....
  995. ;
  996. ;
  997. ; ---> DHXOUT: Double precision hex output routine.
  998. ;     Call with hex value in 'HL'.
  999. ;
  1000. DHXOUT:
  1001.     PUSH    H        ;SAVE H,L
  1002.     PUSH    PSW        ;SAVE A
  1003.     MOV    A,H        ;GET MS BYTE
  1004.     CALL    HEXO        ;OUTPUT HIGH ORDER BYTE
  1005.     MOV    A,L        ;GET LS BYTE
  1006.     CALL    HEXO        ;OUTPUT LOW ORDER BYTE
  1007.     POP    PSW        ;RESTORE A
  1008.     POP    H        ;RESTORE H,L
  1009.     RET            ;RETURN TO CALLER
  1010. ;
  1011. ;
  1012. ; ---> RDSECT:  Reads a sector
  1013. ;
  1014. ; For speed, this routine buffers up 16 sectors at a time.
  1015. ;
  1016. RDSECT:    LDA    SECNBF        ;GET # SECT IN BUFF
  1017.     DCR    A        ;DECREMENT
  1018.     STA    SECNBF        ;   IT
  1019.     JM    RDBLOCK     ;EXHAUSTED?  NEED MORE
  1020.     LHLD    SECPTR        ;GET POINTER
  1021.     LXI    D,BASE+80H    ;TO DATA
  1022.     CALL    MOVE128     ;MOVE TO BUFFER
  1023.     SHLD    SECPTR        ;SAVE BUFFER POINTER
  1024.     RET            ;FROM "READSEC"
  1025. ;.....
  1026. ;
  1027. ;
  1028. ; Buffer is empty - read in another block of 16
  1029. ;
  1030. RDBLOCK:
  1031.     LDA    EOFLG        ;GET 'EOF' FLAG
  1032.     CPI    1        ;IS IT SET?
  1033.     STC            ;TO SHOW 'EOF'
  1034.     RZ            ;GOT 'EOF'
  1035.     MVI    C,0        ;SECTORS IN BLOCK
  1036.     LXI    D,DBUF        ;TO DISK BUFFER
  1037. ;
  1038. RDSECLP:
  1039.     PUSH    B
  1040.     PUSH    D
  1041.     MVI    C,STDMA     ;SET DMA ADDRESS
  1042.     CALL    BDOS
  1043.     LXI    D,FCB
  1044.     MVI    C,READ
  1045.     CALL    BDOS
  1046.     POP    D
  1047.     POP    B
  1048.     ORA    A        ;READ OK?
  1049.     JZ    RDSECOK     ;YES
  1050.     DCR    A        ;'EOF'?
  1051.     JZ    REOF        ;GOT 'EOF'
  1052. ;
  1053. ;
  1054. ; Read error
  1055. ;
  1056.     CALL    ERXIT
  1057.     DB    CR,LF,'++File Read Error++',CR,LF,'$'
  1058. ;
  1059. RDSECOK:
  1060.     INR    C
  1061.     LXI    H,80H        ;ADD LENGTH OF ONE SECTOR
  1062.     DAD    D        ;   TO NEXT BUFF
  1063.     XCHG            ;BUFF TO DE
  1064.     MOV    A,C        ;GET COUNT
  1065.     CPI    16        ;DONE?
  1066.     JZ    RDBFULL     ;   YES, BUFF IS FULL
  1067.     JMP    RDSECLP     ;READ MORE
  1068. ;...
  1069. ;
  1070. ;
  1071. REOF:
  1072.     MVI    A,1
  1073.     STA    EOFLG        ;SET EOF FLAG
  1074.     MOV    A,C
  1075. ;
  1076. ;
  1077. ; Buffer is full, or got EOF
  1078. ;
  1079. RDBFULL:
  1080.     STA    SECNBF        ;STORE SECTOR COUNT
  1081.     LXI    H,DBUF        ;INIT BUFFER POINTEAR
  1082.     SHLD    SECPTR
  1083.     LXI    D,BASE+80H    ;RESET DMA ADDRESS 
  1084.     MVI    C,STDMA
  1085.     CALL    BDOS
  1086.     JMP    RDSECT        ;PASS SECT TO CALLER
  1087. ;
  1088. ;---->    RECV:  Receive a character
  1089. ;
  1090. ; Timeout time is in B, in seconds.  Entry via "RECVDG" deletes garbage
  1091. ; characters on the line.  For example, having just sent a sector, 
  1092. ; calling RECVDG will delete any line-noise-induced characters "long"
  1093. ; before the ACK/NAK would be received.
  1094. ;
  1095. RECVDG:
  1096.     IN    MODDATP     ;GET A CHAR
  1097.     IN    MODDATP     ;   TOTALLY PURGE UART
  1098. RECV:
  1099.     PUSH    D        ;SAVE
  1100. ;
  1101.     IF    FASTCLK     ;4MHZ?
  1102.     MOV    A,B        ;GET TIME REQUEST
  1103.     ADD    A        ;DOUBLE IT
  1104.     MOV    B,A        ;NEW TIME IN B
  1105.     ENDIF
  1106. MSEC:
  1107.     LXI    D,50000     ;1 SECOND DCR COUNT
  1108. ;
  1109.     IF    NOT DCH
  1110. MWTI:
  1111.     IN    MODCTLP     ;CHECK STATUS
  1112.     ENDIF
  1113. ;
  1114.     IF    DCH
  1115. MWTI:
  1116.     IN    MODCTL2     ;CHECK STATUS
  1117.     ENDIF
  1118. ;
  1119.     IF    PMMI AND FRNTPNL
  1120.     OUT    PANEL        ;DISPLAY STATUS ON PANEL LIGHTS
  1121.     ENDIF
  1122. ;
  1123.     ANI    MODRCVB     ;ISOLATE BIT
  1124.     CPI    MODRCVR     ;READY?
  1125.     JZ    MCHAR        ;GOT CHAR
  1126.     DCR    E        ;COUNT
  1127.     JNZ    MWTI        ;   DOWN
  1128.     DCR    D        ;   FOR
  1129.     JNZ    MWTI        ;   TIMEOUT
  1130.     DCR    B        ;MORE SECONDS?
  1131.     JNZ    MSEC        ;YES, WAIT
  1132. ;
  1133. ;
  1134. ; Test for the presence of carrier - if none, go to CARCK and continue
  1135. ; testing for 15 seconds. If carrier returns, continue. If is doesn't
  1136. ; return, exit.
  1137. ;
  1138.     IF    EXTMOD OR H8 OR DCH
  1139.     IN    MODCTL2        ;READ MODEM STATUS
  1140.     ENDIF
  1141. ;
  1142.     IF    PMMI
  1143.     IN    BAUDRP        ;READ MODEM STATUS
  1144.     ENDIF
  1145. ;
  1146.     IF    PMMI AND FRNTPNL
  1147.     OUT    PANEL        ;DISPLAY STATUS ON PANEL LIGHTS
  1148.     ENDIF
  1149. ;
  1150.     ANI    MODDCDB        ;CARRIER DETECT MASK
  1151.     CPI    MODDCDA        ;IS IT STILL ON?
  1152.     CNZ    CARCK        ;IF NOT, TEST FOR 15 SECONDS
  1153. ;
  1154. ; Modem timed out receiving - but carrier still on.
  1155. ;
  1156.     POP    D        ;RESTORE D,E
  1157.     STC            ;CARRY SHOWS TIMEOUT
  1158.     RET
  1159. ;.....
  1160. ;
  1161. ;
  1162. ; Got character from modem.  Check to see if there was a framing error,
  1163. ; overrun, or parity error.
  1164. ;
  1165. MCHAR:
  1166.     IF    PMMI OR H8
  1167.     IN    MODCTLP        ;GET MODEM STATUS
  1168.     ENDIF
  1169. ;
  1170.     IF    DCH
  1171.     IN    MODCTL2        ;GET MODEM STATUS
  1172.     ENDIF
  1173. ;
  1174.     IF    PMMI OR H8 OR DCH
  1175.     MOV    D,A        ;SAVE STATUS
  1176.     ANI    MODFRME        ;FRAMING ERROR?
  1177.     CPI    MODFRME
  1178.     JNZ    MCHAR2        ;NO, CHECK FOR OVERRUN
  1179.     LDA    ERRCDE        ;GET RECV ERR CODE
  1180.     ORI    MODFRME        ;TURN ON RECV ERR CODE
  1181.     STA    ERRCDE        ;PUT IT BACK
  1182. MCHAR2:
  1183.     MOV    A,D        ;RESTORE MODEM STATUS
  1184.     ANI    MODOVRE        ;OVERRUN?
  1185.     CPI    MODOVRE
  1186.     JNZ    MCHAR3        ;NO, CHECK FOR PARITY ERROR
  1187.     LDA    ERRCDE
  1188.     ORI    MODOVRE        ;TURN ON RECV ERR CODE
  1189.     STA    ERRCDE
  1190. MCHAR3:
  1191.     MOV    A,D        ;RESTORE MODEM STATUS
  1192.     ANI    MODPARE        ;PARITY ERROR?
  1193.     CPI    MODPARE
  1194.     JNZ    MCHAR4        ;NO, GET DATA CHAR
  1195.     LDA    ERRCDE
  1196.     ORI    MODPARE
  1197.     STA    ERRCDE
  1198. MCHAR4:
  1199.     ENDIF            ;PMMI OR H8 OR DCH
  1200. ;
  1201. ;
  1202. ; Get data char
  1203. ;
  1204.     IN    MODDATP     ;READ THE CHAR
  1205.     POP    D        ;RESTORE 'DE'
  1206. ;
  1207. ;
  1208. ; Calculate checksum and CRC
  1209. ;
  1210.     PUSH    PSW        ;SAVE THE CHAR
  1211.     CALL    UPDCRC        ;CALC CRC
  1212.     ADD    C        ;ADD TO CHECKSUM
  1213.     MOV    C,A        ;SAVE CHECKSUM
  1214.     POP    PSW        ;RESTORE CHAR
  1215.     ORA    A        ;CARRY OFF: NO ERROR
  1216.     RET            ;FROM "RECV"
  1217. ;.....
  1218. ;
  1219. ;
  1220. ; CARCK - common 15 second carrier test for RECV and SEND.  If carrier
  1221. ; returns within 15 seconds, normal program execution continues.  Else,
  1222. ; it will abort to CP/M via EXIT.
  1223. ;
  1224. CARCK:
  1225.     MVI    E,150        ;VALUE FOR 15 SECOND DELAY
  1226. CARCK1:
  1227.     CALL    DELAY        ;KILL .1 SECONDS
  1228. ;
  1229.     IF    EXTMOD OR H8 OR DCH
  1230.     IN    MODCTL2        ;READ MODEM STATUS
  1231.     ENDIF
  1232. ;
  1233.     IF    PMMI
  1234.     IN    BAUDRP        ;READ MODEM STATUS
  1235.     ENDIF
  1236. ;
  1237.     IF    PMMI AND FRNTPNL
  1238.     OUT    PANEL        ;DISPLAY STATUS
  1239.     ENDIF
  1240. ;
  1241.     ANI    MODDCDB        ;CARRIER DETECT MASK
  1242.     CPI    MODDCDA        ;IS IT STILL ON?
  1243.     RZ            ;RETURN IF CARRIER ON
  1244.     DCR    E        ;HAS 15 SECONDS EXPIRED?
  1245.     JNZ    CARCK1        ;IF NOT, CONTINUE TESTING
  1246.     JMP    EXIT        ;ELSE, ABORT TO CP/M.
  1247. ;
  1248. ;
  1249. ; DELAY - 100 millisecond delay.
  1250. ;
  1251. DELAY:
  1252.     PUSH    B        ;SAVE B,C
  1253. ;
  1254.     IF    FASTCLK        ;IF 4MHZ CLOCK
  1255.     LXI    B,16667        ;VALUE FOR 100MS DELAY
  1256.     ENDIF
  1257. ;
  1258.     IF    NOT FASTCLK
  1259.     LXI    B,8334        ;VALUE FOR 100MS DELAY
  1260.     ENDIF
  1261. DELAY2:
  1262.     DCX    B        ;UPDATE COUNT
  1263.     MOV    A,B        ;GET MS BYTE
  1264.     ORA    C        ;COUNT = ZERO?
  1265.     JNZ    DELAY2        ;IF NOT, CONTINUE
  1266.     POP    B        ;RESTORE B,C
  1267.     RET            ;RETURN TO CARCK1.
  1268. ;.....
  1269. ;
  1270. ;
  1271. ; ---> SEND:  Send a character to the modem
  1272. ;
  1273. SEND:
  1274.     PUSH    PSW        ;SAVE THE CHARACTER
  1275.     CALL    UPDCRC        ;CALC THE CRC
  1276.     ADD    C        ;CALC CKSUM
  1277.     MOV    C,A        ;SAVE CKSUM
  1278. ;
  1279.     IF    NOT DCH
  1280. SENDW:
  1281.     IN    MODCTLP     ;GET STATUS
  1282.     ENDIF
  1283. ;
  1284.     IF    DCH
  1285. SENDW:
  1286.     IN    MODCTL2     ;GET STATUS
  1287.     ENDIF
  1288. ;
  1289.     IF    PMMI AND FRNTPNL
  1290.     OUT    PANEL        ;DISPLAY STATUS
  1291.     ENDIF
  1292. ;
  1293.     ANI    MODSNDB     ;ISOLATE READY BIT
  1294.     CPI    MODSNDR     ;READY?
  1295.     JZ    SENDR        ;   YES, GO SEND
  1296. ;
  1297. ;
  1298. ; Xmit status not ready, so test for carrier before looping - if lost,
  1299. ; go to CARCK and give it up to 15 seconds to return.  If it doesn't,
  1300. ; return abort via EXIT.
  1301. ;
  1302.     PUSH    D        ;SAVE 'DE'
  1303. ;
  1304.     IF    EXTMOD OR H8 OR DCH
  1305.     IN    MODCTL2        ;READ MODEM STATUS
  1306.     ENDIF
  1307. ;
  1308.     IF    PMMI
  1309.     IN    BAUDRP        ;READ MODEM STATUS
  1310.     ENDIF
  1311. ;
  1312.     IF    PMMI AND FRNTPNL
  1313.     OUT    PANEL        ;DISPLAY STATUS
  1314.     ENDIF
  1315. ;
  1316.     ANI    MODDCDB        ;CARRIER DETECT MASK
  1317.     CPI    MODDCDA        ;IS IT STILL ON?
  1318.     CNZ    CARCK        ;IF NOT, CONTINUE TESTING IT
  1319.     POP    D        ;RESTORE D,E
  1320.     JMP    SENDW        ;ELSE, WAIT FOR XMIT READY.
  1321. ;.....
  1322. ;
  1323. ;
  1324. ; Xmit status ready, carrier still on - send the data.
  1325. ;
  1326. SENDR:
  1327.     POP    PSW        ;GET CHAR
  1328.     OUT    MODDATP     ;OUTPUT IT
  1329.     RET            ;FROM "SEND"
  1330. ;
  1331. ; ---> WAITNAK:  Waits for initial NAK
  1332. ;
  1333. ; To ensure no data is sent until the receiving program is ready, this
  1334. ; routine waits for the first timeout-NAK or the letter 'C' for CRC
  1335. ; from the receiver.  If CRC is in effect, then Cyclic Redundancy Checks
  1336. ; are used instead of checksums.  'E' contains the number of seconds to
  1337. ; wait.
  1338. ;
  1339. ; If the first character received is a CAN (CTL-X) then the send will be
  1340. ; aborted as though it had timed out.
  1341. ;
  1342. WAITNAK:
  1343.     MVI    B,1        ;TIMEOUT DELAY
  1344.     CALL    RECV        ;DID WE GET
  1345.     CPI    NAK        ;   A NAK?
  1346.     RZ            ;YES, SEND BLOCK
  1347.     CPI    CRC        ;CRC INDICATED?
  1348.     JZ    WAITCRC        ;YES, GO PUT CRC IN EFFECT
  1349.     CPI    CAN        ;WAS IT A CANCEL (CTL-X)?
  1350.     JZ    ABORT        ;YES, ABORT
  1351.     DCR    E        ;80 TRIES?
  1352.     JZ    ABORT        ;YES, ABORT
  1353.     JMP    WAITNAK     ;NO, LOOP
  1354. ;.....
  1355. ;
  1356. ;
  1357. ; ---> WAITCRC:  Turn on CRC Flag
  1358. ;
  1359. WAITCRC:
  1360.     XRA    A        ;ZERO ACCUM
  1361.     STA    CRCFLG        ;TURN ON CRC OPT
  1362.     RET
  1363. ;.....
  1364. ;
  1365. ;
  1366. ; ---> MOVEFCB:  Moves FCB(2) to MEMFCB
  1367. ;
  1368. ; Saves the member file name into MEMFCB
  1369. ;
  1370. MOVEFCB:
  1371.     LXI    H,FCB+16    ;FROM
  1372.     LXI    D,MEMFCB-1    ;TO
  1373.     MVI    B,16        ;LEN
  1374.     CALL    MOVE        ;DO THE MOVE
  1375.     XRA    A        ;GET 0
  1376.     STA    FCBSNO        ;ZERO SECTOR #
  1377.     STA    FCBEXT        ;   AND EXTENT
  1378.     RET
  1379. ;.....
  1380. ;
  1381. ;
  1382. CTYPE:
  1383.     PUSH    B        ;SAVE ALL REGISTERS
  1384.     PUSH    D
  1385.     PUSH    H
  1386.     PUSH    PSW        ;SAVE THE CHARACTER TEMPORARILY
  1387.     LDA    CONONL        ;LOCAL ONLY?
  1388.     ORA    A
  1389.     JNZ    CLTYP        ;YES, TO TO BIOS OUT
  1390.     POP    PSW        ;ELSE GET THE CHARACTER BACK
  1391.     MOV    E,A        ;CHARACTER TO 'E'
  1392.     MVI    C,WRCON     ;WRITE TO CONSOLE
  1393.     CALL    BDOS        ;PRINT THE CHARACTER
  1394.     POP    H        ;RESTORE
  1395.     POP    D        ;   ALL
  1396.     POP    B        ;   REGS
  1397.     RET            ;FROM "CTYPE"
  1398. ;...
  1399. ;
  1400. ;
  1401. CLTYP:
  1402.     POP    PSW        ;GET THE CHARACTER BACK
  1403.     MOV    C,A        ;BIOS NEEDS IT IN 'C'
  1404.     CALL    CONOUT        ;DO BIOS CALL
  1405.     POP    H        ;ALL THIS
  1406.     POP    D        ;   IS FROM
  1407.     POP    B        ;   CTYPE ROUTINE
  1408.     RET
  1409. ;.....
  1410. ;
  1411. ;
  1412. HEXO:
  1413.     PUSH    PSW        ;SAVE FOR RIGHT DIGIT
  1414.     RAR            ;RIGHT
  1415.     RAR            ;   JUSTIFY
  1416.     RAR            ;   LEFT
  1417.     RAR            ;   DIGIT
  1418.     CALL    NIBBL        ;PRINT LEFT DIGIT
  1419.     POP    PSW        ;RESTORE RIGHT
  1420. NIBBL:
  1421.     ANI    0FH        ;ISOLATE DIGIT
  1422.     CPI    10        ;IS IT <10?
  1423.     JC    ISNUM        ;YES, NOT ALPHA
  1424.     ADI    7        ;ADD ALPHA BIAS
  1425. ISNUM:
  1426.     ADI    '0'        ;MAKE PRINTABLE
  1427.     JMP    CTYPE        ;   THEN TYPE IT
  1428. ;.....
  1429. ;
  1430. ;
  1431. ; ---> ILPRT:  Inline print of message
  1432. ;
  1433. ; The call to ILPRT is followed by a message, binary 0 for its end.
  1434. ;
  1435. ILPRT:
  1436.     XTHL            ;SAVE HL, GET HL=MSG
  1437. ;
  1438. ILPLP:
  1439.     MOV    A,M        ;GET CHAR
  1440.     ORA    A        ;END OF MSG?
  1441.     JZ    ILPRET        ;   YES, RETURN
  1442.     CALL    CTYPE        ;TYPE THE MSG
  1443.     INX    H        ;TO NEXT CHAR
  1444.     JMP    ILPLP        ;LOOP
  1445. ;...
  1446. ;
  1447. ILPRET:
  1448.     XTHL            ;RESTORE HL
  1449.     RET            ;PAST MSG
  1450. ;.....
  1451. ;
  1452. ;
  1453. EXITLG:                ; SPECIAL LOG CALLER EXIT
  1454.     IF    LOGCAL
  1455.     JMP    LOGCALL
  1456.     ENDIF
  1457. ;
  1458.     JMP    EXIT
  1459. ;.....
  1460. ;
  1461. ;
  1462. ; ---> ERXIT:  Exit printing message following call
  1463. ;
  1464. ERXIT:
  1465.     POP    D        ;GET MESSAGE
  1466.     MVI    C,PRINT     ;GET BDOS FNC
  1467.     CALL    BDOS        ;PRINT MESSAGE
  1468. EXIT:
  1469.     LHLD    STACK        ;GET ORIGINAL STACK
  1470.     SPHL            ;RESTORE IT
  1471. ;
  1472.     RET            ;--EXIT-- TO CP/M
  1473. ;
  1474. ;
  1475. ; Move 128 characters from 'HL' to 'DE' length in 'B'
  1476. ;
  1477. MOVE128:
  1478.     MVI    B,128        ;SET MOVE COUNT
  1479. MOVE:
  1480.     MOV    A,M        ;GET A CHAR
  1481.     STAX    D        ;STORE IT
  1482.     INX    H        ;TO NEXT "FROM"
  1483.     INX    D        ;TO NEXT "TO"
  1484.     DCR    B        ;MORE?
  1485.     JNZ    MOVE        ;   YES, LOOP
  1486.     RET            ;   NO, RETURN
  1487. ;.....
  1488. ;
  1489. ;
  1490. ;***********************************************************************
  1491. ;
  1492. ; CRCSUBS (Cyclic Redundancy Code Subroutines) version 1.20
  1493. ; 8080 Mnemonics
  1494. ;
  1495. ; These subroutines will compute and check a true 16-bit Cyclic Redun-
  1496. ; dancy Code for a message of arbitrary length.
  1497. ;
  1498. ; (Theory and appliction are discussed extensively in the LMODEMxx.HIS
  1499. ; file.  See that for additional information.)
  1500. ;
  1501. ;***********************************************************************
  1502. ;
  1503. ;
  1504. ; ENTRY    CLRCRC,UPDCRC,FINCRC,CHKCRC
  1505. ;
  1506. CLRCRC:
  1507.     PUSH    H        ;RESET CRC ACCUMULATOR FOR A NEW MSG.
  1508.     LXI    H,0
  1509.     SHLD    CRCVAL
  1510.     POP    H
  1511.     RET
  1512. ;
  1513. UPDCRC:
  1514.     PUSH    PSW        ;UPDATE CRC ACCUMULATOR WITH BYTE IN 'A'
  1515.     PUSH    B
  1516.     PUSH    H
  1517.     MVI    B,8
  1518.     MOV    C,A
  1519.     LHLD    CRCVAL
  1520. UPDLOOP:
  1521.     MOV    A,C
  1522.     RLC
  1523.     MOV    C,A
  1524.     MOV    A,L
  1525.     RAL
  1526.     MOV    L,A
  1527.     MOV    A,H
  1528.     RAL
  1529.     MOV    H,A
  1530.     JNC    SKIPIT
  1531. ;
  1532.     MOV    A,H        ;The generator is X^16 + X^12 + X^5 + 1
  1533.     XRI    10H        ;as recommended by CCITT.  An alternate
  1534.     MOV    H,A        ;generator which is often used in
  1535.     MOV    A,L        ;synchronous transmission protocols is
  1536.     XRI    21H        ;X^16 + X^15 + X^2 + 1. This may be used
  1537.     MOV    L,A        ;by substituting XOR 80H for XOR 10H and
  1538. SKIPIT:
  1539.     DCR    B        ;XOR 05H for XOR 21H in the adj. code.
  1540.     JNZ    UPDLOOP
  1541.     SHLD    CRCVAL
  1542.     POP    H
  1543.     POP    B
  1544.     POP    PSW
  1545.     RET
  1546. ;
  1547. FINCRC:
  1548.     PUSH    PSW        ;FINISH CRC CALC FOR OUTBOUND MSG.
  1549.     XRA    A
  1550.     CALL    UPDCRC
  1551.     CALL    UPDCRC
  1552.     PUSH    H
  1553.     LHLD    CRCVAL
  1554.     MOV    D,H
  1555.     MOV    E,L
  1556.     POP    H
  1557.     POP    PSW
  1558.     RET
  1559. ;.....
  1560. ;
  1561. CRCVAL:    DW    0
  1562. ;
  1563. ;
  1564. ;
  1565. ; Temporary storage area
  1566. ;
  1567.     DB    0
  1568. MEMFCB:    DS    16
  1569. ;
  1570. DIRSZ:    DW    0
  1571. MAXEXT:    DB    0        ;HIGHEST EXT. # SEEN IN FILE SIZE CALC.
  1572. SECTNO:    DW    0        ;CURRENT SECTOR NUMBER 
  1573. ERRCT:    DB    0        ;ERROR COUNT
  1574. OPTSAV:    DB    0        ;SAVE OPTION HERE FOR CARRIER LOSS
  1575. CONONL:    DB    0        ;CTYPE CONSOLE-ONLY FLAG        
  1576. INDEX:    DW    0
  1577. ;
  1578.     IF    PMMI OR H8 OR DCH
  1579. ERRCDE:    DB    0        ;RECEIVE ERROR CODE
  1580.     ENDIF
  1581. ;
  1582. CRCFLG:    DB    'C'        ;SET TO NULL IF CRC USED
  1583. RCNT:    DW    0        ;RECORD COUNT
  1584. ;
  1585. ;
  1586. ; Following 3 used by disk buffering routines
  1587. ;
  1588. EOFLG:    DB    0        ;'EOF' FLAG (1=TRUE)
  1589. SECPTR:    DW    DBUF
  1590. SECNBF:    DB    0        ;# OF SECTORS IN BUFFER
  1591.     DS    60        ;STACK AREA
  1592. ;
  1593. STACK:    DS    2        ;STACK POINTER
  1594. ;
  1595. ;
  1596. ; 16 sector disk buffer
  1597. ;
  1598. DBUF:    DS    0        ;16 SECTOR DISK BUFFER
  1599. ;
  1600. ; BDOS equates
  1601. ;
  1602. RDCON    EQU    1
  1603. WRCON    EQU    2
  1604. PRINT    EQU    9
  1605. CONST    EQU    11        ;CONSOLE STAT
  1606. SELDRV    EQU    14        ;SELECT DRIVE
  1607. OPEN    EQU    15        ;0FFH = NOT FOUND
  1608. CLOSE    EQU    16        ;    "       "
  1609. SRCHF    EQU    17        ;    "       "
  1610. SRCHN    EQU    18        ;    "       "
  1611. ERASEF    EQU    19        ;NO RET CODE
  1612. READ    EQU    20        ;0=OK, 1=EOF
  1613. WRITE    EQU    21        ;0=OK, 1=ERR, 2=?, 0FFH=NO DIR SPC
  1614. MAKE    EQU    22        ;0FFH=BAD
  1615. REN    EQU    23        ;0FFH=BAD
  1616. CURDRV    EQU    25        ;GET CURRENT DRIVE
  1617. STDMA    EQU    26        ;SET DMA
  1618. USER    EQU    32        ;SET USER AREA TO RECEIVE FILE
  1619. BDOS    EQU    BASE+5
  1620. FCB    EQU    BASE+5CH    ;SYSTEM FCB
  1621. FCBEXT    EQU    FCB+12        ;FILE EXTENT
  1622. FCBSNO    EQU    FCB+32        ;SECTOR #
  1623. ;.....
  1624. ;
  1625. ;
  1626.     END
  1627.