home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / modem / glassmdm.asm < prev    next >
Assembly Source File  |  1994-03-04  |  18KB  |  803 lines

  1.     title    glassmodem.asm Glass TTY routine for IBM VCAPI
  2.     Page    60,132
  3. ;
  4. ;    This ain't beautiful code. It just evolved this way.
  5. ;    I could have spent more time cleaning things up.
  6. ;    It should be useful as a guide as to how to call the 
  7. ;    IBM Voice Communication Application Program Interface.
  8. ;    This has only been tested with Microsoft MASM 4.0
  9. ;
  10. ;    The program takes the number to be dialed from the command
  11. ;    line. What ever garbage you put on the command line will be
  12. ;    fed to the dial routine.
  13. ;
  14. ;    Control break exits
  15. ;    F10 prints error summary there are more errors than their ought to be!
  16. ;    It is left as an exercise to the reader to make F9 send a break
  17. ;
  18. ;    There are two modules in this file  the last one is called ERR.
  19. ;    It should be assembled seperately.
  20. ;    Use the following to link these files:
  21. ;
  22. ;    link glasmode+err/dosseg,glasmode,glasmode/map;
  23. ;
  24. ;    Note the /dosseg flag this puts the zzrom segment last in 
  25. ;    memory. There is probably some way to get the last memory from
  26. ;    the prefix header, but that has always been an unfathomable mystery
  27. ;    to me. 
  28.  
  29.     include    veqts.asm
  30. sseg    segment    para    stack
  31.     db    100 dup('STACK')
  32. sseg    ends
  33. zzrom    segment     public 'dseg'
  34. zzrom    ends
  35. ;
  36. code    segment    para public 'code'
  37.     assume    cs:code,ss:sseg,ds:dyseg,es:dyseg
  38.     extrn    uerr:near    ;Load code to print string
  39.     extrn    nout:near    ;print number in decimal
  40.     extrn    hout:near    ;print byte in hex
  41.     extrn    perr:near    ;writes dos error code
  42.     extrn    getlast:near    ;gets last location loaded in memory
  43.     public    main
  44. main    proc    far
  45.     mov    ax,es        ;shrink allocated memory
  46.     mov    bx,zzrom    ;IBM resident code does dynamic memory
  47.     sub    bx,ax        ;allocation so we must give it back first
  48.     call    getlast        ;so some is available
  49.     add    bx,ax
  50.     mov    ah,4ah
  51.     int    dos
  52.     jnc    dispok
  53.     jmp    hbye        ;Thats all folks
  54. dispok:    lea    bx,dyseglen    ;Length in bytes of dynamic memory
  55.     push    ds        ;save prefix
  56.     call    getmemory    ;gets dynamic memory
  57.     jnc    memok
  58.     jmp    hbye
  59. memok:    pop    ax
  60.     mov    prefix,ax    ;prefix segment needed later
  61.     xor    ax,ax        ;zero modem error counts
  62.     mov    framec,ax
  63.     mov    parityc,ax
  64.     mov    overunc,ax
  65. ;
  66. ;    open VCAPI
  67. ;
  68.     mov    ax,255        ;wierd return code
  69.     mov    ret,ax        ;if unchanged there is no card
  70.     mov    ah,11h        ;VCAPI id
  71.     mov    al,open        ;function code for open
  72.     mov    dx,21fh        ;Card I/O address
  73.     lea    bx,plist    ;Address of parameter list
  74. ;
  75. ; note DS register will be used by interrupt routines
  76. ;
  77.     int    14h            ;invoke open
  78.     or    ax,ax            ;IBM could save a lot by using cc
  79.     je    openok            ;Continue if no error
  80.     mov    ax,ret            ;perhaps not installed
  81.     cmp    ax,255
  82.     jne    operr
  83.     mov    ax,2            ;Tell world vcapi not installed
  84.     call    uerr
  85.     jmp    hbye
  86. operr:    mov    bx,open            ;Let world know what we were doing
  87.     jmp    errcod
  88. openok:    lea    bx,parms        ;bx always points to parameter list
  89. chkerr    =    1            ;print errors if they happen
  90.  
  91. ;
  92. ;grab hardware we need
  93. ;
  94.     stuf2    claimhdw,rcb,bid,port1+line1+part1+part2+telephone,0,claimok
  95. ;
  96. ;connect function to port
  97. ;
  98. claimok:
  99.     stuf2    connftop,cid1,bid,port1,telephony,cftpok
  100. ;
  101. ;see if we can load modem in part 2
  102. ;
  103. cftpok:
  104.     stuf2    connftop,cid2,bid,port1,amodem,cftpok2
  105. ;
  106. ;read modem configuration values
  107. ;
  108. cftpok2:
  109.     stuf    rconfig,cid2,cid2,rcok
  110. ;
  111. ;set new modem config values
  112. ;
  113. rcok:
  114.     mov    [bx].rate,12        ;set baud 1200
  115.     mov    [bx].length,8        ;8 bit bytes
  116.     mov    [bx].parity,0        ;no parity
  117.  
  118. ;
  119. ;set these new values
  120. ;
  121.     stuf    cconfig,cid2,cid2,stok
  122. ;
  123. ;connect devices to port
  124. ;
  125. stok:    stuf2    conndtop,rcb,bid,port1,line1,cdtpok
  126. ;
  127. ;disconnect line 1 
  128. ;
  129. cdtpok:
  130.     stuf1    dcondevs,rcb,bid,line1,disconok
  131. ;
  132. ;set up interrupt for bid with special macro
  133. ;
  134. disconok:stuf3s    estint,rcb,bid,comdcomplet,1,baseint,bestiok
  135. ;
  136. ;    allow command complete interrupt to work
  137. ;
  138. bestiok:mov    ax,comdcomplet
  139.     call    benaints
  140. ;
  141. ;    pick up the phone
  142. ;
  143.     stuf1    offhook,rcb,bid,1,offhok ;Note equate for line1 is 10h not 1
  144. offhok:    mov    ax,50            ;Wait 5 seconds
  145.     call    wait
  146.     jnc    offok
  147. offok:    mov    ret,0
  148. ;
  149. ;link interrupts to interrupt routine
  150. ;
  151.     stuf3s    estint,cid1,cid1,readcallprogc+dialcomplete,1,cid1int,esti1ok
  152. esti1ok:mov    ax,readcallprogc+dialcomplete
  153.     mov    dx,cid1
  154.     call    cenaints
  155. ;
  156. ;    see whether we got a dial tone
  157. ;
  158.     stuf4    readcall,cid1,cid1,70,70,0,0,rdok
  159. rdok:    mov    ax,100            ;wait 10 seconds
  160.     call    wait
  161.     jnc    rdcok
  162.     mov    ax,5            ;Tell world we timed out
  163.     call    uerr
  164.     jmp    hbye
  165. rdcok:    cmp    [bx].subints2,dialtone
  166.     jz    gotdt
  167.     mov    ax,6
  168.     call    uerr
  169.     jmp    hbye
  170. gotdt:    lea    di,[bx].w2
  171.     mov    ds,prefix
  172.     mov    al,byte ptr ds:80h ;count of characters on command line
  173.     mov    si,81h        ;point to characters on command line
  174.     and    ax,0fh        ;Only allow 15 characters
  175.     mov    cx,ax
  176.     rep    movsb
  177.     mov    al,':'
  178.     stosb
  179.     push    es
  180.     pop    ds        ;restore dynamic segment
  181.     mov    ax,1100h+dial        ;dial the number
  182.     mov    dx,cid1
  183.     mov    [bx].w1,dx
  184.     int    14h
  185.     or    ax,ax            ;test return code
  186.     jz    dialok
  187.     mov    bx,dial
  188.     jmp    errcod
  189. dialok:    mov    ax,200
  190.     call    wait
  191.     jnc    dialdone
  192.     mov    ax,5            ;Tell world we timed out
  193.     call    uerr
  194.     jmp    hbye
  195. ;
  196. ;    see what we got at other end of phone
  197. ;    this part of the code is weak and doesn't work for all
  198. ;    phones. A bit of fiddeling with parameters and a more intelligent
  199. ;    retry mechanism would be nice. Also if a person answers the phone
  200. ;    it would be polite to give the operator a chance to pick up the
  201. ;    phone so they could talk.
  202. ;
  203. dialdone:stuf4    readcall,cid1,cid1,70,70,0,0,rdok2
  204. rdok2:    mov    ax,100            ;wait 10 seconds (more than 7 sec!)
  205.     call    wait
  206.     jnc    rdcdok
  207.     mov    ax,5            ;Tell world we timed out
  208.     call    uerr
  209.     jmp    hbye
  210. rdcdok:    cmp    [bx].subints2,carrier
  211.     jz    gotcar
  212.     cmp    [bx].subints2,ringback
  213.     jnz    wrdans
  214.     mov    ax,9            ;tell em it is ringing
  215.     call    uerr
  216.     mov    ah,06            ;check console
  217.     mov    dl,0ffh
  218.     int    dos
  219.     lea    bx,parms        ;dos clobbered this
  220.     jz    rdok2            ;wait for another ring
  221.     jmp    hbye
  222. wrdans:    cmp    [bx].subints2,busy
  223.     jz    gotbus
  224.     cmp    [bx].subints2,fastbusy
  225.     jnz    whtnxt
  226. gotbus:    mov    ax,10
  227.     call    uerr            ;announce phone is busy
  228.     jmp    hbye
  229. ;
  230. ;    we could ask user to pick up phone to see if we got a person
  231. ;    or something but we are just interested in a carrier
  232. ;
  233. whtnxt:    mov    ax,7
  234.     call    uerr
  235.     jmp    hbye
  236. gotcar:    mov    ax,8
  237.     call    uerr
  238.     lea    ax,cbuff        ;initialise circular pointers
  239.     mov    tailptr,ax
  240.     mov    headptr,ax
  241. ;
  242. ;    hook up to interrupt routine for incomming characters
  243. ;
  244.     stuf3s    estint,cid2,cid2,dataready,1,rcvint,esti2ok
  245. esti2ok:
  246. ;
  247. ;hook up routine to count errors
  248. ;
  249.     stuf3s    estint,cid2,cid2,linerr,1,errint,esti3ok
  250. esti3ok:
  251.     mov    ax,lnkstatus
  252.     mov    dx,cid2            ;for this cid
  253.     call    cenaints
  254. ;
  255. ;    start modem going
  256. ;
  257.     stuf    start,cid2,cid2,strtok
  258. strtok:    stuf    readstat,cid2,cid2,chkints
  259. chkints:mov    ax,[bx].ints
  260.     test    ax,lnkstatus
  261.     jz    strtok
  262.     mov    ax,[bx].subints1    ;these bits tell if modem started OK
  263.     and    ax,0f0h
  264.     jz    watup
  265.     mov    ax,11
  266.     call    uerr
  267.     jmp    hbye
  268. watup:    mov    ax,0fh            ;enable all interrupts
  269.     mov    dx,cid2            ;for this cid
  270.     call    cenaints
  271. ;
  272. ;    here is main glasstty loop
  273. ;
  274.     public    sndok
  275. sndok:    MOV    AH,1        ; CHARACTER TYPED?
  276.     INT    16H        ; BIOS KBD
  277.     JZ    NOKEY        ; JUMP IF NOT
  278.     MOV    AH,0        ; READ CHAR TYPED
  279.     INT    16H        ; BIOS KBD
  280.     OR    AX,AX        ; CONTROL BREAK?
  281.     jnz    gotkey
  282.     jmp    hbye        ;punt
  283. gotkey:    cmp    ax,4400h    ;F10?
  284.     jne    not_f10        ;Jump if not
  285.     jmp    prtsum        ;print error summary for f10
  286. not_f10:and    ax,7fh
  287.     push    ax
  288. watup3:    stuf    readstat,cid2,cid2,tstup2
  289. tstup2:    mov    ax,[bx].state
  290.     test    ax,modemstrt+statxmitrdy
  291.     jz    watup3
  292.     pop    ax
  293.     mov    [bx].w2,ax    ;character to be sent
  294.     stuf    send,cid2,cid2,sndok
  295. ;
  296. ;no fall through here
  297. ;
  298. nokey:    mov    si,headptr    ;see if anything is in circular buffer
  299.     cmp    si,tailptr
  300.     jnz    carin
  301.     jmp    sndok
  302. carin:    lodsb
  303.     cmp    si,offset bufend
  304.     jnz    nowrap
  305.     lea    si,cbuff
  306. nowrap:    mov    headptr,si
  307.     MOV    AH,14        ; WRITE TTY
  308.     INT    10H        ; BIOS VIDEO
  309.     jmp    sndok
  310. ;
  311. ;    print error summary
  312. ;
  313. prtsum:    mov    ax,parityc
  314.     or    ax,ax
  315.     jz    noparer
  316.     call    nout
  317.     mov    ax,12
  318.     call    uerr
  319. noparer:mov    ax,framec
  320.     or    ax,ax
  321.     jz    noframer
  322.     call    nout
  323.     mov    ax,13
  324.     call    uerr
  325. noframer:mov    ax,overunc
  326.     or    ax,ax
  327.     jz    noverun
  328.     call    nout
  329.     mov    ax,14
  330.     call    uerr
  331. noverun:add    ax,framec    ;Were there any errors?
  332.     add    ax,parityc
  333.     jnz    diderr
  334.     mov    ax,15        ;tell em no errors
  335.     call    uerr
  336. diderr:    jmp    sndok        ; control break exits
  337.  
  338. main    endp
  339. ;
  340. ;    interrupt routine for incomming character
  341. ;
  342. rcvint    proc    far
  343.     push    ds
  344.     pop    es        ;IBM wasn't good enough to do this for us
  345. chkerr    =    0        ;don't print errors from int code
  346.     lea    bx,iparms    ;int code gets own copy of parm area
  347.     stuf    receive,cid2,cid2,yepchr
  348. yepchr:    mov    ax,[bx].w2        ;here be character
  349.     mov    di,tailptr
  350.     and    al,07fh
  351.     stosb
  352.     cmp    di,offset bufend ;stuff incomming char in circular buffer
  353.     jnz    notwrap
  354.     lea    di,cbuff
  355. notwrap:mov    tailptr,di
  356.     ret
  357. chkerr    =    1            ;print errors if they happen
  358.  
  359. rcvint    endp
  360. ;
  361. ;    interrupt routine for base function complete
  362. ;
  363. baseint    proc    far
  364.     public    baseint
  365.     mov    dx,bid
  366.     mov    ax,rcb            ;do real simple setup for
  367. rdstx:    lea    bx,parms        ;readstat command
  368.     mov    [bx].w1,ax
  369.     mov    ax,1100h+readstat
  370.     push    ds
  371.     pop    es            ;IBM doesn't restore es!!
  372.     int    14h
  373. ;
  374. ;If this fails we are dead anyway so don't bother checking
  375. ;
  376.     mov    ret,1            ;signal foreground something happened
  377.     ret
  378. baseint    endp
  379. ;
  380. ;    interrupt routine for cid1 interrupts is just as simple
  381. ;
  382. cid1int    proc
  383.     public    cid1int
  384.     mov    ax,cid1
  385.     mov    dx,ax
  386.     jmp    rdstx
  387. cid1int    endp
  388. ;
  389. ;    errint    adds one to the error count for what ever is ailing us
  390. ;
  391. errint    proc    far
  392.     public    errint
  393.     push    ds
  394.     pop    es        ;IBM wasn't good enough to do this for us
  395. chkerr    =    0        ;don't print errors from int code
  396.     lea    bx,iparms    ;int code gets own copy of parm area
  397.     stuf    readstat,cid2,cid2,cnters
  398. cnters:    mov    ax,[bx].subints1
  399.     test    al,1
  400.     jz    tstpar
  401.     inc    overunc
  402. tstpar:    test    al,2
  403.     jz    tstfrm
  404.     inc    parityc
  405. tstfrm:    test    al,4
  406.     jz    nofrm
  407.     inc    framec
  408. nofrm:    ret
  409. errint    endp
  410. ;
  411. ;    print message saying this is vcapi return code presumably uerr
  412. ;    was called so the user is informed as to which call failed
  413. ;    error code passed as 16 bits in AX command code in BL
  414. ;
  415. errcod    proc    near
  416.     push    ax        ;save error code
  417.     push    bx
  418.     mov    ax,-3        ;print message saying here is command code
  419.     call    uerr
  420.     pop    ax
  421.     call    hout        ;hex the command code
  422.     mov    ax,-4        ;print message saying here is errorcode
  423.     call    uerr
  424.     pop    ax
  425.     call    nout        ;manual gives errors in decimal
  426.     xor    ax,ax
  427.     call    uerr        ;prints crlf
  428.     jmp    hbye        ;always a fatal error
  429. errcod    endp
  430. benaints proc    near
  431. ;
  432. ;This could be done by macro byt since it gets called so many times...
  433. ;
  434. ;    Interrupt mask passed in AX
  435. ;    BX as always points to parameter list
  436. ;
  437.     mov    [bx].w2,ax    ;Interrupt mask
  438.     mov    ax,rcb
  439.     mov    [bx].w1,ax
  440.     mov    dx,bid
  441. enaj:    mov    ax,1100h+maskint
  442.     int    14h
  443.     or    ax,ax
  444.     jc    badmask
  445.     ret
  446. badmask:mov    bx,maskint
  447.     jmp    errcod        ;don't mind not popping stack
  448. benaints    endp
  449. cenaints proc    near
  450. ;
  451. ;This could be done by macro byt since it gets called so many times...
  452. ;
  453. ;    Interrupt mask passed in AX
  454. ;    BX as always points to parameter list
  455. ;
  456.     mov    [bx].w2,ax    ;Interrupt mask
  457.     mov    [bx].w1,dx
  458.     jmp    enaj
  459. cenaints    endp
  460. getmemory proc near
  461. ;
  462. ;This gets dynamic memory in C or Pascal environment call the heap allocator
  463. ;or Windows or Topview (or whatever) memory allocator. This should have
  464. ;conditional assembly parameters to support all those good things. Currently
  465. ;just ask DOS.
  466. ;
  467. ;On entry BX contains bytes required
  468. ;On exit DS and ES point to segment
  469. ;
  470.     add    bx,10h        ;round to paragraph
  471.     mov    cl,4
  472.     shr    bx,cl
  473.     mov    ah,48h        ;Allocate memory function
  474.     int    dos
  475.     jnc    aok
  476.     push    ax        ;save return code
  477.     mov    ax,-1        ;tell world memory allocate 
  478.     call    uerr
  479.     pop    ax
  480.     call    perr        ;prints DOS error
  481.     stc
  482. aok:    mov    ds,ax        ;set segment registers
  483.     mov    es,ax        ;invalid if carry set
  484.     ret
  485.  
  486. getmemory endp
  487. ;
  488. ;    Local timer to check on board uses stack space this is a busy
  489. ;    wait timer. If running in an environment with real tasking support
  490. ;    replace this code with something better!!!!
  491. ;
  492. strtc    proc    near
  493.     xor    ah,ah        ; read clock
  494.     int    btod        ; BIOS time-of-day routine
  495.     mov    [bp],cx        ; high portion of clock
  496.     mov    [bp].2,dx    ; low portion of clock
  497.     ret
  498. strtc    endp
  499. dw_mpd        dw    1000/10        ; msecs per decisecond
  500. dw_tick_len    dw    tick_len    ; timer tick in msecs
  501. chk_timr proc    near
  502.     mov    ah,0        ;read clock
  503.     int    btod        ;BIOS time-of-day routine
  504.     sub    dx,[bp].2
  505.     sbb    cx,[bp]
  506.     mov    ax,dx        ;Prepare for mul/div
  507.     mov    dx,cx        ; ax=lo, dx=hi
  508.     mul    dw_tick_len    ;Convert ticks
  509.     div    dw_mpd        ;to 100 msec ticks
  510.     cmp    ax,[bp].4    ;Wait for specified time
  511.     ret
  512. chk_timr endp
  513. ;
  514. ;    Wait waits for an event or for timer to expire.
  515. ;    Carry exit means time expired. This can be replaced by
  516. ;    something that actually causes a context switch when DOS grows up
  517. ;
  518. wait    proc    near  ;AX contains time in deciseconds in AX
  519.     push    bx
  520.     strt_timr
  521. cloop0:    test    ret,1        ;This bit gets set when interrupt routine
  522.     jne    donwat        ;is run
  523.     call    chk_timr
  524.     jl    cloop0
  525.     add    sp,6        ;pop stack
  526.     pop    bx
  527.     stc            ;error exit
  528.     ret
  529. donwat:    add    sp,6
  530.     pop    bx
  531.     mov    ret,0
  532.     clc            ;good exit
  533.     ret
  534. wait    endp
  535. ;
  536. ;    hbye    closes the vcapi, releases dynamic memory and exits
  537. ;
  538. hbye    proc    near
  539.     mov    ax,1100h+onhook
  540.     lea    bx,parms        ;May have been clobbered by now
  541.     mov    dx,rcb            ;dx = rcb
  542.     mov    [bx].w1,dx        ;move rcb into paramater list
  543.     mov    dx,1            ;Line 1 (no equate here)
  544.     mov    [bx].w2,dx
  545.     mov    dx,bid            ;Base commands
  546.     int    14h
  547. ;don't care if this works or not
  548. chkerr    =    0            ;don't check errors
  549.  
  550.     stuf1    conndevs,rcb,bid,telephone+line1
  551. ;don't care here either
  552.     mov    ax,1100h+close
  553.     lea    bx,plist        ;Address of parameter list
  554.     mov    dx,bid            ;dx = base id (for base commands)
  555.     int    14h
  556. ;
  557. ;Don't bother checking return code
  558. ;
  559.     push    ds
  560.     pop    es            ;free data segment
  561.     mov    ah,49h
  562.     int    dos
  563.     mov    ax,4c00h
  564.     int    dos            ;say goodbye with 0 return code
  565. hbye    endp
  566. code    ends
  567.     end    main
  568.  
  569. Comment +
  570.  
  571.         ----- Cut here for ERR Module  -----
  572.  
  573.  
  574.     title    ERR 
  575.     page    55,131
  576. ;
  577. ;    This module contains lots of error print out routines.
  578. ;    It uses its own data segment and is reentrant. Error
  579. ;    messages are referred to by number so any program can be
  580. ;    written and error messages later changed to whatever language
  581. ;    is desired.
  582. ;
  583.  
  584. cr    equ    13
  585. lf    equ    10
  586. zzrom    segment     public 'dseg'
  587. ertab    dw    m0,m1,m2,m3,m4,m5,m6,m7,m8,m9
  588.     dw    m10,m11,m12,m13,m14,m15,m16,m17,m18,m19
  589.     dw    m20,m21,m22,m23,m24,m25,m26,m27,m28,m29
  590.     dw    m30,m31,m32,m33,m34,m35
  591. uertab    dw    u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15
  592. dw10    dw    10
  593. crlf    db    cr,lf,'$'
  594. m0    db    '$'
  595. m1    db    'Invalid Function Number$'
  596. m2    db    'File not Found$'
  597. m3    db    'Path not found$'
  598. m4    db    'Too many Open Files$'
  599. m5    db    'Access Denied$'
  600. m6    db    'Invalid Handle$'
  601. m7    db    'Memory Control blocks destroyed$'
  602. m8    db    'Insufficient Memory$'
  603. m9    db    'Invalid memory block address$'
  604. m10    db    'Invalid environment$'
  605. m11    db    'Invalid format$'
  606. m12    db    'Invalid access code$'
  607. m13    db    'Invalid data$'
  608. m14    db    'Reserved (ask Microsoft)$'
  609. m15    db    'Invalid drive specification$'
  610. m16    db    'Attempt to remove current directory$'
  611. m17    db    'Not same device$'
  612. m18    db    'No more files$'
  613. m19    db    'Diskette write protected$'
  614. m20    db    'Unknown Unit$'
  615. m21    db    'Drive not ready$'
  616. m22    db    'Unknown Command$'
  617. m23    db    'Data Error (CRC)$'
  618. m24    db    'Bad request structure length$'
  619. m25    db    'Seek error$'
  620. m26    db    'Unknown Media Type$'
  621. m27    db    'Sector not found$'
  622. m28    db    'Printer out of paper$'
  623. m29    db    'Write fault$'
  624. m30    db    'Read fault$'
  625. m31    db    'General failure$'
  626. m32    db    'Sharing violation$'
  627. m33    db    'Lock violation$'
  628. m34    db    'Invalid disk change$'
  629. m35    db    'FCB Unavailable$'
  630. maxmsg    equ    35
  631. unknown    db    'Unknown Error code $'
  632. u0    db    '$'
  633. u1    db    'Memory allocation: $'
  634. u2    db    'Voice communications application interface not installed$'
  635. u3    db    'Fatal Error calling VCAPI Command: $'
  636. u4    db    ' Return Code: $'
  637. u5    db    'Timed out waiting for VCAPI interrupt$'
  638. u6    db    'Could not detect dial tone$'
  639. u7    db    'Unable to detect modem carrier$'
  640. u8    db    'modem carrier detected$'
  641. u9    db    'ring$'
  642. u10    db    'busy$'
  643. u11    db    'modem start command failed$'
  644. u12    db    ' parity errors$'
  645. u13    db    ' frameing errors$'
  646. u14    db    ' overun errors$'
  647. u15    db    'no errors yet$'
  648. maxumsg    equ    15
  649. hextab    db    '0123456789ABCDEF'
  650. last    label    byte
  651. zzrom    ends
  652. CODE    SEGMENT PARA PUBLIC 'CODE'
  653.         ASSUME  CS:CODE,DS:zzrom
  654.     public    perr        ;Prints DOS error
  655.     public    uerr        ;User error
  656.     public    nout        ;Print decimal AX
  657.     public    whout        ;Print hex AX
  658.     public    hout        ;print hex AL
  659.     public    getlast        ;gets last value in memory
  660. ;
  661. ;    gets last paragraph boundary there are better ways and this
  662. ;    won't work in a high level language environment but....
  663. ;
  664. getlast    proc    near
  665.     lea    ax,last
  666.     add    ax,0fh
  667.     shr    ax,1
  668.     shr    ax,1
  669.     shr    ax,1
  670.     shr    ax,1
  671.     ret
  672. getlast    endp
  673. perr    proc    near
  674.     push    ds
  675.     push    ax
  676.     mov    ax,zzrom    ;Got to address our strings
  677.     mov    ds,ax
  678.     pop    ax
  679.     or    ax,ax        ;ax contains error code
  680.     jg    ok
  681.     jnz    unk
  682.     jmp    short perr_x    ;do nothing for zero
  683. unk:    push    ax
  684.     lea    dx,unknown    ;never seen this error code
  685.     mov    ah,9
  686.     int    21h
  687.     pop    ax
  688.     call    whout        ;print numeric code
  689.     jmp    short perr_x
  690. ok:    cmp    ax,maxmsg
  691.     jg    unk        ;unknown error
  692.     add    ax,ax        ;make word inder
  693.     mov    si,ax
  694.     mov    dx,ertab[si]
  695.     mov    ah,9
  696.     int    21h
  697. perr_x:    pop    ds
  698.     ret
  699. perr    endp
  700. ;
  701. ;    print an error string if error number is negative don't append CRLF
  702. ;
  703. uerr    proc    near
  704.     push    ds
  705.     push    ax
  706.     push    ax        ;save second one as crlf flag
  707.     mov    ax,zzrom    ;Got to address our strings
  708.     mov    ds,ax
  709.     pop    ax
  710.     or    ax,ax        ;ax contains error code
  711.     jg    ok1
  712.     neg    ax        ;Make negative positive
  713.     jg    ok1
  714.     jnz    unk1
  715.     jmp    short uerr_x    ;do nothing for zero
  716. unk1:    push    ax
  717.     lea    dx,unknown    ;never seen this error code
  718.     mov    ah,9
  719.     int    21h
  720.     pop    ax
  721.     call    nout        ;print numeric code
  722.     jmp    short uerr_x
  723. ok1:    cmp    ax,maxumsg
  724.     jg    unk1        ;unknown error
  725.     add    ax,ax        ;make word inder
  726.     mov    si,ax
  727.     mov    dx,uertab[si]
  728.     mov    ah,9
  729.     int    21h
  730. uerr_x:    pop    ax        ;If code was positive do crlf
  731.     or    ax,ax        ;If negative don't
  732.     jl    nocrlf
  733.     lea    dx,crlf        ;get new line
  734.     mov    ah,9
  735.     int    21h
  736. nocrlf:    pop    ds
  737.     ret
  738. uerr    endp
  739.  
  740. ; Print the number in AX on the screen in decimal
  741.  
  742. NOUT     PROC    NEAR
  743.     push    ds
  744.     push    ax
  745.     mov    ax,zzrom    ;Got to address our strings
  746.     mov    ds,ax
  747.     pop    ax
  748.     push    dx
  749.     mov    dx,0        ;High order word should be zero.
  750.     div    dw10        ;AX <-- Quo, DX <-- Rem.
  751.     cmp    ax,0        ;Are we done?    
  752.     jz    nout0        ;Yes.
  753.     call    nout        ;If not, then recurse.
  754. nout0:    add    dl,'0'        ;Make it printable.
  755.     push    ax
  756.     mov    ah,2        ;Single character to display
  757.     int    21H    
  758.     pop    ax
  759.     pop    dx
  760.     pop    ds
  761.     ret            ;We're done. [21c]
  762. NOUT    ENDP
  763. whout    proc    near        ;Print words worth of hex code
  764.     push    ax
  765.     call    hout        ;by calling hout twice
  766.     pop    ax
  767.     mov    al,ah
  768.     jmp    hout
  769. whout    endp
  770. hout    proc    near        ;Print byte in hex
  771.     push    ds
  772.     push    ax
  773.     mov    ax,zzrom    ;Got to address our strings
  774.     mov    ds,ax
  775.     pop    ax
  776.     push    dx        ;Save registers used
  777.     push    bx
  778.     push    cx
  779.     push    ax        ;Save input so we can get low nibble
  780.     mov    cx,4        ;Do hi nibble first
  781.     shr    al,cl
  782.     and    ax,0fH        ;Just four bits
  783.     lea    bx,hextab
  784.     xlat    hextab        ;Turn into printable
  785.     mov    dl,al        ;Print single character
  786.     mov    ah,2
  787.     int    21H
  788.     pop    ax
  789.     and    al,0fH        ;Now do low bits
  790.     xlat    hextab
  791.     mov    dl,al
  792.     mov    ah,2
  793.     int    21H
  794.     pop    cx        ;and restore registers
  795.     pop    bx
  796.     pop    dx
  797.     pop    ds
  798.     ret
  799. hout    endp
  800. code    ends
  801.     end
  802.  
  803. +