; JCATDIAL.ASM - A dial utility for the Novation J-Cat. Released ; to the public domain. Written by Len Moskowitz, Fair Lawn, NJ. ; January 1985. ; ; This program prompts for the number you want to dial allowing ; only numbers between 0 and 9. You can use phone numbers up to ; 11 digits long. If you want to use longer numbers, change the ; amount of storage allocated at the label "length". It's currently ; set at 12 (11 digits and a terminating null). If during the number ; entry or the dialing, you type control-X the program will reprompt ; for a new number. If you type control-C it will return to CP/M ; via a jump to location 0000. ; After it dials, it checks for the presence of the modem carrier ; signal, signalling that a modem picked up the phone and data ; can be transferred. The J-Cat signals "Carrier Detect" with the ; CAR signal (pin 8 on the RS-232 connector, the orange wire). If ; a carrier is detected, the program exits without hanging up. If a ; carrier is not detected within 15 seconds after the last digit is ; dialed, it hangs up the phone and asks if you want to redial. If ; you say no, it exits to CP/M. If you say yes, it redials continuously ; until either a carrier is detected or any key is pressed. ; This program uses the OHK signal (The blue wire in the RS-232 ; connecter) to command the J-Cat into an off-hook state, pulse dial ; it, and hang it up. ; See the file JCATDIAL.INF for tips on getting the J-CAT to dial ; with less headaches during the process. ; Assembles with ASM.COM, the assembler provided with CP/M. ; ;********** ; EQUATES * ;********** ; This section should be modified to match your system. ; offonhookport equ 08h ;I/O port used to command OHK signal cardetectport equ 05h ;I/O port used to read CAR signal carriermask equ 80h ;mask used to check carrier detect bit. if this ; bit is a zero, the carrier was detected. onhook equ 0feh ;mask used reset OHK to 0. All bits set to 1 ; except the bit that controls OHK offhook equ 01h ;mask used to set OHK to 1. All bits zero ; except the bit that controls OHK length equ 12 ;11 digits max per phone number plus a ; null portdefault equ 00h ;you might use a port that controls other ; things too. since we don't want to disturb ; them, store the default setting for the port, ; with OHK set to zero, here milliconstant equ 165 ;delay constant for millisecond delay loop. ; correct for 4 megaHertz Z80A. halve it ; for 2 megaHertz cpu or adjust per your ; cpu requirements. a good way to check how ; accurate it is, is to set the three second ; delay, after the phone is taken off hook, ; to 60 seconds and time it carefully, and then ; adjust this constant. dialtonewait equ 3 ;this is how long we wait after taking the ; phone off-hook for a dial tone carrierwait equ 15 ;this is how many seconds we wait for a ; carrier before we consider it a failed call. ; This section has important CP/M addresses. bdos equ 0005 ;the call to BDOS is at address 0005h cpm equ 0000 ;the jump to CP/M is at address 0000h ; This section has BDOS call codes. conin equ 01 ;bdos console input conout equ 02 ;bdos console output const equ 06 ;bdos direct console status and i/o input equ 0ffh ;bdos direct i/o input directive ; This section has ASCII codes. null equ 0 ; null controlc equ 'C' - 64 ; control C bell equ 'G' - 64 ; bell bs equ 'H' - 64 ; backspace lf equ 'J' - 64 ; line feed cr equ 'M' - 64 ; carriage return controlx equ 'X' -64 ; control X asp equ ' ' ; space del equ 7fh ; delete ; This section has logicals. true equ 0ffh ;true false equ 0 ;false ; ;************ ; MAIN LOOP * ;************ ; org 0100h ;starts at the normal cp/m tpa lxi h,header ;tell him how to get out and restart call print dial: lxi sp,stacktop mvi a,false ;set the repeatflag to no redial sta repeatflag lxi h,numberq ;prompt him for a telephone number call print dial0 mvi c, length - 1 ;store the max number of digits in C call getnumber ;get a telephone number ora a ;see if he deleted beyond the prompt jnz dial0b ;jump if he didn't lxi h,crlf ;if he did, print an empty line and restart call print jmp dial dial0b mvi a,portdefault ;get the default setting for the port we use ori offhook ; to control OHK and set OHK to 1 out offonhookport ;take the phone off hook lxi h,waitdialtone ;tell him we're waiting 3 seconds call print mvi d,dialtonewait ;wait "dialtonewait" seconds dial0c lxi b,1000 call delay call keycheck ;see if a key was pressed cnz exitcheck ;if yes, check which one dcr d jnz dial0c ;jump if we haven't waited long enough lxi h,dialing ;tell him we're starting to dial call print lxi h,number ;point to the number he just typed mov a,m ;load it into A and check if it's zero dial1 ora a ;set the flags. Z set to 1 means A is a zero. jz done ;jump if we finished dialing sui '0' ;otherwise, subtract out the ASCII offset jnz dial1a ;check if it's zero. jump if it's not mvi a,10 ;it was zero, so convert it to ten dial1a mov e,a ;keep the digit we're dialing in E dial2 mvi a,portdefault ;get the default setting for the port ani onhook ;set OHK to 0 for 60 milliseconds out offonhookport lxi b,60 call delay mvi a,portdefault ;get the default setting again ori offhook ;set OHK to 1 for 40 milliseconds out offonhookport lxi b,40 call delay dcr e ;decrement E. if E is zero go on to next digit jnz dial2 ;jump if it's not zero yet lxi b,900 ;it was zero, so wait for 700 to 900 call delay ; milliseconds before we dial the next digit push h ;save our place call keycheck ;see if a key was pressed cnz exitcheck ;if one was, check which one pop h ;restore our place inx h ;get the next digit mov a,m ;put it in A jmp dial1 ;jump back to the zero check done mvi d,carrierwait ;loop until we detect a carrier or for a ; maximum of "carrierwait" seconds done1 lxi b,1000 ;wait 1 second for a carrier call delay call carriercheck ;see if we connected with a modem jnz yescarrier ;jump if we connected call keycheck ;see if a key was pressed cnz exitcheck ;if yes, check which one dcr d jnz done1 ;jump if we haven't waited long enough lxi h,carnotdet ;tell him that a carrier was not detected call print call hangup ;hangup the phone lda repeatflag ;check if we're repeat-dialing ora a jz redialq ;jmp if we're not lxi h,redialing ;tell him we're redialing call print lxi b,3500 ;wait for 3.5 seconds before we redial call delay ; to be sure that we really hung up. jmp dial0b redialq lxi h,repeatq ;ask him if we should redial call print mvi c,conin call bdos cpi 'y' jz setflag ;redial if he said "y" or "Y" cpi 'Y' jz setflag ;jump ahead if he typed "y" or "Y" lxi h,crlf call print jmp dial ;any other key restarts the program setflag mvi a,true sta repeatflag lxi h,redialing call print lxi b,3500 call delay jmp dial0b bye: jmp cpm ;jump back to cp/m yescarrier:lxi h,carrierdet ;otherwise, tell him we've got a carrier call print jmp cpm ; and exit to cp/m header:db cr,lf,'***********************************' db cr,lf,'* Dial Utility for Novation J-Cat *' db cr,lf,'* Version 1.1 *' db cr,lf,'***********************************' db cr,lf,cr,lf,'Control-X restarts, Control-C exits.',cr,lf,0 dialing db cr,lf,'Dialing...',0 waitdialtone db cr,lf,'Waiting for a dial tone...',0 number: ds length numberq:db cr,lf,'Number? : ',0 beep db bell,0 carrierdet db cr,lf,'Carrier detected.',0 carnotdet db cr,lf,'Carrier not detected.',0 repeatflag db 0 redialing db cr,lf,cr,lf,'Redialing... ',0 repeatq db cr,lf,'Redial? (Y/N) : ',0 crlf db cr,lf,0 ; ;************ ; GETNUMBER * ;************ ; Getnumber gets the telephone number we will dial from the user. ; C holds the maximum number of characters to be accepted. getnumber: lxi h,number ;"number" is where we store the mvi b,0 ; telephone number. B is our ; pointer into number getnum0 call getone ;get one character cpi bs ;was it bs? cz delete ;call the delete handler if it was cpi del ;was it del? cz delete ;call the delete handler if it was cpi null ;did he delete to the prompt? rz ;return with A = 0 if he deleted ; or backspaced back to the prompt getnum1 cpi controlc ;was it control C? jz cpm ; exit if it was cpi controlx ;was it control X? jnz getnum2 ;jump if it wasn't ;he typed ^X. start the program over lxi h,crlf call print jmp dial getnum2 cpi cr ;was it a cr? jnz getnum3 ;jump if it wasn't mvi m,0 mvi a,0ffh ret getnum3 mov m,a ;put the digit in storage in "number" inr b ;check if he's hit the max number of digits inx h mov a,b cmp c ;C holds the max number of digits allowed jnz getnum0 ;if not, get another digit mvi m,0 ;he entered the maximum number allowed, so lxi h,crlf ; move a null into the last location at call print ; "number", print a cr and a lf, and return mvi a,0ffh ret ; ;********* ; DELETE * ;********* ; Delete the character at HL and get a new character from the console. ; Put a null in A if B goes negative (too 0ffh). This means he ; tried to delete beyond the current prompt. ; ; We get here if he typed a bs or delete. ; delete: dcx h dcr b mvi a,0ffh cmp b jz delete1 call getone cpi bs jz delete cpi del jz delete ret delete1 inx h inr b mvi a,null ret ; ;********* ; GETONE * ;********* ; Getone gets one character from the console. Only digits between ; 0 and 9, control X, control C, backspace and delete are allowed. ; Any other character is not echoed and not returned to the calling ; procedure. Both backspace and delete are echoed as bs,asp,bs. ; getone: push b push d push h get1 mvi c,const mvi e,input call bdos ora a jz get1 ;no character is ready, so loop ani 7fh ;mask off the MSB (ASCII is seven bits) cpi controlc ;check if it's a valid character jz getone1 cpi controlx jz getone1 cpi cr jz getone1 cpi ':' ;compare it against the character just above 9 jnc getone0a ;it's ASCII value is above 9 so jump back adi 0ah ;is it's value between 0 and 9? cpi ':' jc getone0 ;its value is less than 0 so jump back sui 0ah ;restore it jmp getone1 ;accept it and jump getone0 sui 0ah ;restore it getone0a cpi del jz getone0b cpi bs jnz get1 ;it's not one of the valid characters, so get ; another one getone0b mov e,a lxi h,termdel ;echo the terminal delete sequence call print jmp getone2 getone1 mov e,a push d mvi c,conout call bdos pop d getone2 mov a,e pop h pop d pop b ret termdel:db bs,asp,bs,0 ; ;*************** ; CARRIERCHECK * ;*************** ; ; Check if we have a carrier. Return with the zero flag set if not. ; carriercheck: in cardetectport ;check if a carrier was detected ani carriermask ;mask off the "carrier detect" bit ret ; ;*********** ; KEYCHECK * ;*********** ; See if a key was pressed. If yes, zero flag is not set. keycheck:push b push d push h mvi c,const ;see if a key was pressed mvi e,input call bdos pop h pop d pop b ora a ;set flags. if Z is set, no character is ready ret ; ;************ ; EXITCHECK * ;************ ; See if the key he pressed is control X or control C. If it is ; control C, jump back to CP/M. IF it's control X, jump back to the top ; of the program. exitcheck: cpi controlc ;see if the key he pressed was control C jnz exit1 ;jump if not call hangup ; otherwise hangup and jump back to CP/M jmp cpm exit1: cpi controlx ;was it control X? rnz ;return if it wasn't control C or control X call hangup ;if it was control X, hang it up lxi h,crlf ;print a blank line call print jmp dial ; and jump back to the top ; ;********* ; HANGUP * ;********* ; Hangup puts the phone on hook in the strange way the J-Cat requires ; to avoid going into self-test. hangup lxi h,hangingup ;tell him we're hanging up call print mvi a,portdefault ;get the default settings again ani onhook ;put the phone on hook (hang up) for 25 msec. out offonhookport lxi b,25 call delay mvi a,portdefault ;get the default setting again ori offhook ;take the phone off hook for 20 milliseconds out offonhookport lxi b,20 call delay mvi a,portdefault ;get the default setting again ani onhook ;put it on hook again for good this time out offonhookport ret hangingup db cr,lf,'Hanging up.',0 ; ;******** ; DELAY * ;******** ; Delay is a delay loop that last BC milliseconds. Doesn't touch ; DE and HL. delay: push d ;save DE and HL push h inr b ;Set B to 1 higher, since we decrement it ; later before we test it delay1 lxi d,milliconstant ;load DE with the delay constant delay2 dcx d ;inner loop until DE goes to zero mov a,e ora d jnz delay2 dcr c ;middle loop until C goes to zero jnz delay1 dcr b ;outer loop until B goes to zero too jnz delay1 pop h ;restore HL and DE pop d ret ; and return ; ;******** ; PRINT * ;******** ; Print prints whatever HL is pointing to until a null (00h) is found. print: mov a,m ;get the first character inx h ;increment the message pointer ora a ;check if the character is a null (0) rz ;return if it is push b push d push h mov e,a mvi c,conout ;if not, print it out call bdos pop h pop d pop b jmp print ;loop ; stack ds 32 stacktop equ $