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 / CPM / CIS / BUFEXC.AQM / BUFEXC.ASM
Assembly Source File  |  2000-06-30  |  28KB  |  1,213 lines

  1. ;    *** CompuServe Information Service Executive for CP/M (R)
  2. ;        (CP/M is a trademark of Digital Research)
  3. ;    Copyright (C) 1980, 1981 CompuServe Incorporated
  4. ;    Version 2.3
  5. ;    Written by:
  6. ;            Russ Ranshaw
  7.  
  8.  
  9. false:    equ    0
  10. true:    equ    not false
  11.  
  12. usebios:    equ    false        ; true to use direct BIOS calls for
  13.                     ; console output
  14.             ;*** Note: If you choose to use BDOS call for console
  15.             ; write, AND have "shoxfr" true, you may not be able
  16.             ; to do file transfers if your communication channel
  17.             ; is operating at greater than 300 baud!
  18. shoxfr:    equ    true    ; true to show data during file transfer
  19. sholcc:    equ    09h    ; lowest displayable control character for console
  20. shohcc:    equ    0dh    ; highest "" (used in PRODSP to map ctl characters)
  21. paglen:    equ    60    ; printer page length
  22.  
  23. other:    equ    false    ; true if the computer is NOT one of the special ones
  24. hz89:    equ    false    ; true if the computer is a Heath/Zenith 88, 89, 8
  25. hz19:    equ    false        ; Console is a Heath/Zenith -19
  26. pmmi    equ    true    ; true if PMMI modem board
  27.  
  28.     if    other
  29. BBASE:    EQU    0000H    ; "PAGE 0" ADDRESS
  30. CTL    EQU    03H    ; CONTROL PORT
  31. SIO    EQU    01H    ; SIO PORT
  32. SIOIR    EQU    40H    ; SIO PORT DATA INPUT READY FLAG
  33. SIOTR    EQU    80H    ; SIO PORT TRANSMITTER READY FLAG
  34. hitrue:    equ    false    ; SIO flags are "hi" (1) when true
  35.     endif
  36.  
  37.     if    hz89
  38. bbase:    equ    4200h    ; "Page 0" Address - Set to 0 if you have 0 based CP/M
  39. ctl:    equ    0ddh    ; Line Control Register 
  40. sio:    equ    0d8h    ; Receive/Transmit Data Register
  41. sioir:    equ    01h    ; Receive Data Ready flag
  42. siotr:    equ    20h    ; Transmitter Buffer Ready flag
  43. hitrue:    equ    true
  44.     endif
  45.  
  46.     if    pmmi
  47. bbase:    equ    0h    ; "Page 0" address
  48. basprt:    equ    0c0h    ; base i/o port address for pmmi board
  49. ctl:    equ    basprt    ; primary control port
  50. sio:    equ    basprt+1    ; serial data port
  51. sioir:    equ    02h    ; data input ready flag
  52. siotr:    equ    01h    ; transmitter ready flag
  53. hitrue:    equ    true    ; flags are high when true
  54.     endif
  55.  
  56. ; SPECIAL CHARACTERS FOR DATA TRANSMISSION PROTOCOL
  57.  
  58. SOH:    EQU    01H    ; START OF TEXT
  59. ETX:    EQU    03H    ; END OF TEXT
  60. EOT:    EQU    04H    ; END OF TRANSMISSION
  61. ENQ:    EQU    05H    ; ^E, USED FOR PMMI EXIT W/O DISCONNECT
  62. SI:    EQU    0FH    ; <SI> = SHIFT INTO PROTOCOL MODE
  63. SO:    EQU    0EH    ; <SO> = SHIFT OUT OF PROTOCOL MODE]
  64.             ; PROTOCOL MODE IMPLIES THAT <ESC> SEQUENCES
  65.             ; ARE NOT SENT TO CONSOLE BUT ARE USED TO CONTROL
  66.             ; THE UP/DOWN LOAD PROTOCOL
  67. DC1:    EQU    11H    ; <DC1> CONTROL-Q: RESUME TRANSMISSION
  68. DC2:    EQU    12H    ; <DC2> CONTROL-R: PRINTER ON
  69. DC3:    EQU    13H    ; <DC3> CONTROL-S: STOP TRANSMISSION
  70. DC4:    EQU    14H    ; <DC4> CONTROL-T: PRINTER OFF
  71. KNAK:    EQU    15H    ; <NAK>
  72. DLE:    EQU    10H    ; <DLE> (TRANSPARACY FLAG)
  73. ESC:    EQU    1BH    ; ESCAPE
  74. EOF:    EQU    1AH    ; ^Z (CP/M END OF FILE)
  75. CR:    EQU    0DH    ; <RET>
  76. LF:    EQU    0AH    ; <LF>
  77. FF:    EQU    0CH    ; <FF>
  78. MON:    EQU    18H    ; ^X (RETURN TO CP/M) (& DISCONNECT PMMI)
  79.  
  80. ; CP/M EQUATES
  81.  
  82. BDOS:    EQU    BBASE+0005H    ; MAIN ENTRY POINT FOR CP/M
  83. TFCB:    EQU    BBASE+005CH    ; DEFAULT FILE CONTROL BLOCK
  84. TBUFF:    EQU    BBASE+0080H    ; DEFAULT FILE BUFFER
  85. TBASE:    EQU    BBASE+0100H    ; TRANSIENT BASE
  86.  
  87. ; DEFINE OFFSETS INTO FILE CONTROL BLOCK (FCB)
  88.  
  89. FCB$ET:    EQU    0    ; ENTRY TYPE
  90. FCB$FN:    EQU    1    ; FILE NAME (8 BYTES)
  91. FCB$FT:    EQU    9    ; FILE TYPE (3 BYTES)
  92. FCB$RC:    EQU    15    ; RECORD COUNT (CURRENT EXTENT)
  93. FCB$DM:    EQU    16    ; DISK MAP
  94. FCB$NR:    EQU    32    ; NEXT RECORD NUMBER TO READ OR WRITE
  95.  
  96. ;     BDOS FUNCTIONS:
  97.  
  98. FN$SR:    EQU    0    ; SYSTEM RESET
  99. FN$RC:    EQU    1    ; READ CONSOLE
  100. FN$WC:    EQU    2    ; WRITE CONSOLE
  101. FN$RR:    EQU    3    ; READ READER
  102. FN$WP:    EQU    4    ; WRITE PUNCH
  103. FN$WL:    EQU    5    ; WRITE LIST
  104. FN$IS:    EQU    7    ; INTERROGATE I/O STATUS
  105. FN$AS:    EQU    8    ; ALTER I/O STATUS
  106. FN$PCB:    EQU    9    ; PRINT CONSOLE BUFFER
  107. FN$RCB:    EQU    10    ; READ CONSOLE BUFFER
  108. FN$CCS:    EQU    11    ; CHECK CONSOLE STATUS
  109. FN$LDH:    EQU    12    ; LIFT DISK HEAD
  110. FN$RDS:    EQU    13    ; RESET DISK SYSTEM
  111. FN$SD:    EQU    14    ; SELECT DISK
  112. FN$OPN:    EQU    15    ; OPEN FILE
  113. FN$CLS:    EQU    16    ; CLOSE FILE
  114. FN$SF:    EQU    17    ; SEARCH FIRST
  115. FN$SN:    EQU    18    ; SEARCH NEXT
  116. FN$DEL:    EQU    19    ; DELETE FILE
  117. FN$RDR:    EQU    20    ; READ DISK RECORD
  118. FN$WDR:    EQU    21    ; WRITE DISK RECORD
  119. FN$CRE:    EQU    22    ; CREATE FILE
  120. FN$REN:    EQU    23    ; RENAME FILE
  121. FN$IL:    EQU    24    ; INTERROGATE LOGIN
  122. FN$ID:    EQU    25    ; INTERROGATE DISK
  123. FN$SDA:    EQU    26    ; SET DMA ADDRESS
  124. FN$IA:    EQU    27    ; INTERROGATE ALLOCATION
  125.  
  126.     ORG    TBASE
  127.  
  128. START:    JMP    START0        ; NORMAL START
  129. INISIO:    JMP    SIOINI        ; INITIALIZE MODEM UART
  130. GETSIO:    JMP    SIOGET        ; GET CHAR FROM MODEM UART
  131. PUTSIO:    JMP    SIOPUT        ; PUT A CHAR TO MODEM UART
  132.  
  133. ; <ESC><I> response for this executive:
  134.  
  135.     if    other
  136. SYSID:    DB    '#CPMTarbell,CC,HC,PA,PL',CR,00
  137.     endif
  138.  
  139.     if    hz89
  140. sysid:    db    '#CPMHeath/Zenith,CC,HC,PA,PL',cr,00
  141.     endif
  142.  
  143.     if    pmmi
  144. sysid:    db    '#CPMPMMI,CC,HC,PA,PL',CR,00
  145.     endif
  146.  
  147. ; CC = Cursor Control
  148. ;   Implies following cursor controls:
  149. ;    <ESC><A>    cursor up
  150. ;    <ESC><B>    cursor down
  151. ;    <ESC><C>    cursor right
  152. ;    <ESC><D>    cursor left
  153. ;    <ESC><H>    cursor home (line 1, column 1)
  154. ;    <ESC><J>    erase to end of screen
  155. ;    <ESC><K>    erase to end of line
  156. ;    <ESC><j>    erase screen and home cursor (also <FF>)
  157. ;    <ESC><Y><L+31><C+31> position cursor to line L column C
  158. ; HC = Hard Copy
  159. ;   Implies following:
  160. ;    <DC2> (^R, 022 octal, 12 hex) enable printer; subsequent data
  161. ;                      will be copied to local printer
  162. ;    <DC4> (^T, 024 octal, 14 hex) disable printer
  163. ;    <ESC><e>    disable terminal display
  164. ;    <ESC><f>    enable terminal display
  165. ; PA = A Protocol
  166. ;    Implies file transfer capability using the CompuServe A protocol
  167. ; PL = Load Protocol
  168. ;    Implies ability to load code segments under the CompuServe L protocol
  169.  
  170. banner:    db    'CompuServe CP/M (R) Executive Version 2.3',cr,lf
  171.     if    other
  172.     db    '**** Tarbell/Z-80 ****',cr,lf,0
  173.     endif
  174.  
  175.     if    hz89
  176.     db    '**** Heath/Zenith ****',cr,lf,0
  177.     endif
  178.  
  179.     if    pmmi
  180.     db    '**** PMMI Modem ****',cr,lf
  181.     db    '^E exit WITHOUT disconnect, ^X exit WITH disconnect'
  182.     db    cr,lf,lf,'$'
  183.     endif
  184.  
  185.     DB    'Copyright (C) 1980, 1981 CompuServe Incorporated',CR,LF
  186.     DB    CR,LF,'$'
  187.  
  188. START0:    LXI    SP,STACK        ; SET UP OUR OWN STACK
  189.     MVI    C,FN$ID        ; GET CURRENT CP/M DISK DRIVE
  190.     CALL    BDOS
  191.     STA    CPMDEF
  192.     LHLD    BBASE+1        ; GET START OF BIOS
  193.     XCHG
  194.     LXI    H,3        ; OFFSET TO CONSOLE CHECK
  195.     DAD    D
  196.     SHLD    TRMGET+1    ; STORE ADDRESS
  197.     LXI    H,6        ; OFFSET TO CONSOLE READ
  198.     DAD    D
  199.     SHLD    TERMRD+1
  200.     if    usebios
  201.     LXI    H,9        ; OFFSET TO CONSOLE WRITE
  202.     DAD    D
  203.     SHLD    TERMWR+1
  204.     endif
  205.     LXI    H,2AH        ; OFFSET TO LIST STATUS
  206.     DAD    D        ; MUST BE IMPLEMENTED IN BIOS
  207.     SHLD    LSTST+1        ; FOR PRINT BUFFERING TO WORK
  208.  
  209.     XRA    A        ; DISABLE PRINTER OUTPUT
  210.     STA    PRTFLG
  211.     STA    SIFLAG        ; NO <SI> SEEN
  212.     if    shoxfr
  213.     sta    shoflg        ; Don't come up in "show transfer"
  214.     endif            ; mode!
  215.     CALL    INISIO        ; INITIALIZE MODEM UART
  216.     LXI    D,BANNER    ; ANNOUNCE OURSELVES
  217.     MVI    C,FN$PCB
  218.     CALL    BDOS
  219.  
  220. ; TERMINAL EMULATOR LOOP
  221.  
  222. TERM:    CALL    TRMGET
  223.     JZ    TSTSIN
  224.     CPI    MON        ; IF USER WANTS TO RETURN TO CP/M
  225.     
  226.     IF    NOT PMMI
  227.     JZ    BBASE        ; THEN DO IT!
  228.     ENDIF    ;NOT PMMI
  229.  
  230.     IF    PMMI
  231.     JZ    DISCON        ; DISCONNECT MODEM
  232.     ENDIF    ;PMMI
  233.  
  234.     CPI    ENQ        ; IF ^E
  235.     JZ    BBASE        ; THEN JUST EXIT
  236.     CPI    DC2        ; IF ^R
  237.     JZ    PRTON        ; THEN TURN PRINTER ON
  238.     CPI    DC4        ; IF ^T
  239.     JZ    PRTOFF        ; THEN TURN PRINTER OFF
  240.     CALL    PUTSIO        ; ELSE PUT CHAR OUT TO SIO
  241.  
  242. TSTSIN:    CALL    GETSIN        ; ELSE GET A CHAR FROM SIO
  243.     JZ    TSTPRT
  244.     CPI    DLE        ; IF <DLE>
  245.     JZ    ISDLE        ; THEN PROCESS <DLE>
  246.     CPI    SI        ; IF <SI>
  247.     JZ    ISSI        ; THEN PROCESS <SI>
  248.     CPI    SO        ; IF <SO>
  249.     JZ    ISSO        ; THEN PROCESS <SO>
  250.     CPI    ESC        ; IF <ESC>
  251.     JZ    ISESC        ; THEN GO PROCESS ESCAPE SEQUENCE
  252.     CPI    DC2        ; IF ^R
  253.     JZ    PRTON        ; THEN TURN PRINTER ON
  254.     CPI    DC4        ; ELSE IF ^T
  255.     JZ    PRTOFF        ; THEN TURN PRINTER OFF
  256.  
  257.     IF    HZ19        ; IF RUNNING A H/Z-19 CONSOL
  258.     CPI    FF        ; THEN IF CHAR IS <FF>
  259.     JZ    FFHZ19        ; THEN MAP IT TO <ESC><E>
  260.     ENDIF
  261.  
  262. NOTSIM:    CALL    TERDSP        ; DISPLAY/PRINT CHARACTER
  263. TSTPRT:
  264. LSTST:    CALL    0000        ; MODIFIED TO LIST STATUS
  265.     ORA    A
  266.     JZ    TERM        ; IF PRINTER IS BUSY
  267.                 ; THEN CONTINUE TO SERVICE THE
  268.                 ; KEYBOARD & MODEM AT HIGH POLLING RATE
  269.     LHLD    HEAD        ; GET HEAD POINTER
  270.     XCHG
  271.     LHLD    TAIL        ; AND TAIL POINTER
  272.     CALL    DEHLCMP        ; SEE IF THEY ARE EQUAL
  273.     JZ    TERM        ; IF SO, BUFFER IS EMPTY, SO EXIT
  274.     PUSH    H        ; SAVE TAIL POINTER
  275.     MOV    A,M        ; GET THE CHAR
  276.     ANI    7FH        ; STRIP PARITY
  277.     LXI    H,LINCNT    ; POINT TO LINE COUNTER
  278.     CPI    FF        ; IF FF
  279.     JZ    NEWPAGE        ; RESET LINE COUNTER
  280.     CPI    LF        ; IF LF
  281.     JNZ    OUTP        ; DECREMENT LINE COUNTER
  282.     DCR    M        ; IF ROOM LEFT ON PAGE
  283.     JNZ    OUTP        ; OUTPUT THE LF
  284. NEWPAGE    MVI    M,PAGLEN    ; ELSE A FF
  285.     MVI    A,FF
  286. OUTP:    MOV    E,A
  287.     MVI    C,FN$WL        ; CHAR TO LIST DEVICE
  288.     CALL    BDOS
  289.     POP    H        ; RESTORE TAIL PTR
  290.     INX    H
  291.     LDA    BDOS+2        ; CHECK FOR MEMORY TOP
  292.     DCR    A
  293.     CMP    H
  294.     JNC    OUTP1
  295.     LXI    H,PRTBUF    ; WRAPAROUND
  296. OUTP1:    SHLD    TAIL        ; UPDATE TAIL PTR
  297.     JMP    TERM
  298.  
  299. DEHLCMP:    ; TEST (DE)-(HL) COMPARISON
  300.     MOV    A,D
  301.     CMP    H
  302.     RNZ
  303.     MOV    A,E
  304.     CMP    L
  305.     RET
  306.  
  307.  
  308. ; GET A CHARACTER FROM LOCAL TERMINAL
  309. ; RETURN Z FLAG IF LOCAL NOT READY
  310.  
  311. TRMGET:    CALL    0000H        ; **** MODIFIED ADDRESS!!!
  312.     ANI    01
  313.     RZ            ; RETURN IF NO LOCAL INPUT
  314. TERMRD:    CALL    0000H        ; **** MODIFIED ADDRESS!!!
  315.     ANI    7FH        ; RETURN WITH PARITY STRIPPED
  316.     RET
  317.  
  318. ; HERE IF <DC2> (^R) RECEIVED FROM HOST OR CONSOLE
  319.  
  320. PRTON:    MVI    A,0FFH        ; SET PRINTER FLAG
  321.     STA    PRTFLG
  322.     JMP    TERM
  323.  
  324. ; HERE IF <DC4> (^T) RECEIVED FROM HOST OR CONSOLE
  325.  
  326. PRTOFF:    XRA    A        ; CLEAR PRINTER FLAG
  327.     STA    PRTFLG
  328.     JMP    TERM
  329.  
  330. ; HERE IF <DLE> RECEIVED FROM HOST
  331.  
  332. ISDLE:    CALL    GETSIX        ; GET CHARACTER FOLLOWING <DLE>
  333.     CALL    TERDSP        ; DISPLAY IT ON CONSOLE/PRINTER
  334.     JMP    TERM
  335.  
  336. ISSO:    XRA    A    ; <SO> DISABLES PROTOCOL MODE
  337.     if    shoxfr
  338.     sta    shoflg
  339.     endif
  340.     LXI    SP,STACK    ; RESTORE STACK INCASE OF ABORT
  341. ISSI:    STA    SIFLAG    ; <SI> ENABLES PROTOCOL MODE
  342.     JMP    TERM
  343.  
  344. ; HERE ON <ESC> 
  345.  
  346. ISESC:    LDA    SIFLAG    ; IF <SI> NOT RECEIVED
  347.     ORA    A
  348.     MVI    A,ESC
  349.  
  350.     IF    NOT HZ19
  351.     JZ    NOTSIM    ; THEN JUST DISPLAY IT
  352.     ENDIF
  353.  
  354.     IF    HZ19
  355.     JZ    CK1061        ; THEN CHECK FOR SPECIAL MAPPINGS
  356.     ENDIF
  357.  
  358. ISESCN:    CALL    GETSIX    ; ELSE GET CHARACTER FROLLOWING <ESC>
  359.     CPI    'I'    ; IF <ESC><I>
  360.     JNZ    ESC0    ; THEN
  361.     LXI    H,SYSID        ; SEND THE ID STRING TO HOST
  362.  
  363. SNDID:    MOV    A,M        ; GET NEXT ID BYTE
  364.     ORA    A        ; IF NULL
  365.     JZ    TERM        ; THEN FINISHED
  366.     CALL    PUTSIO        ; ELSE SEND TO HOST
  367.     INX    H
  368.     JMP    SNDID
  369.  
  370.  
  371.     IF    HZ19        ; IF WE HAVE A H/Z-19 AS CONSOLE
  372. CK1061:    CALL    GETSIX        ; GET CHAR FOLLOWING <ESC>
  373.     CPI    'j'        ; <ESC><j> = <ESC><E>
  374.     JNZ    NT1061
  375. FFHZ19:    MVI    A,'E'
  376. NT1061:    PUSH    PSW
  377.     MVI    A,ESC
  378.     CALL    TERDSP
  379.     POP    PSW
  380.     JMP    NOTSIM
  381.     ENDIF            ; H/Z-19 MAPPING
  382.  
  383. ESC0:    CPI    'L'    ; IF <ESC><L>
  384.     JNZ    ESC1    ; THEN
  385.     MVI    E,0    ;     PERFORM SYSTEM LOAD FUNCTION
  386.     CALL    GETCKS    ; GET BYTE COUNT
  387.     MOV    B,A
  388.     CALL    GETCKS    ; GET LOW ADDRESS BYTE
  389.     MOV    L,A
  390.     CALL    GETCKS
  391.     MOV    H,A    ; AND HIGH-ORDER
  392.  
  393. ESCL0:    CALL    GETCKS    ; GET NEXT DATA BYTE
  394.     MOV    M,A    ; SAVE IT
  395.     INX    H    ; BUMP MEMORY ADDRESS
  396.     DCR    B    ; COUNT BYTES RECEIVED
  397.     JNZ    ESCL0    ; & LOOOP TILL ZERO
  398.     MOV    C,E    ; SAVE CHECKSUM
  399.     CALL    GETCKS    ; GET NEXT BYTE
  400.     CMP    C    ; IF MATCH
  401.     MVI    A,'.'    ; THEN SEND .
  402.     JZ    ESCL1    ; ELSE
  403.     MVI    A,'/'    ;    SEND /
  404. ESCL1:    CALL    PUTSIO
  405.     if    not shoxfr
  406.     call    viomrk        ; display protocol mark
  407.     endif
  408.     JMP    TERM
  409.  
  410.     if    not shoxfr
  411. viomrk:
  412.     push    psw
  413.     mvi    a,cr
  414.     call    viodsp
  415.     mvi    a,lf
  416.     call    viodsp
  417.     mvi    a,32
  418.     sta    xfrctr
  419.     pop    psw
  420.     cpi    '.'
  421.     cnz    viodsp
  422.     ret
  423.  
  424. ctxfr:    push    h
  425.     push    psw
  426.     lxi    h,xfrctr    ; decrement count of xfr'd characters
  427.     dcr    m
  428.     jnz    ctxfr0
  429.     mvi    m,32
  430.     mvi    a,'+'        ; display '+' every 32 bytes
  431.     call    viodsp
  432. ctxfr0:    pop    psw
  433.     pop    h
  434.     ret
  435.     endif
  436.  
  437.  
  438. ESC1:    CPI    'A'    ; IF <ESC><A>
  439.     JNZ    TERM    ; THEN
  440.  
  441. ; Initialize for data transmission using the CompuServe A-protocol
  442. ; The protocol begins with the following being sent from the host:
  443. ;    <ESC><A><SOH><U | D><A | B><FILESPEC><ETX><CKSUM>
  444. ; where:
  445. ;    U = upload, D = download
  446. ;    A = ASCII (file ends in 1Ah), B = binary
  447. ;    FILESPEC = standard CP/M file specification, including optional drive
  448. ;    CKSUM = checksum for the record
  449.  
  450.     MVI    A,'0'        ; INIT RECORD NUMBER
  451.     STA    APNXT
  452.     CALL    APRCVX        ; GET COMMAND LINE FROM HOST
  453.     LXI    H,APBUF+2    ; POINT TO FILE SPEC FROM USER
  454.     LXI    D,TFCB        ; POINT TO FILE CONTROL BLOCK
  455.     MOV    B,M        ; GET POSSIBLE DISK DRIVE NAME
  456.     INX    H        ; IF : NEXT
  457.     MOV    A,M
  458.     CPI    ':'
  459.     JNZ    NOCOL        ; THEN
  460.     INX    H        ; SKIP THE COLON
  461.     MVI    A,7        ; MASK OFF DRIVE NUMBER
  462.     ANA    B
  463.     JMP    FIRSTB
  464.  
  465. NOCOL:    DCX    H        ; POINT BACK TO FIRST FILE BYTE
  466.     XRA    A        ; USE DEFAULT DRIVE NUMBER
  467. FIRSTB:    STAX    D        ; STORE DRIVE NUMBER
  468.     INX    D        ; POINT TO FIRST FILE NAME BYTE
  469.     MVI    B,8        ; MAX LENGTH OF NAME
  470.     CALL    NAAME        ; GET FILE NAME
  471.     MOV    A,M        ; GET NEXT BYTE
  472.     CPI    '.'        ; IF . PRESENT
  473.     JNZ    EXT        ; THEN
  474.     INX    H        ; SKIP OVER IT
  475. EXT:    MVI    B,3        ; LENGTH OF EXTENSION
  476.     CALL    NAAME        ; GET EXTENSION
  477.     XRA    A        ; ZERO FILE EXTENT
  478.     STAX    D
  479.     LDA    TFCB        ; SELECT THE DISK
  480.     ORA    A        ; IF 0 THEN USE DEFAULT DISK
  481.     JZ    NODISK
  482.     SUI    1        ; MAP A INTO 0, B INTO 1, ETC.
  483.     MOV    E,A
  484.     MVI    D,0
  485.     MVI    C,FN$SD
  486.     CALL    BDOS
  487.  
  488. NODISK:
  489.     lda    apbuf+1        ; store transfer type
  490.     sta    xfrtyp
  491.     LDA    APBUF        ; CHECK DIRECTION
  492.     CPI    'D'        ; IF DOWN LOAD
  493.     JNZ    CHKUPL        ; THEN
  494.     lxi    d,dnload
  495.     mvi    c,fn$pcb
  496.     call    bdos
  497.     MVI    C,FN$OPN    ; IF THE FILE EXISTS
  498.     CALL    DSKOP
  499.     CPI    0FFH
  500.     JZ    DLOKAY        ; THEN
  501.     LXI    D,DLBOMB    ;    TELL THE USER ABOUT IT
  502.     MVI    C,FN$PCB
  503.     CALL    BDOS
  504.     MVI    C,FN$RC        ; GET USER'S RESPONSE
  505.     CALL    BDOS
  506.     ani    7fh
  507.     PUSH    PSW
  508.     MVI    A,CR
  509.     CALL    VIODSP
  510.     MVI    A,LF
  511.     CALL    VIODSP
  512.     POP    PSW
  513.     CPI    'Y'        ; IF NOT 'Y'
  514.     JZ    DLDEL
  515.     CPI    'y'
  516.     JNZ    ABORT        ; THEN ABORT THE DOWNLOAD ATTEMPT
  517. DLDEL:    MVI    C,FN$DEL    ; ELSE DELETE THE FILE
  518.     CALL    DSKOP
  519. DLOKAY:    CALL    OPNOUT        ; OPEN FOR OUTPUT
  520.     if    shoxfr
  521.     mvi    a,0ffh
  522.     sta    shoflg
  523.     endif
  524.  
  525. ; THE FOLLOWING LOOP DOES THE DOWNLOAD FUNCTION
  526.  
  527. DL0:    CALL    APRCV        ; GET NEXT LINE OF DATA
  528.     JNZ    DLEOT        ; HANDLE END OF TRANSMISSION
  529.     LXI    H,APBUF        ; POINT TO BUFFER
  530. DL1:    MOV    A,M        ; GET NEXT BYTE
  531.     INX    H        ; POINT TO NEXT BYTE
  532.     CALL    PUTBYT        ; PUT IT INTO OUTPUT BUFFER
  533.     DCR    B        ; COUNT THE BYTE
  534.     JNZ    DL1
  535.     JMP    DL0        ; GET NEXT RECORD FROM HOST
  536.  
  537. ; HERE WHEN THE HOST'S <EOT> MESSAGE HAS BEEN RECEIVED
  538.  
  539. DLEOT:
  540.     lda    xfrtyp        ; if binary transfer
  541.     cpi    'B'
  542.     jz    dleotb        ; then don't insert ^Z
  543.     MVI    A,EOF        ; PUT ^Z (END OF FILE MARK)
  544.     CALL    PUTBYT
  545. dleotb:    MVI    C,FN$WDR
  546.     CALL    DSKOP
  547. DLEOT0:    MVI    C,FN$CLS
  548.     CALL    DSKOP
  549.     CALL    RSTDEF
  550.     MVI    A,'.'        ; TELL HOST WE GOT IT
  551.     CALL    PUTSIO
  552.     if    not shoxfr
  553.     call    viomrk
  554.     endif
  555.     if    shoxfr
  556.     xra    a
  557.     sta    shoflg
  558.     endif
  559.     JMP    TERM        ; BACK TO TERMINAL MODE
  560.  
  561. ; HERE IF NOT A DOWN LOAD - BETTER BE UP LOAD!
  562.  
  563. CHKUPL:    CPI    'U'
  564.     JNZ    ABORT        ; SEND NAK TO HOST IF NOT .
  565.     lxi    d,upload
  566.     mvi    c,fn$pcb
  567.     call    bdos
  568.     CALL    OPNINP        ; OPEN THE FILE FOR INPUT
  569.     MVI    A,'.'        ; TELL HOST WE'RE READY TO SEND DATA
  570.     CALL    PUTSIO
  571.     if    not shoxfr
  572.     call    viomrk
  573.     endif
  574.  
  575. ; THE UPLOAD FUNCTION IS DONE IN THE FOLLOWING LOOP:
  576.  
  577.     CALL GETSIX        ; GET HOST'S PROMPT
  578.     CPI    '.'        ; ABORT IF NOT '.'
  579.     JNZ    ABORT
  580.     if    shoxfr
  581.     mvi    a,0ffh
  582.     sta    shoflg
  583.     endif
  584.  
  585. UPL1:    MVI    B,0        ; INIT COUNT
  586.     LXI    H,APBUF
  587. UPL2:    CALL    GETBYT        ; GET DATA FROM FILE
  588.     jp    upl3        ; jump if <EOF> occured
  589.     MOV    M,A        ; THEN PUT INTO BUFFER
  590.     INX    H        ; BUMP POINTER
  591.     INR    B        ; AND BYTE COUNT
  592.     JNZ    UPL2        ; GET NEXT BYTE IF BUFFER NOT FILLED
  593. UPL4:    MOV    A,B        ; SAVE COUNT
  594.     STA    APLEN
  595.     CALL    APSND        ; SEND THE DATA
  596.     JMP     UPL1        ; GO DO NEXT LINE
  597.  
  598. UPL3:    MOV    A,B        ; WRITE FINAL DATA BLOCK IF THERE IS ONE
  599.     STA    APLEN
  600.     ORA    A
  601.     CNZ    APSND
  602.     MVI    A,0FFH        ; SEND <EOT> MESSAGE WITHOUT MASKING
  603.     LXI    H,EOTMSG
  604.     CALL    APSND0
  605.     CALL    RSTDEF        ; RESTORE CP/M'S DEFAULT DISK DRIVE
  606.     if    shoxfr
  607.     xra    a
  608.     sta    shoflg
  609.     endif
  610.     JMP    TERM        ; RETURN TO TERMINAL MODE
  611.  
  612. EOTMSG:    DB    1,EOT
  613.  
  614. ;***
  615.  
  616. ; ROUTINE TO INTERFACE TO CP/M'S CONSOLE OUTPUT DRIVER
  617.  
  618. viodsp:    push    b    ; save register
  619.     push    d
  620.     push    h
  621.     push    psw
  622.     if    usebios
  623.     mov    c,a
  624. TERMWR:    CALL    0000H    ; ***** MODIFIED TO CONOT IN BIOS
  625.     endif
  626.     if    not usebios
  627.     mov    e,a        ; call BDOS to write char on console
  628.     mvi    c,fn$wc
  629.     call    bdos
  630.     endif
  631.     pop    psw
  632.     pop    h
  633.     pop    d
  634.     pop    b
  635.     RET
  636.  
  637. ; ROUTINE TO DISPLAY C(A) ON CP/M CONSOLE AND PRINTER IF NECESSARY
  638.  
  639. TERDSP:    PUSH    PSW        ; SAVE C(A)
  640.     CALL    VIODSP        ; DISPLAY ON CONSOLE
  641.     POP    PSW        ; GET CHARACTER BACK
  642.     MOV    E,A        ; SAVE CHARACTER
  643.     LDA    PRTFLG        ; IF ^R RECEIVED
  644.     ORA    A
  645.     RZ            ; THEN
  646. ; STORE THE CHAR IN THE PRINTER BUFFER
  647.     LHLD    HEAD        ; GET BUFFER PTR
  648.     MOV    M,E        ; STORE THE CHAR
  649.     INX    H        ; BUMP PTR
  650.     LDA    BDOS+2        ; CHECK FOR TOP OF MEMORY
  651.     DCR    A
  652.     CMP    H
  653.     JNZ    TERDS1        ; IF REACHED, WRAPAROUND
  654.     LXI    H,PRTBUF
  655. TERDS1:    SHLD    HEAD        ; UPDATE PTR
  656.     RET
  657.  
  658. ; ROUTINE TO OPEN A FILE FOR OUTPUT
  659.  
  660. OPNOUT:    MVI    C,FN$CRE    ; CREATE FILE
  661.     CALL    DSKOP    ; CALL CP/M
  662.     CPI    0FFH    ; IF OKAY
  663.     JZ    ERRCRE        ; ERROR DURING CREATE (DIRECTOR FULL?)
  664.     XRA    A    ; CLEAR NEXT RECORD COUNT
  665.     STA    TFCB+FCB$NR
  666.     STA    IBP    ; INIT BUFFER POINTER
  667.     RET
  668.  
  669. ; ROUTINE TO OPEN FILE FOR INPUT
  670.  
  671. OPNINP:    MVI    C,FN$OPN
  672.     CALL    DSKOP
  673.     CPI    0FFH        ; IF FILE NOT FOUND
  674.     JZ    ERROPN        ; THEN ERROR MESSAGE TIME!
  675.     XRA    A
  676.     STA    TFCB+FCB$NR    ; INIT TO FIRST RECORD
  677.     MVI    A,80H        ; "EMPTY BUFFER"
  678.     STA    IBP
  679.     RET
  680.  
  681.  
  682. ; ROUTINE TO PUT C(A) INTO DISK BUFFER
  683.  
  684. PUTBYT:    PUSH    B    ; SAVE REGS
  685.     PUSH    D
  686.     PUSH    H
  687.     PUSH    PSW    ; SAVE BYTE
  688.     LDA    IBP    ; IF BUFFER IS FULL
  689.     CPI    80H
  690.     JNZ    PUT0    ; THEN
  691.     MVI    C,FN$WDR
  692.     CALL    DSKOP
  693.     ORA    A
  694.     JNZ    ERRWDR        ; WRITE ERROR???
  695.     XRA    A    ; INIT IBP TO 0
  696.  
  697. PUT0:    MOV    E,A    ; SAVE CUR BYTE POSITION
  698.     MVI    D,0
  699.     INR    A    ; BUMP POINTER
  700.     STA    IBP
  701.     LXI    H,TBUFF    ; POINT TO BUFFER
  702.     DAD    D    ; NOW POINT TO BYTE
  703.     POP    PSW    ; GET BYTE
  704.     MOV    M,A    ; STORE BYTE
  705.     POP    H    ; RESTORE REGS
  706.     POP    D
  707.     POP    B
  708.     RET
  709.  
  710. ; ROUTINE TO GET NEXT BYTE FROM A DISK RECORD
  711.  
  712. GETBYT:    PUSH    B    ; SAVE REGS
  713.     PUSH    D
  714.     PUSH    H
  715.     mvi    b,0    ; assume not <EOF>
  716.     LDA    IBP    ; IF BUFFER IS EMPTY
  717.     CPI    80H
  718.     JNZ    GET0
  719.     MVI    C,FN$RDR
  720.     CALL    DSKOP
  721.     mov    b,a        ; save return code (0 implies okay)
  722.     XRA    A    ; RESET BYTE POINTER
  723. GET0:    MOV    E,A    ; SAVE BYTE POS
  724.     MVI    D,0
  725.     INR    A    ; BUMP BYTE POS
  726.     STA    IBP
  727.     LXI    H,TBUFF
  728.     DAD    D
  729.     lda    xfrtyp        ; if binary transfer
  730.     cpi    'B'
  731.     jz    gtbtbn        ; then don't check for ^Z
  732.     MOV    A,M    ; GET THE BYTE
  733.     cpi    eof    ; if ^Z
  734.     jnz    gtrstr    ; then
  735.     mvi    b,1    ; we will exit with N cleared
  736. gtrstr:    dcr    b    ; set N if NOT eof
  737.     POP    H    ; RESTORE REGS
  738.     POP    D
  739.     POP    B
  740.     RET
  741.  
  742. gtbtbn:    mov    a,m    ; get binary byte
  743.     jmp    gtrstr    ; set N flag and exit
  744.  
  745. ; FATAL CP/M ERROR CONDITIONS PRINT A LOCAL MESSAGE 
  746. ; THEN SEND A <NAK> TO HOST
  747.  
  748. ERRCRE:    LXI    D,CREMSG
  749.     JMP    DFATAL
  750.  
  751.  
  752. ERROPN:    LXI    D,OPNMSG
  753.     JMP    DFATAL
  754.  
  755.  
  756. ERRWDR:    LXI    D,WDRMSG
  757.     JMP    DFATAL
  758.  
  759.  
  760.  
  761. DFATAL:
  762. FATAL:    MVI    C,FN$PCB        ; WRITE ERROR MESSAGE
  763.     CALL    BDOS
  764.  
  765. ABORT:
  766.     lxi    d,abload    ; tell user we are aborting
  767.     mvi    c,fn$pcb
  768.     call    bdos
  769.     MVI    C,FN$CLS
  770.     CALL    DSKOP
  771.     CALL    RSTDEF        ; RESTORE DEFAULD DISK
  772.     MVI    A,KNAK
  773.     CALL    PUTSIO            ; TELL HOST WE HAVE BOMBED
  774.     JMP    ISSO            ; DISABLE PROTOCOL MODE
  775.  
  776. ; HERE TO DO A CP/M DISK OPERATION; CALLED WITH DESIRED FUNCTION CODE IN C
  777.  
  778. DSKOP:    LXI    D,TFCB
  779.     CALL    BDOS
  780.     PUSH    PSW        ; SAVE RETURN CODE
  781.     XRA    A        ; OUTPUT A NULL TO CONSOLE
  782.     CALL    VIODSP        ; TO FLUSH DISK BUFFER
  783.     POP    PSW        ; RESTORE DSK RETURN CODE
  784.     RET
  785.  
  786. ; ROUTINE TO RESTORE CP/M'S DEFAULT DISK DRIVE
  787.  
  788. RSTDEF:    LDA    CPMDEF
  789.     MOV    E,A
  790.     MVI    D,0
  791.     MVI    C,FN$SD
  792.     CALL    BDOS
  793.     RET
  794.  
  795. ; ROUTINE TO EXTRACT FILE NAME AND EXTENSION
  796.  
  797. NAAME:    MOV    A,M    ; GET NEXT BYTE
  798.     CPI    CR    ; <RET> ENDS NAME
  799.     JZ    FILL    ; FILL IF END OF STRING
  800.     CPI    '.'    ; IF EXTENSION
  801.     JZ    FILL    ; THEN FILL OUT WITH SPACES
  802.     INX    H    ; SKIP THIS BYTE
  803.     CPI    60H    ; LOWER CASE A
  804.     JC    NAME1    ; JUMP IF NOT LOWER CASE
  805.     SBI    20H    ; CONVERT LOWER CASE TO UPPER
  806. NAME1:    STAX    D    ; STORE BYTE IN FCB
  807.     INX    D
  808.     DCR    B    ; COUNT THIS BYTE
  809.     JNZ    NAAME    ; PROCESS NEXT IF MORET
  810.     RET
  811.  
  812. FILL:    MVI    A,' '    ; STORE A SPACE
  813.     JMP    NAME1
  814.  
  815.  
  816. ; THIS ROUTINE RECEIVES A RECORD USING THE ASCII PROTOCOL
  817.  
  818. APRCV:    MVI    A,'.'    ; PROMPT REMOTE FOR NEXT RECORD
  819.     CALL    PUTSIO
  820.     if    not shoxfr
  821.     call    viomrk
  822.     endif
  823. APRCVX:    LDA    APNXT    ; BUMP EXPECTED RECORD NUMBER
  824.     INR    A
  825.     CPI    '9'+1    ; WRAP-AROUND
  826.     JC    APRCVY    ; JUMP IF LEQ 9
  827.     MVI    A,'0'
  828. APRCVY:    STA    APNXT
  829.     if    not shoxfr
  830.     call    viodsp
  831.     endif
  832. APRCV0:    CALL    TRMGET        ; GET LOCAL KEYBOARD INPUT
  833.     CPI    ETX            ; IF ^C
  834.     JZ    ABORT            ; THEN ABORT THE TRANSFER
  835.     CALL    GETSIX    ; GET NEXT CHARACTER
  836.     CPI    SOH    ; <SOH> STARTS THE RECORD
  837.     JZ    APRCV1
  838.     CPI    ETX    ; <ETX> BY ITSELF IS QUESTIONABLE
  839.     JNZ    APRCV0
  840.     MVI    A,'/'    ; SEND A LOGICAL NAK
  841.     CALL    PUTSIO
  842.     if    not shoxfr
  843.     CALL    VIODSP
  844.     endif
  845.     JMP    APRCV0
  846.  
  847. APRCV1:    MVI    E,0    ; INIT CHECKSUM
  848.     MOV    B,E    ; INIT BYTE COUNT
  849.     MOV    A,E    ; CLEAR <EOT> FLAG
  850.     STA    APEOT
  851.     LXI    H,APBUF
  852.     CALL    GETCKS    ; GET SENDER'S RECORD NUMBER
  853.     STA    APCUR
  854.  
  855. APRCV2:    CALL    GETCKS    ; GET A CHECKSUMMED CHARACTER
  856.     JZ    APRCV3
  857.     MOV    M,A    ; PUT BYTE IN BUFFER
  858.     INR    B    ; COUNT THIS BYTE
  859.     INX    H
  860.     if    not shoxfr
  861.     call    ctxfr    ; display '+' every 32 bytes
  862.     endif
  863.     JMP    APRCV2
  864.  
  865. APRCV3:    MOV    C,E    ; SAVE CHECKSUM
  866.     CALL    GETCKS    ; GET REMOTE'S CHECKSUM
  867.     CMP    C    ; IF SAME
  868.     JNZ    APRCV4    ; THEN
  869.     LDA    APNXT        ; CHECK RECORD COUNT
  870.     MOV    C,A
  871.     LDA    APCUR
  872.     CMP    C
  873.     JNZ    APRCV8        ; JUMP IF NOT MATCHED
  874.     MOV    A,B    ; STORE BYTE COUNT
  875.     STA    APLEN
  876.     LDA    APEOT    ; RETURN WITH EOT FLAG STATUS
  877.     ORA    A
  878.     RET
  879.  
  880. APRCV4:    MVI    A,'/'    ; ELSE REQUEST RETRANSMISSION
  881.     CALL    PUTSIO
  882.     if    not shoxfr
  883.     CALL    VIODSP
  884.     endif
  885.     JMP    APRCV0
  886.  
  887. APRCV8:    JNC    ABORT        ; ABORT IF RCV GTR EXPECTED
  888.     MVI    A,'.'        ; MUST HAVE RECEIVED A DUPLICATE RECORD
  889.     CALL    PUTSIO        ; ACCEPT IT, AND TRY AGAIN
  890.     if    not shoxfr
  891.     call    viomrk
  892.     endif
  893.     JMP    APRCV0
  894.  
  895.  
  896. ; ROUTINE TO SEND A MESSAGE
  897.  
  898. APSND:    XRA    A        ; Flag for masking control characters
  899.     LXI    H,APLEN        ; BUFFER ADDRESS: LENGTH FOLLOWED BY DTA
  900. APSND0:    STA    APFLG        ; STORE MASK FLAG
  901.     SHLD    APADDR        ; STORE BUFFER ADDRESS
  902.     LDA    APNXT        ; BUMP NEXT RECORD COUNT
  903.     INR    A
  904.     CPI    '9'+1
  905.     JC    ASND0A
  906.     MVI    A,'0'
  907. ASND0A:    STA    APNXT
  908.     if    not shoxfr
  909.     call    viodsp
  910.     endif
  911.  
  912. APSND1:    MVI    E,0        ; CLEAR CHECKSUM
  913.     LHLD    APADDR
  914.     MOV    B,M        ; GET LENGTH
  915.     INX    H        ; POINT TO DATA
  916.     MVI    A,SOH        ; START THE MESSAGE
  917.     CALL    APPUTS
  918.     LDA    APNXT        ; SEND RECORD NUMBER
  919.     CALL    DOCKS        ; UPDATE CHECKSUM
  920.     CALL    APPUTS
  921. APSND2:    MOV    A,M        ; GET NEXT DATA BYTE
  922.     CALL    DOCKS        ;UPDATE CHECKSUM
  923.     CPI    20H        ; IF CONTROL CHARACTER
  924.     JNC    ASND2A        ; THEN
  925.     LDA    APFLG        ; IF MASKING CONTROL CHARACTERS
  926.     ORA    A
  927.     MOV    A,M        ; GET BYTE AGAIN
  928.     JNZ    ASND2A        ; THEN
  929.     CPI    05H        ; FOR EFFICIENCY, ONLY MASK THE BADDIES
  930.     JC    ASND2B        ; MASK 00H 01H 02H 03H 04H
  931.                 ;      NUL SOH STX ETX EOT
  932.     CPI    dle
  933.     JZ    ASND2B        ; 10H DLE
  934.     CPI    knak
  935.     JNZ    ASND2A        ; 15H NAK
  936. ASND2B:    MVI    A,DLE        ; SEND <DLE><DATA+40H)
  937.     CALL    APPUTS
  938.     MOV    A,M    
  939.     ORI    40H
  940. ASND2A:    CALL    APPUTS        ; TRANSMIT THE CHARACTER
  941.     INX    H
  942.     if    not shoxfr
  943.     call    ctxfr        ; display '+' every 32 characters
  944.     endif
  945.     DCR    B
  946.     JNZ    APSND2    ; BACK FOR MORE IF ANY
  947.  
  948. APSND3:    MVI    A,ETX        ; TERMINATE THE TEXT PORTION
  949.     CALL    APPUTS
  950.     MOV    A,E        ; GET CHECKSUM
  951.     CPI    20H        ; IF < 20H
  952.     JNC    ASND3A        ; THEN
  953.     MVI    A,DLE        ; SEND IT MASKED
  954.     CALL    APPUTS
  955.     MOV    A,E
  956.     ORI    40H
  957. ASND3A:    CALL    APPUTS
  958.  
  959. ASND4A:    MVI    C,30        ; ABOUT 4 SECONDS
  960. ASND4C:    LXI    D,2500H        ;
  961. ASND4:    CALL    GETSIN        ; GET HOST'S REPLY
  962.     JNZ    SND4B
  963.     CALL    TRMGET
  964.     CPI    ETX
  965.     JZ    ABORT        ; ABORT THE OPERATION IF ^C TYPED
  966.     DCX    D        ; DECREMENT INNER LOOP COUNT
  967.     MOV    A,D
  968.     ORA    E
  969.     JNZ    ASND4
  970.     DCR    C
  971.     JNZ    ASND4C
  972.     MVI    A,ETX        ; SEND EXTRA <ETX>
  973.     CALL    APPUTS
  974.     JMP    ASND4A
  975.  
  976. snd4b:
  977.     if    shoxfr
  978.     call    viodsp
  979.     endif
  980.     if    not shoxfr
  981.     call    viomrk
  982.     endif
  983.     CPI    '.'
  984.     RZ            ; RETURN IF HOST GOT IT OKAY
  985.     CPI    '/'        ; ELSE IF / 
  986.     JZ    APSND1        ; THEN RETRANSMIT THE MESSAGE
  987.     CPI    KNAK        ; ELSE IF <NAK>
  988.     JZ    ISSO        ; THEN ABORT
  989.     JMP    ASND4        ; ELSE KEEP WAITING
  990.  
  991. APPUTS:    PUSH    PSW        ; SAVE CHAR
  992.     CALL    GETSIN        ; CHECK MODEM FIRST
  993.     JZ    APPUT4        ; THEN
  994.     ani    7fh
  995.     CPI    KNAK        ; IF WE RECEIVE A <NAK>
  996.     JZ    ISSO        ; THEN SHUT DOWN THE PROTOCOL
  997.     CPI    DC3        ; IF X-OFF
  998.     JNZ    APPUT4        ; THEN
  999.     PUSH    D        ; DELAY A FEW SECONDS
  1000.     PUSH    B
  1001.     MVI    B,2
  1002. APPUT0:    LXI    D,8000H
  1003. APPUT1:    CALL    GETSIN        ; IF CHAR PRESENT
  1004.     JZ    APPUT2        ; THEN
  1005.     ani    7fh
  1006.     CPI    DC1        ; IF ^Q (XON)
  1007.     JZ    APPUT3        ; THEN EXIT
  1008. APPUT2:    DCX    D
  1009.     MOV    A,D
  1010.     ORA    E
  1011.     JNZ    APPUT1
  1012.     DCR    B
  1013.     JNZ    APPUT0
  1014. APPUT3:    POP    B        ; RESTORE REGS AND RETURN
  1015.     POP    D
  1016. APPUT4:    POP    PSW        ; GET CHAR
  1017.     CALL    PUTSIO        ; SEND CHAR
  1018.     RET
  1019.  
  1020.  
  1021. ; ROUTINE TO GET A CHARACTER FROM UART WITH WAIT
  1022.  
  1023. GETSIN:    CALL    GETSIO    ; RETURN SIO CHAR WITH BIT 7 = 0
  1024.     RZ
  1025.     ANI    7FH
  1026.     RET
  1027.  
  1028. GETSIX:    CALL    GETSIO    ; GET SIO CHAR OR WAIT
  1029.     JZ    GETSIX    ; WAIT FOR A CHARACTER
  1030.     CPI    KNAK    ; IF <NAK> RECEIVED
  1031.     JZ    ISSO    ; THEN REVERT TO TERMINAL MODE
  1032.     RET        ; RETURN
  1033.  
  1034.  
  1035. GETCKS:    CALL    GETSIX    ; GET NEXT SIO CHAR WITH CHECKSUMMING
  1036.     CPI    ETX    ; IF <ETX>
  1037.     RZ        ; THEN RETURN
  1038.     PUSH    PSW
  1039.     CPI    EOT
  1040.     JNZ    NOTEOT    ; THEN
  1041.     STA    APEOT    ; SET <EOT> SEEN FLAG
  1042. NOTEOT:    CPI    DLE    ; IF <DLE>
  1043.     JNZ    GETCK0    ; THEN
  1044.     CALL    GETSIX    ;    GET NEXT CHARACTER
  1045.     ANI    1FH    ;    MAKE CONTROL CHAR OF IT
  1046. GETCK0:    CALL    DOCKS    ; UPDATE CHECKSUM
  1047.     POP    PSW    ; RESTORE FLAGS
  1048.     MOV    A,D    ; RESTORE NEW CHAR
  1049.     RET        ; RETURN
  1050.  
  1051. DOCKS:    MOV    D,A    ; SAVE BYTE
  1052.     MOV    A,E    ; GET OLD CHECKSUM
  1053.     RLC        ; ROTATE ONE BIT LEFT
  1054.     ADD    D    ; ADD NEW BYTE
  1055.     ACI    0    ; ADD POSSIBLE CARRY
  1056.     MOV    E,A    ; REPLACE CHECKSUM WITH UPDATED ONE
  1057.     MOV    A,D    ; RESTORE NEW BYTE
  1058.     RET
  1059.  
  1060. ;    VARIOUS MESSAGE STRINGS
  1061.  
  1062. proini:    db    cr,lf,'% CSEXEC - Initializing file transfer',cr,lf,'$'
  1063. dnload:    db    cr,lf,'% CSEXEC - Beginning Download',cr,lf,'$'
  1064. upload:    db    cr,lf,'% CSEXEC - Beginning Upload',cr,lf,'$'
  1065. abload:    db    cr,lf,'? CSEXEC - Aborting file transfer',cr,lf,'$'
  1066. DLBOMB:    DB CR,LF,'% CSEXEC - That file already exists on your disk.',CR,LF
  1067.     DB    'Do you wish to replace it (Y or N) ? $'
  1068. CREMSG:    DB    cr,lf,'? CSEXEC - Diskette is full!',CR,LF,'$'
  1069. opnmsg:    db Cr,lf,'? CSEXEC - That file is not on your diskette!',cr,lf,'$'
  1070. wdrmsg:    db    cr,lf,'? CSEXEC - Your diskette is full!',cr,lf,'$'
  1071. dmsg:    db    cr,lf,'++DISCONNECTED++',cr,lf,'$'
  1072.  
  1073. ; I/O SUBROUTINES FOR SIO
  1074.  
  1075. SIOGET:    IN    CTL    ; GET MIO STATUS FLAGS
  1076.     ANI    SIOIR    ; ISOLATE INPUT READY FLAG
  1077.     if    not hitrue
  1078.     XRI    SIOIR    ; INVERT IT
  1079.     endif
  1080.     RZ        ; RETURN IF NOW 0
  1081.     IN    SIO    ; ELSE GET SIO CHARACTER
  1082.  
  1083.     if    shoxfr
  1084.     call    prodsp
  1085.     endif
  1086.     RET        ; AND RETURN (Z FLAG = 0)
  1087.  
  1088. SIOPUT:    PUSH    PSW    ; WRITE (A) TO SIO
  1089. PUTSI1:    IN    CTL    ; WAIT FOR FLAG TO = 0
  1090.     ANI    SIOTR
  1091.     if    not hitrue
  1092.     JNZ    PUTSI1
  1093.     endif
  1094.  
  1095.     if    hitrue
  1096.     jz    putsi1
  1097.     endif
  1098.     POP    PSW
  1099.     OUT    SIO
  1100.  
  1101.     if    shoxfr
  1102.     if    hz19
  1103.     push    psw
  1104.     mvi    a,esc    ; invert video for incoming characters
  1105.     call    viodsp
  1106.     mvi    a,'p'
  1107.     call    viodsp
  1108.     pop    psw
  1109.     push    psw
  1110.     call    prodsp
  1111.     mvi    a,esc
  1112.     call    viodsp
  1113.     mvi    a,'q'        ; return to normal video
  1114.     call    viodsp
  1115.     pop    psw
  1116.     endif
  1117.  
  1118.     if    not hz19
  1119.     call    prodsp
  1120.     endif
  1121.  
  1122.     endif
  1123.     RET
  1124.  
  1125. sioini:
  1126.     if    hz89
  1127.     mvi    a,3        ; init uart to
  1128.     out    sio+3        ; 8 data bits, 1 stop bit, no parity
  1129.     endif
  1130.  
  1131.     if    pmmi
  1132.     mvi    a,93        ; 8 data bits, 1 stop bit, no parity
  1133.     out    basprt
  1134.     mvi    a,52        ; 300 baud
  1135.     out    basprt+2
  1136.     mvi    a,127        ; originate mode
  1137.     out    basprt+3
  1138.     endif
  1139.  
  1140.     ret
  1141.  
  1142.     if    shoxfr
  1143. prodsp:    push    psw        ; save the character
  1144.     lda    shoflg        ; if in protocol
  1145.     ora    a
  1146.     jz    proter        ; then
  1147.     pop    psw
  1148.     push    psw
  1149.     ani    7fh        ; remove high-order bit
  1150.     cpi    ' '        ; if this is a control char
  1151.     jnc    proyes        ; then
  1152.     lda    xfrtyp        ; if doing a binary transfer
  1153.     cpi    'B'
  1154.     jz    pronot        ; then "flag" all control characters
  1155.     pop    psw        ; else flag only funny ones
  1156.     push    psw
  1157.     cpi    sholcc        ; is it a normal control character?
  1158.     jc    pronot        ; (ie, <HT> thru <RET>, 08h - 0Dh)
  1159.     cpi    shohcc+1
  1160.     jc    proyes
  1161. pronot:    mvi    a,'^'        ; flag the control character
  1162.     call    viodsp
  1163.     pop    psw
  1164.     push    psw
  1165.     adi    40h        ; map char to letter
  1166. proyes:    call    viodsp
  1167. proter:    pop    psw
  1168.     ret
  1169.  
  1170.     endif
  1171.  
  1172.     if    pmmi    ; routine to disconnect pmmi modem
  1173. discon:    mvi    a,03fh
  1174.     out    basprt+3
  1175.     xra    a
  1176.     out    basprt
  1177.     out    basprt+2
  1178.     lxi    d,dmsg    ; print disconnect msg
  1179.     mvi    c,fn$pcb
  1180.     call    bdos
  1181.     jmp    bbase    ; and exit
  1182.     endif
  1183.  
  1184. ;    RAM STORAGE AREA
  1185.  
  1186.     if    shoxfr
  1187. shoflg:    ds    1        ; 1 if in file transfer protocol
  1188.     endif
  1189.     if    not shoxfr
  1190. xfrctr:    ds    1        ; counter for displaying +'s
  1191.     endif
  1192. CPMSTK:    ds    2        ; SAVES CP/M'S STACK POINTER
  1193. CPMDEF:    ds    1        ; SAVES CP/M'S DEFAULT DISK DRIVE
  1194. PRTFLG:    ds    1    ; FF IF PRINTER ENABLED, 00 OTHERWISE
  1195. SIFLAG:    ds    1    ; NON-ZERO IMPLIES <SI> RECEIVED AND PROTOCOL ACTIVE
  1196. APEOT:    ds    1    ; NON ZERO IF <EOT> SEEN IN GETCKS
  1197. APFLG:    ds    1    ; 00 IF MASKING CONTROL CHARACTERS, FF IF NOT
  1198. xfrtyp:    ds    1    ; 'A' if ASCII, 'B' if binary
  1199. APADDR:    ds    2    ; POINTER TO BUFFER
  1200. APLEN:    DB    0    ; LENGTH OF RECORD AS RECEIVED
  1201. APBUF:    DS    256    ; STORAGE FOR THE RECORD
  1202. IBP:    DS    1    ; BYTE POINTER
  1203. APNXT:    DS    1    ; EXPECTED RECORD NUMBER
  1204. APCUR:    DS    1    ; CURRENT (RECEIVED) RECORD NUMBER
  1205.     DS    256    ; STACK GOES HERE
  1206. STACK:
  1207. HEAD:    DW    PRTBUF
  1208. TAIL:    DW    PRTBUF
  1209. LINCNT:    DB    PAGLEN
  1210. PRTBUF    EQU    $
  1211.  
  1212.     END    START
  1213.