home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / cpm / mex / mxm-cd10.aqm / MXM-CD10.ASM
Assembly Source File  |  1985-08-05  |  16KB  |  503 lines

  1.     TITLE    'MEX CONCORD DATA SYSTEMS 224 AD OVERLAY V1.0'
  2. ;
  3. ; (DELETE ABOVE TITLE LINE IF ASSEMBLING WITH ASM)
  4. ;
  5. ; MXM-CD10.ASM  Current version 27 Nov 84
  6. ;
  7. ; Concord Data Systems 224 AD modem overlay for MEX v1.x
  8. ;  Written 27 Nov 84 by Dave Mabry
  9. ;  Adapted using information and excerps from Ron Fowler's
  10. ;   overlay for the PMMI modem.
  11. ;
  12. ; Please leave any bug reports or requests on TCBBS in Dearborn,
  13. ;  Michigan (313-846-6127) or Royal Oak RCPM (313-759-6569)
  14. ;  or call me at 313-956-5703 (voice).        mabry
  15. ;
  16. ; Updates:
  17. ;  MXM-CD10.ASM
  18. ;   11/27/84...Original release.
  19. ;
  20. ; Note that unlike the Hayes modem, the Concord does not
  21. ;  have an ascii command that will cause a disconnect.  Therefore
  22. ;  for that feature of MEX to work properly, your normal overlay
  23. ;  for your machine must be able to toggle DTR in the DISCV routine.
  24. ;
  25. ; This overlay will work with any modem overlay that terminates
  26. ; prior to 0900H
  27. ;
  28. VERS    EQU    10        ; Version number
  29. FALSE    EQU    0
  30. TRUE    EQU    0FFH
  31. ;
  32. ;
  33. ; SYSTEM CONSTANTS
  34. ;
  35. DIALV    EQU    0162H        ;LOCATION OF DIAL VECTOR IN OVERLAY
  36. DISCV    EQU    0165H        ;LOCATION OF DISCONNECT VECTOR IN OVERLAY
  37. DIALOC    EQU    0900H        ;DIALING CODE GOES HERE
  38. SMINIT    EQU    0D55H        ; Vector to modem initialization routine
  39. ;
  40. ;
  41. ; MEX service processor stuff ... MEX supports an overlay service
  42. ; processor, located at 0D00H (and maintained at this address from
  43. ; version to version).  If your overlay needs to call BDOS for any
  44. ; reason, it should call MEX instead; function calls below about
  45. ; 240 are simply passed on to the BDOS (console and list I/O calls
  46. ; are specially handled to allow modem port queueing, which is why
  47. ; you should call MEX instead of BDOS).  MEX uses function calls
  48. ; above about 244 for special overlay services (described below).
  49. ;
  50. ; Some sophisticated overlays may need to do file I/O; if so, use
  51. ; the PARSFN MEX call with a pointer to the FCB in DE to parse out
  52. ; the name.  This FCB should support a spare byte immediately pre-
  53. ; ceeding the actual FCB (to contain user # information).  If you've
  54. ; used MEX-10 for input instead of BDOS-10 (or you're parsing part
  55. ; of a SET command line that's already been input), then MEX will
  56. ; take care of DU specs, and set up the FCB accordingly.  There-
  57. ; after all file I/O calls done through the MEX service processor
  58. ; will handle drive and user with no further effort necessary on
  59. ; the part of the programmer.
  60. ;
  61. MEX    EQU    0D00H        ;address of the service processor
  62. INMDM    EQU    255        ;get char from port to A, CY=no more in 100 ms
  63. TIMER    EQU    254        ;delay 100ms * reg B
  64. TMDINP    EQU    253        ;B=# secs to wait for char, cy=no char
  65. CHEKCC    EQU    252        ;check for ^C from KBD, Z=present
  66. SNDRDY    EQU    251        ;test for modem-send ready
  67. RCVRDY    EQU    250        ;test for modem-receive ready
  68. SNDCHR    EQU    249        ;send a character to the modem (after sndrdy)
  69. RCVCHR    EQU    248        ;recv a char from modem (after rcvrdy)
  70. LOOKUP    EQU    247        ;table search: see CMDTBL comments for info
  71. PARSFN    EQU    246        ;parse filename from input stream
  72. BDPARS    EQU    245        ;parse baud-rate from input stream
  73. SBLANK    EQU    244        ;scan input stream to next non-blank
  74. EVALA    EQU    243        ;evaluate numeric from input stream
  75. LKAHED    EQU    242        ;get nxt char w/o removing from input
  76. GNC    EQU    241        ;get char from input, cy=1 if none
  77. ILP    EQU    240        ;inline print
  78. DECOUT    EQU    239        ;decimal output
  79. PRBAUD    EQU    238        ;print baud rate
  80. PRNTBL    EQU    237        ;print MEX format table (HL)
  81. PRIN    EQU    236        ;print MEX ID string on console
  82. ;
  83. ;
  84. CONOUT    EQU    2        ;simulated BDOS function 2: console char out
  85. PRINT    EQU    9        ;simulated BDOS function 9: print string
  86. INBUF    EQU    10        ;input buffer, same structure as BDOS 10
  87. ;
  88. ;
  89. CR    EQU    0DH
  90. LF    EQU    0AH
  91. ESC    EQU    1BH
  92. ;
  93. ;
  94. MSPEED    EQU    107H        ; Modem speed byte
  95. B1200    EQU    5        ; Byte for 1200 baud
  96. B2400    EQU    6        ; Byte for 2400 baud
  97. NEWBDV    EQU    16EH        ; Entry point for new baud routine
  98. ;
  99. ;
  100.     ORG    SMINIT        ; Overlay the initialization vector
  101.     DW    INIT        ; Just the address
  102.  
  103.  
  104.     ORG    DIALV        ;OVERLAY THE DIALING VECTOR
  105.     JMP    DIAL
  106. ;    
  107. ;
  108. ; This is the DIAL routine called by MEX to dial a digit. The digit
  109. ; to be dialed is passed in the A register.  Note that two special
  110. ; codes must be intercepted as non-digits: 254 (start dial sequence)
  111. ; and 255 (end-dial sequence).  Mex will always call DIAL with 254
  112. ; in the accumulator prior to dialing a number.  Mex will also call
  113. ; dial with 255 in A as an indication that dialing is complete. Thus,
  114. ; the overlay may use these values to "block" the number, holding it
  115. ; in a buffer until it is completely assembled (in fact, that's the
  116. ; scheme employed here).
  117. ;
  118. ; After the 254-start-dial sequence, MEX will call the overlay with
  119. ; digits, one-at-a-time.  MEX will make no assumptions about the dig-
  120. ; its, and will send each to the DIAL routine un-inspected (some modems,
  121. ; like the Smartmodem, allow special non-numeric characters in the
  122. ; phone number, and MEX may make no assumptions about these).
  123. ;
  124. ; After receiving the end-dial sequence (255) the overlay must take
  125. ; whatever end-of-dial actions are necessary *including* waiting for
  126. ; carrier at the distant end.  The overlay should monitor the keyboard
  127. ; during this wait (using the MEX keystat service call), and return
  128. ; an exit code to MEX in the A register, as follows:
  129. ;
  130. ;    0 - Carrier detected, connection established
  131. ;    1 - Far end busy (only for modems that can detect this condition)
  132. ;    2 - No answer (or timed out waiting for modem response)
  133. ;    3 - Keyboard abort (^C only: all others should be ignored)
  134. ;    4 - Error reported by modem
  135. ;    5 - No ring reported by modem
  136. ;    6 - No dial tone reported by modem
  137. ;
  138. ; <No other codes should be returned after an end-dial sequence>
  139. ;
  140. ; The overlay should not loop forever in the carrier-wait routine, but
  141. ; instead use either the overlay timer vector, or the INMDMV (timed 100
  142. ; ms character wait) service call routine.
  143. ;
  144. ; The DIAL routine is free to use any of the registers, but must return
  145. ; the above code after an end-dial sequence
  146. ;
  147.     ORG    DIALOC
  148.  
  149. INIT:    ; Just to print a signon message
  150.     MVI    C,PRINT
  151.     LXI    D,SIGNON
  152.     CALL    MEX
  153.     RET
  154. ;
  155. DIAL:    LHLD    DIALPT        ;FETCH POINTER
  156.     CPI    254        ;START DIAL?
  157.     JZ    STDIAL        ;JUMP IF SO
  158.     CPI    255        ;END DIAL?
  159.     JZ    ENDIAL        ;JUMP IF SO
  160. ;
  161. ; Not start or end sequence, must be a digit to be sent to the modem
  162. ;
  163.     MOV    M,A        ;PUT CHAR IN BUFFER
  164.     INX    H        ;ADVANCE POINTER
  165.     SHLD    DIALPT        ;STUFF PNTR
  166.     RET            ;ALL DONE
  167. ;
  168. ; Here on a start-dial sequence
  169. ;
  170. STDIAL:    LXI    H,DIALBF    ;SET UP BUFFER POINTER
  171.     SHLD    DIALPT
  172.     RET
  173. ;
  174. ; Here on an end-dial sequence
  175. ;
  176. ENDIAL:
  177.     MVI    M,0        ; Terminate phone number string
  178.     XRA    A        ; Initialize baud flag
  179.     STA    BDFLAG
  180. ;
  181. ; Since the modem may not be at the same rate as the hardware and
  182. ;  we really have no way of knowing, we try the baud rate the
  183. ;  hardware is at first, and if the modem fails to respond in
  184. ;  about a half a second then assume it is at the other baud rate.
  185. ;  So try that baud rate.  If the modem still fails to respond, then
  186. ;  return to mex with a MODEM ERROR code.
  187. ;
  188. CLEAR:
  189.     MVI    C,INMDM        ; Clear out the data buffer in USART
  190.     CALL    MEX
  191.     JNC    CLEAR        ; Get them all
  192.     LXI    H,WAKEUP    ; Get modem's attention
  193.     CALL    CDSEND
  194.     MVI    C,5        ; ~.5 second wait
  195.     CALL    CATCHR        ; Catch response from modem
  196.     ORA    A        ; Check response
  197.     JZ    AROUND        ; If there was a response, then modem
  198.                 ;  and system were at same baud rate
  199.     CPI    3        ; User typed ^C ?
  200.     RZ            ; If yes, abort to mex
  201.     LXI    H,BDFLAG    ; Check to see if we have tried this
  202.     MOV    A,M        ;  before
  203.     ORA    A        ; True means yes
  204.     JNZ    ERRET
  205.     MVI    M,TRUE        ; If false, then make it true now
  206.     LDA    MSPEED        ; Get original baud rate
  207.     STA    MSSAVE        ; Save it temporarily
  208.     CPI    B1200        ; Was first try at 1200 baud ?
  209.     LXI    H,BDCMD+1    ; Point to second char of baud set command
  210.     JZ    CLR05        ; Yes, go try 2400
  211.     CPI    B2400        ; Was first try at 2400 baud ?
  212.     JNZ    ERRET        ; If not one of the two, then error
  213.     MVI    A,B1200
  214.     MVI    M,'H'        ; If changing baud to 1200, need to change
  215.     JMP    CLR10        ;  it back to 2400 later
  216. CLR05:
  217.     MVI    A,B2400        ; Now set to 2400 baud
  218.     MVI    M,'L'        ; Later must set back to 1200
  219. CLR10:
  220.     CALL    NEWBDV        ; ***This must be in hardware overlay***
  221.     JMP    CLEAR
  222. AROUND:
  223.     LDA    BDFLAG
  224.     ORA    A        ; Need to reset baud rate ?
  225.     JZ    CLR15        ; No, just continue
  226.  
  227.     LXI    H,BDCMD        ; Send modem speed command
  228.     CALL    CDSEND
  229. ; Now must wait for last character to be fully shifted out of USART
  230.     MVI    C,TIMER
  231.     MVI    B,2        ; 200ms should be plenty of time
  232.     CALL    MEX
  233.     LDA    MSSAVE        ; Get original baud rate
  234.     CALL    NEWBDV        ; Set hardware to old baud rate
  235.     MVI    C,INMDM        ; Clear out any characters we might
  236.     CALL    MEX        ;  have missed while changing baud rates
  237.     JNC    $-5        ; Loop til all bytes removed from USART
  238. CLR15:
  239.     LXI    H,DCMD        ; Send "dial" command and # to modem
  240.     CALL    CDSEND
  241.     CALL    SENDCR        ; Send <cr> to terminate phone number
  242. ;
  243. ; Here starts the main loop waiting for messages from the modem
  244. ;  and interpreting them.  Some are just passed to the console
  245. ;  and others trigger a specific action.
  246. ;
  247. DLOOP:
  248.     MVI    C,255        ; Long wait here
  249.     CALL    CATCHR        ; Catch response from modem
  250.     ORA    A        ; Zero return code ?
  251.     JNZ    IDLE        ; No, disconnect and return error code
  252.     MOV    A,B        ; Get character count from CATCHR
  253.     ORA    A        ; Hope it isn't zero
  254.     JZ    DLOOP        ; If it is, then ignore this response
  255.     LXI    H,RESPBF    ; Point to string from modem
  256.     LXI    D,RSPTBL    ; Point to valid response table
  257.     CALL    COMPR        ; Find out which response we got
  258.     MOV    A,B        ; Get return value
  259.     CPI    255        ; No response match
  260.     JNZ    DIAL05
  261. ERRET:
  262.     MVI    A,4        ; Error return to MEX
  263.     JMP    IDLE        ; Disconnect and return error code
  264. DIAL05:
  265.     CPI    3        ; OK ?
  266.     JZ    DLOOP        ; Ignore this one
  267.     ORA    A        ; Need to know if 0 ==> connected
  268.     RZ            ; Only this code can return w/o disconnecting
  269.     CPI    7        ; If <= 6 then let it return to MEX
  270.     JC    IDLE
  271.     JNZ    DIAL10        ; If not 7 (7 = voice)
  272.     MVI    A,1
  273.     JMP    IDLE        ; Return BUSY code to MEX
  274. DIAL10:
  275.     CPI    8        ; Call fail ?
  276.     JZ    ERRET        ; Return modem error code
  277.     CPI    13        ; Between 9 and 12 (inclusive) ?
  278.     JNC    DLOOP        ; Ignore 13 and above (13 = dial tone)
  279. ; At this point the match code from COMPR is between 9 and 12 inclusive.
  280. ;  Use this number as an offset into a table of messages, print the
  281. ;  appropriate message and continue to loop.
  282.     SUI    9        ; Now between 0 and 3
  283.     RLC            ; *2
  284.     RLC            ; *4
  285.     RLC            ; *8
  286.     MVI    B,0
  287.     MOV    C,A        ; BC contain offset
  288.     LXI    H,MSGS        ; Point to messages table
  289.     DAD    B        ; Index into it
  290.     XCHG            ; Pointer to message into DE
  291.     MVI    C,9        ; Let mex to string print
  292.     CALL    MEX
  293.     LXI    D,COMSP        ; Print ", "
  294.     MVI    C,9
  295.     CALL    MEX
  296.     JMP    DLOOP        ; And continue to loop
  297.  
  298.  
  299. ;
  300. IDLE:
  301. ;
  302. ; Forces modem into idle state by sending "idle" command and
  303. ;  then toggling DTR using the user's DISCV entry.
  304. ; Preserves any return code that may be in register A.
  305. ;
  306.     PUSH    PSW        ; Preserve any return code
  307.     LXI    H,IDLCMD    ; Send abort character to modem
  308.     CALL    CDSEND
  309.     CALL    DISCV        ; Make sure modem disconnects
  310.     POP    PSW        ; Retrieve return code
  311.     RET
  312.  
  313. SENDCR:
  314. ;
  315. ; Sends a carriage return character to the modem.
  316. ;
  317.     LXI    H,CRMSG        ; Send <cr> to modem
  318.     JMP    CDSEND
  319.  
  320.  
  321. ; Table of valid responses from modem
  322. RSPTBL:
  323.     DB    'IN',0        ; Initiating
  324.     DB    'BSY',0        ; Busy
  325.     DB    'NOA',0        ; No answer
  326.     DB    'OK',0        ; Signon
  327.     DB    'NOT',0        ; No answer tone
  328.     DB    'NOR',0        ; No ring
  329.     DB    'NDT',0        ; No dial tone
  330.     DB    'VDT',0        ; Voice detected
  331.     DB    'CFL',0        ; Call failed
  332.     DB    'DG',0        ; Dialing
  333.     DB    'RG',0        ; Ringing
  334.     DB    'AT',0        ; Answer tone
  335.     DB    'AR',0        ; Answer
  336.     DB    'DT',0        ; Dial tone
  337.     DB    0        ; Table terminator
  338.  
  339. ; Table of messages for some of the entries in the above table.
  340. ;  Each entry must be exactly eight characters including the "$".
  341. MSGS:
  342.     DB    'dialing$'
  343.     DB    'ringing$'
  344.     DB    'anstone$'
  345.     DB    'answer$ '
  346.  
  347. COMSP:
  348.     DB    ', $'        ; To delimit messages
  349.  
  350. COMPR:
  351. ; Compares a string of characters in memory to a table of
  352. ;  strings.  Each entry of the table must be terminated by
  353. ;  a zero byte, and the table must be terminated by another
  354. ;  zero byte.
  355. ; Inputs:  HL points to the string to look for
  356. ;       DE points to the table
  357. ; Output:  B contains the number of the table entry that
  358. ;         matches the string, and a 255 if no entry matched.
  359. ;
  360.     MVI    B,0        ; Init index
  361. CMPR02:
  362.     PUSH    H        ; Save pointer to string in question
  363. CMPR05:
  364.     LDAX    D        ; Fetch char from table
  365.     ORA    A        ; Is it end of table entry ?
  366.     JNZ    CMPR10        ; Not end of entry
  367.     POP    H
  368.     RET            ; Return with match code in B
  369. CMPR10:
  370.     CMP    M        ; Same as char in string ?
  371.     JNZ    CMPR15        ; Jump if not this entry in table
  372.     INX    H        ; Else, point to next char in string
  373.     INX    D        ;  and next char in table entry
  374.     JMP    CMPR05        ; Check next char
  375. CMPR15:
  376.     INR    B        ; Increment index
  377. CMPR20:
  378.     INX    D        ; Next char in table
  379.     LDAX    D        ; Get next char from table
  380.     ORA    A        ; Is it last char in that entry ?
  381.     JNZ    CMPR20        ; No, keep looking
  382.     INX    D        ; Yes, then point to first char of next one
  383.     LDAX    D        ; Now check for end of table
  384.     ORA    A        ; Zero delimits table
  385.     POP    H        ; Point to original string again
  386.     JNZ    CMPR02        ; Go check next table entry
  387.     MVI    B,255        ; No match return code
  388.     RET
  389.  
  390.  
  391. CATCHR:
  392. ;
  393. ; Catch response from modem.
  394. ; Input:  C  delay allowed before timeout (multiples of 100ms)
  395. ; Output: Buffer (RESPBF) contains the string received from modem with
  396. ;       any control characters filtered out.
  397. ;      C  count of characters received before <cr>
  398. ;      A  error code:  0 ==> normal return
  399. ;              2 ==> time out occurred
  400. ;              3 ==> user typed ^C
  401. ;
  402.     LXI    H,RESPBF
  403.     PUSH    H
  404.     MVI    B,BUFLEN    ; Length of character buffer
  405. CRL10:
  406.     MVI    M,0        ; Fill buffer with zeros
  407.     INX    H
  408.     DCR    B
  409.     JNZ    CRL10
  410.     POP    H        ; Get original pointer
  411.     MVI    B,0        ; Character counter
  412. CRLOOP:
  413.     MOV    D,C        ; Initialize count down timer
  414. CRL05:
  415.     PUSH    B        ; Save character counter
  416.     PUSH    D        ; Save time out count down
  417.     PUSH    H        ; Save buffer pointer
  418.     MVI    C,CHEKCC    ; See if user typed ^C
  419.     CALL    MEX
  420.     JZ    UABORT        ; If yes, jump to user abort code
  421.     MVI    C,INMDM        ; Else, continue
  422.     CALL    MEX        ; Get char in 1ms if available
  423.     POP    H        ; Restore working registers
  424.     POP    D
  425.     POP    B
  426.     JC    NOCHAR        ; If no char in 1ms, handle it
  427.     ANI    7FH        ; Mask any parity bit
  428.     CPI    CR        ; End of line from modem ?
  429.     JZ    EOL        ; If <cr> then end of line
  430.     MOV    M,A        ; Here we have a valid character
  431.     INX    H        ;  so save it and bump pointer
  432.     INR    B        ; Increment character counter also
  433.     JMP    CRLOOP        ; Go get the next one
  434.  
  435. ;
  436. ; Handle no character from modem in 1ms
  437. ;
  438. NOCHAR:
  439.     DCR    D        ; Decrement time out counter
  440.     JNZ    CRL05        ; If not to zero, wait some more
  441.     MOV    C,B        ; Else, return with what we have now
  442.     MVI    A,2        ; Time-out error code
  443.     RET
  444. ;
  445. ; End of line from modem
  446. ;
  447. EOL:
  448.     MOV    C,B        ; Character count
  449.     XRA    A        ; Return zero
  450.     RET
  451. ;
  452. ; User abort from ^C
  453. ;
  454. UABORT:
  455.     CALL    IDLE        ; Force disconnect
  456.     POP    H        ; Since these are still on the stack
  457.     POP    D
  458.     POP    B
  459.     MOV    C,B        ; Count of characters up to now
  460.     MVI    A,3        ; User abort code
  461.     RET
  462.  
  463. ;
  464. ; Sends a string of characters pointed to by HL terminated by zero
  465. ;
  466. CDSEND:
  467.     MVI    C,SNDRDY    ; Get modem send status
  468.     CALL    MEX
  469.     JNZ    CDSEND        ; Wait for modem ready
  470.     MOV    A,M        ; Get character
  471.     INX    H        ; Point to next character
  472.     ORA    A        ; Is this the terminator ?
  473.     RZ            ; If yes, done
  474.     MOV    B,A        ; Pass character in B
  475.     MVI    C,SNDCHR    ; Let MEX send to modem
  476.     CALL    MEX
  477.     JMP    CDSEND
  478.  
  479. ;
  480. ; DATA AREA
  481. ;
  482. SIGNON:
  483.     DB    '(Modem overlay for Concord Data Systems 224 AutoDial  V'
  484.     DB    VERS/10 + '0', '.', (VERS MOD 10) + '0'
  485.     DB    ')$'
  486. ; Wakeup string to put modem into "interactive DTE" mode
  487. WAKEUP:    DB    ESC,CR,CR,'B',CR,0 ; String to wake up modem
  488. IDLCMD:    DB    ESC,0        ; Idle command
  489. BDCMD:    DB    'SL'        ; Set baud command
  490. CRMSG:    DB    CR,0        ; Note, this is end of LSCMD also
  491.  
  492. DCMD:    DB    'DM'        ; Dial command to modem
  493. DIALBF:    DS    30        ; Phone number buffer
  494.  
  495. BUFLEN    EQU    8        ; Length of response buffer
  496. RESPBF:    DS    BUFLEN        ; Response from modem
  497. DIALPT:    DS    2        ;DIAL POSITION POINTER
  498. MSSAVE:    DS    1        ; Save location for original baud rate
  499. BDFLAG:    DS    1        ; Flag for baud rate changed
  500. ;
  501.  
  502.     END
  503.