rem Modem communication program rem Based around BASIC-52 software for RPC-320, 330 rem General operation. rem This program is designed as a reciever. Dialing out from rem a modem is simply a matter of sending the ATDT rem command and responding appropriately to whatever is dialing. rem Recieving is a matter of going through a series of steps, or rem cycles. The first cycle is to detect Ringing message. Then rem Connect . After that, a password is entered. rem Line 2300 sets the password. After 3 fails, it hangs up. rem commands are then processed. Processing is done as part of rem the main loop rather than in the interrupt. rem Commands are processed at line 2400. At this point the card rem could be treated as a network, processing commands. A more rem sophisticated command handler is in the RS-485 demo program. rem If you want to do more, refer to this application note. rem Additonal CYCLEs can be added for outgoing initiated calls. rem The new cycle would look for BUSY, NO DIALTONE, and NO rem ANSWER. Rem ONTICK acts as a communication timer. Should there be a rem period of inactivity while the modem is on line, it issues a rem hang up command to the modem. Timeout for this example is rem 10 seconds rem The program is designed so that on a communication problem rem it will hang up and reset the modem. The OK string from the rem modem is treated as a "ready to recieve" indication from the rem modem. If no OK is recieved, it will go through a hang-up- rem reset process every 10 seconds until it recieves one. rem The NOKFL variable is set to 1 if no OK message is recieved. rem This is read by the main loop since what to do with an inoperative rem modem is application dependent. rem If a NO CARRIER message is recieved from the modem after connecting, rem the modem will be reset. If you expect to ever send this string over, rem modify the program at lines 1500+ else the modem will be reset. rem Some modem messages such as NO DIALTONE, BUSY, and NO ANSWER are not rem processed since these are outgoing dependent. However, they can be rem processed by adding CYCLEs. rem To run this program "as is", you should have 2 PC's available. rem This program has DEBUGging print statements throughout. rem They may be removed as required. rem One is connected to the card, the other to a phone line through rem a modem. Configure the modem per the RPBASIC software manual. rem Connect a modem to an RPC-320, 330, rem or other software compatible card (one that recognizes ON COM$) rem to COM 1. Don't forget to put a null modem adapter between the rem modem and card. Connect a PC or other such device to COM 0. rem Download this program. rem Connect the modem to a phone line. Run your your other PC's modem rem program. Run this program on the RPC card. You will see initialization rem messages and status displayed. You should see RD and SD lights blinking rem on the external modem. What you are looking for is rem cycle = 0 atim = 0 rem on the bottom of the screen. Dial up the RPC card from the other PC. rem You should see a progression of messages such as RING, CONNECT rem and the CYCLE count will increase. Pay attention to your dial up rem PC. You should see a short sign on message and a prompt for a rem password. Enter 'password'. Use lower case. The password is rem set at line 2300. rem You are then prompted for a command. Commands for this demo are rem prefixed with '>03'. The command is a number following the '3'. rem To return the current analog reading on channel 0, type '>030' rem You will probably get 0 if there is no voltage on channel 0. rem To return the status at line 0, type '>031'. You will probably rem get a 1. A '>032' will disconnect from the line. rem If you do nothing, the modem will reset by the time atim = 9 rem as printed on the screen. When that happens, the modem disconnects rem and resets. rem Other things to consider. rem If you are going to be sending out data for long periods of time, rem be sure to change the variable ctim or reset atim periodically. rem This program is designed to hang up if there is inactivity for a period rem of time. Default is 10 seconds. rem CYCLE 4 is the hang up/reset modem cycle. When something sets this cycle rem in motion, nothing in this program can get it out. CYCLE 4 starts by rem assuming that nothing is being transmitted out. It does wait a period of rem time to ensure the time dependent escape sequence gets recognized. rem A potential problem is in downloading information. Running at 1200 baud, rem characters are sent out at about 120 characters/second. If you are sending rem out lots of data, chances are the serial buffer in the card will get full. rem At this baud rate, it will take about 2 seconds to empty. If you go into rem CYCLE 4 right after a data dump, the escape sequence will not be recognized rem immediately. Since CYCLE 4 keeps trying to reset the modem, it will rem eventually reset it. In the mean time, you may get "strange" data on rem the recieving end. rem This program was moderately tested. It recovers from no connects, rem disconnects, and modem power off/on conditions fairly well. Keep rem in mind each modem tends to operate a little differently and some rem adjustments might have to be made. The biggest problem we had was rem in "dead" times. Manufactures claim they need 1 second of dead time rem before sending the escape sequence, but we found one needed more. Also rem you may need to pause a little longer after getting the CONNECT message rem before sending out a sign on message. rem We used USR, Practical Peripherals, and "no name" modems. rem variable definitions rem cycle = communication cycle counter rem mcycl = main loop multi tasking cycle rem flag(n) = main task dispatcher flag rem atim = actual time since last communication (in seconds) rem ctim = commanded time for timout rem htim = hang up/reset timer rem $(0) = input string from com 1 buffer rem $(1) = working search string in com 1 interrupt routine rem $(2) = NO CARRIER string constant rem cia = Communication Interrupt variable A - working variable rem passw = pass word tries rem okflg = flag to indicate OK was recieved 1 = got it rem nokfl = flag to indicate OK was NOT recieved 1 = not got it rem The main loop looks at nokfl and resets it. Reason being is rem modem may be bad, not powered, or not connected. rem Application requirements dictate what to do in case of a bad rem modem. This flag is reset by the main loop. This program rem is set up to continiously try to reset the modem. rem nocfg = no carrier flag 1 = "NO CARRIER" string found rem Varible root tim was used because time is a key word. rem initialize strings, arrays, interrupts 10 config baud 1,5,0:rem 1200 baud for this example 20 string 1000,50 :rem 20 strings, 50 bytes 30 dim flag(15) :rem flags for main task dispatcher 40 okflg = 0 :rem OK recieved flag 50 ontick 1,1000 :rem communication watchdog and system timer 60 on com$ 1,49,13,2000 :rem interrupt on 49 chars or 70 ctim = 10 :rem communication timeout if on line. 80 $(2) = "NO CARRIER" :rem string constant 90 nocfg = 0 :rem no carrier flag 100 htim = 0 110 clear com(1) :rem get rid of any previous stuff rem Send reset to modem rem NOTE: If you are allowing for downloads to the card, rem skip around line 150. This can be done by rem checking for a flag set in expanded memory (segment 1) rem If it is set, then don't do card reset. 150 cycle = 4 :rem do modem reset rem other initialization as needed by the program rem Main program loop rem This is a multi-tasker dispatcher. It performs various tasks rem as dictated by other interrupts or programs rem the array FLAG is used to indicate a process should be performed rem For this example rem flag(0) = send back analog input channel 0 value rem flag(1) = send back digital 0 value rem flag(2) = hang up rem flag(3) through flag(14) are used for other process functions rem for this example, only the first 11 flags are processed. 200 for mcycl = 0 to 14 210 if flag(mcycl) = 0 then 300 :rem when a 1, then do a process 220 if mcycl > 5 then 250 rem mcycl = 0 1 2 3 4 5 230 on mcycl gosub 10000,11000,12000,13000,14000,15000 240 goto 300 rem mcycl = 6 7 8 9 10 250 on mcycl-6 gosub 16000,17000,18000,19000,20000 260 goto 300 rem do mcycl 11-14 or more here 300 next rem DEBUG 400 print "cycle =",cycle," atim =",atim,cr, rem if there are other tasks that have to be done, then do them here 500 goto 200 rem ONTICK processing rem Communication timeouts checked rem if on line, some communication must be recieved in 10 seconds rem Exception processing is: Hang up (waits 3 seconds) rem Long data send (ctim set longer) rem If you need to do other things, then add them as needed. rem Gosub to routine based on current cycle rem Cycles are: rem 0 = waiting for RING 1400 rem 1 = looking for CONNECT 1500 rem 2 = looking for password. If ok send log on. If not, tell user 1500 rem 3 = looking for command. If ok, set MCYCLE. If not, tell user 1500 rem 4 = Send esc, look for OK, send hang up, look for OK, send reset rem look for OK1600 rem 5 = Send out sign on message after a few seconds delay rem cycle = 0 1 2 3 4 5 6 7 1000 on cycle gosub 1400,1500,1500,1500,1600,1900 rem other ONTICK stuff 1390 reti rem cycle 0 waiting for ringing rem This is idle. No checking is done 1400 return rem Cycle 1, 2, or 3 rem Looking for CONNECT, password, or command. rem Look for NO CARRIER flag. If set, then reset modem rem Check 10 second counter atim and compare with ctim 1500 atim = atim+1 :rem the '1' is changed based on current ON TICK time 1510 if nocfg = 1 then 1550 : rem if no carrier, reset all 1520 if atim < ctim then return rem no communication recieved Hang up and reset modem rem DEBUG 1540 print : print "no CONNECT, password, or command in time" 1550 cycle = 4 1560 htim = 0 1570 nocfg = 0 1590 return rem cycle 4 rem Wait 2 seconds, send esc, look for OK, send hang up rem look for OK rem ATIM value is used to determine what part of cycle rem 2 seconds are allowed for each step rem first wait htim=0 rem send esc htim = 2 rem look for OK, send hangup htim = 5 rem look for OK, send reset htim = 8 rem look for OK. got into cycle 0 htim = 11 1600 htim = htim + 1 1610 if htim = 2 then 1650 1620 if htim = 5 then 1700 1630 if htim = 8 then 1750 1635 if htim = 11 then 1850 1640 if htim > 12 then htim = 0 : return :rem if really large, then reset 1645 return : rem if none of the above rem send out escape sequence. Look for OK 1650 uo 1 1660 print "+++", 1670 uo 0 1680 okflg = 0 : rem reset flag rem DEBUG 1685 print : print "Sent +++" 1690 return rem look for OK rem If have it, send hang up rem If not, set flag (nokfl) and continue as modem could have rem been hung up on and lost carrier rem Send out hang up command any way 1700 uo 1 1710 print "ATH0" 1720 uo 0 1730 nokfl = not(okflg).and.1 : okflg = 0 rem DEBUG 1735 print : print "Sent ATHO." 1740 return rem Look for OK (must have it). If not there, reset htim=0 rem nokfl set to alert system, and redo cycle rem Send out reset string to modem. This is a simple one. 1750 if okflg = 0 then htim = 0:nokfl = 1: return 1760 uo 1 1770 print "ATZ" 1780 uo 0 1790 okflg = 0 rem DEBUG 1795 print : print "Sent ATZ" 1800 return rem Look for OK (must have this one also). If not there, reset rem htim =0 and redo cycle rem clear COM(1) to flush out any other erroneous data 1850 clear com(1) 1860 if okflg = 1 then cycle = 0 : return 1870 htim = 0 1890 return rem Cycle 5 tick processing rem Send out sign on message after 3 seconds of waiting 1900 htim = htim + 1 1910 if htim < 3 then return rem print sign on message and request password 1920 uo 1 1930 print "Remote Processing modem demo" 1940 print "Enter password..." 1950 uo 0 rem DEBUG 1955 print : print "Printed RPC sign on message" 1960 clear com(1) 1970 cycle = 2 1980 atim = 0 1990 return rem ON COM$ processing rem get current input 2000 $(0) = com$(1) 2010 atim = 0 : rem if anything came in, reset actual com time rem ignore any . Check for lf 2020 if str(0,$(0)) = 0 then return rem if first character is lf, then filter it out 2030 if asc($(0),1) <> 10 then 2060 2040 cia = str(7,$(0),$(0),2,str(0,$(0))-1) :rem get rid of 2050 goto 2020 :rem check for any length of string rem DEBUG 2060 print : print "Recieved string:",$(0)," Cycle=",cycle rem Check for NO CARRIER string. If there, then set flag and rem continue. Other parts of program may use flag 2070 cia = str(8,$(0),$(2)) 2075 if cia > 0 then nocfg = 1 rem process according to current cycle rem CYCLE is defined as follows: rem 0 = waiting for RING rem 1 = looking for CONNECT rem 2 = looking for password. If ok send log on. If not, tell user rem 3 = looking for command. If ok, set MCYCLE. If not, tell user rem 4 = Send esc, look for OK, send hang up, look for OK, send reset, rem look for OK This routine just looks for OK rem 5 = send out sign on message after 2 second delay for CONNECT rem cycle = 0 1 2 3 4 5 6 2080 on cycle gosub 2100,2200,2300,2400,2500,2600 2090 return rem check if RING message. If so, then set cycle for 1 2100 $(1) = "RING" 2120 cia = str(8,$(0),$(1)) 2130 if cia = 0 then return :rem if something else, just ignore it 2140 cycle = 1 rem DEBUG 2150 print "Got RING. To cycle 1" 2190 return rem cycle = 1 rem check for CONNECT message rem if not, hang up by setting cycle 4 rem if CONNECT, then wait before sending sign on 2200 $(1) = "CONNECT" 2210 htim = 0 2220 cia = str(8,$(0),$(1)) 2230 if cia > 0 then 2270 2240 cycle =4 rem DEBUG 2255 print "No CONNECT recieved. Input string=",$(0) 2260 return rem hold off any xmission for 3 seconds before sending sign on 2270 cycle =5 2280 passw = 0 2290 return rem cycle 2 rem Looking for password. rem If tried 3 times, hang up 2300 $(1) = "password" 2310 cia = str(8,$(0),$(1)) 2320 if cia > 0 then 2350 2330 passw = passw + 1 2335 uo 1 : print "Invalid password. Re-enter" : uo 0 2340 if passw = 3 then cycle = 4 : htim = 0 : passw = 0 2345 return rem check on length to make sure its all correct 2350 if str(0,$(0)) <> str(0,$(1)) then 2330 rem successful log in. Tell user to put in valid command 2360 cycle = 3 2370 uo 1 2380 print "Password accepted. Enter command" 2390 uo 0 2395 return rem Cycle 3 rem Process a command. If valid, set flag(n) rem To make sure no erroneous data looks like a command, all commands are rem prefixed with ">03". Idea is the likely hood of 4 random characters rem making a valid command is unlikely compared to just 1 2400 $(1) = ">03" 2410 if str(8,$(0),$(1)) <> 0 then 2450 2420 uo 1 : print "Invalid command. Re-enter" 2430 uo 0 2440 return rem command is number in 4th position rem Line 2460 checks for valid command limit 2450 cia = asc($(0),4)-48 2460 if (cia < 0) .or.(cia > 2) then goto 2420 2470 flag(cia) = 1 : rem indicate do this 2490 return rem cycle 4 rem Look for OK rem If have OK, then reset cycle to 0 rem If message is not OK, simply leave 2500 $(1) = "OK" 2510 if str(8,$(0),$(1)) <> 1 then return rem got OK rem Signal system and let tick timer do next 2520 okflg = 1 2590 return rem cycle 5 rem send out sign on message after 1 second delay rem Clear out COM if got here 2600 clear com(1) 2610 return rem mcycl 0 processing from main loop rem send back analog channel 0 to modem 10000 uo 1 10010 print ain(0) 10020 uo 0 10030 flag(0) = 0 10090 return rem mcycl 1 processing rem Send back digital status from line 0 11000 uo 1 11010 print line(0) 11020 uo 0 11030 flag(1) = 0 11090 return rem mcycl 2 processing rem hang up 12000 htim = 0 12010 cycle = 4 12020 flag(2) = 0 12030 uo1 12040 print:print "Hanging up" 12050 uo 0 12090 return