home *** CD-ROM | disk | FTP | other *** search
- /* rc85prg: program an RC-85 compatible controller
- via the phone line, using a Hayes-compatible modem.
-
- USAGE: rc85prg [options] inputfile
- -or- rc85prg [options] < inputfile
- -or- (for example) grep pattern inputfile | rc85prg [options]
-
- Input file format: Usage
- S nn call number Program number into autodial slot nn
- CL Config Lock (after a CU)
- CU Config unlock (to permit msg programming)
- CS string... Send config string to RC85
- CO string... Send control-op prefix followed by config string
- MP Msg program (same as CS *0)
- MR Msg readback (same as CS *2)
- MA Msg abort (same as CS *4)
- # comment text May appear anywhere on a line
-
- Written by James Dugal, N5KNX, Aug 1989.
- Ver 1.1 9/89: Improved abort handling. Added copyright greeting.
- Ver 1.2 10/89: Added inputfile as an argument, redid option parsing.
-
- Compile in Turbo C 1.5 + by: tcc -a -G -O rc85prg.c
- Requires AA4RE's MBBIOS com drivers be loaded before invocation.
-
- Copyright 1989 by James P. Dugal.
- */
-
- #define VERSION "1.2"
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <bios.h>
- #include <string.h>
-
-
- /* Int 14H (serial i/o) defines */
-
- int baudtab[8] = { 110, 150, 300, 600, 1200, 2400, 4800, 9600 };
- char partab[3][2] = { 'N', 0, 'E', 0x18, 'O', 0x8 };
-
- #define SENDST 0
- #define SENDCH 1
- #define GOODWRITE 0x8000
- #define READCH 2
- #define GOODREAD 0x9E00
- #define READST 3
- #define STDAV 0x0100 /* data available */
- #define MBENQ 4
- #define MBDRTS 5
- #define MBARTS 6
- #define MBSBRK 7
- #define MBNDRD 8
- #define MBOPTS 9
- #define SHAKEBF 0x0 /* No xmit buffering, no hardware handshake, low-speed opt */
-
- #define MBWBUF 10
- #define MBRBUF 11 /* ES:DI->BUF, CX={BUFSIZ,NREAD}, AX=stats */
-
-
- #define COMMENT '#' /* in input file */
-
-
- /* MODEM-related commands */
- #define DEFPORT "COM1:1200,7E1"
- #define USRHEAD "ATDT"
- #define USRTAIL ";"
- #define HANGUP "ATH0"
- #define OK "OK"
- #define USRMAXSZ 42 /* 40 + AT (spaces and CR don't count) */
-
- /* RC85 controller-related commands */
- #define DIALRC85 "5551234" /* RC85 phone number */
- #define RCUNLOCK "1234567890" /* owner's unlock seq. */
- #define RCLOCK "#" /* owner's lock seq. */
-
- #define CTRLOP "123" /* control operator prefix */
- #define RCHANGUP "44" /* RC85 on-hook command */
- #define RCAU "47" /* autodial prog unlock */
- #define RCAL "48" /* autodial prog lock */
-
- #define RC1SLOT "*520" /* then digit */
- #define RC2DFLT "456" /* then *nnxxxyyyy or nn */
- #define RC3DFLT "457" /* then *nnxxxyyyy or nn */
-
- char *me;
- char baudetc;
- char *dialup_num = DIALRC85;
- char *owner_code = RCUNLOCK;
- char *ctrlop_code = CTRLOP;
- char *rc2slot = RC2DFLT;
- char *rc3slot = RC3DFLT;
-
- int comport;
- int unlock = 1; /* 1 => we must unlock user autodialer */
- int aunlocked = 0; /* 1 => we have unlocked the user autodialer */
- int cunlocked = 0; /* 1 => we have unlocked for config commands */
- int verbose = 0;
- int waitsec = 25;
- int pausesec = 4;
- int test = 0;
-
- char progseq[100]; /* room for building programming sequences */
-
- /* ANSI func defs */
- int main(int, char**);
- void programslot(int, char *, char *);
- void dialup(void);
- void hangup(void);
- void enter_config(void);
- void exit_config(void);
- void send(char *);
- int writecom(char *);
- int waitfor(char *, int, char *, int);
- void parse_args(int, char**);
- int parse_comport(char *);
- int hndlbrk(void);
- int hat_break(void);
-
-
- main(argc,argv)
- int argc;
- char **argv;
- {
- int lineno,slot,i;
- char buffer[256],call[10],number[30],*cp;
-
- cprintf("Version %s. Copyright 1989 by James P. Dugal. All rights reserved.\r\n", VERSION);
- parse_args(argc, argv);
-
- if ((unsigned)bioscom(MBENQ, 0, comport) != 0xAA55) {
- fprintf(stderr,"%s: MBBIOS not enabled for COM%d.\n",
- me, comport+1);
- exit(2);
- }
-
- (void)bioscom(SENDST, baudetc, comport); /* set baud,parity,etc */
- (void)bioscom(MBOPTS, SHAKEBF, comport); /* set handshaking etc */
-
- /* Just to ge safe we flush all input */
- while (bioscom(READST, 0, comport) & STDAV)
- (void)bioscom(READCH, 0, comport);
-
-
- dialup();
- ctrlbrk(hndlbrk); /* we now take over if ^C typed */
-
- lineno = 0;
- while (gets(buffer) != NULL) {
- lineno++;
- if ((cp=strchr(buffer,COMMENT)) != NULL) *cp=0; /* ignore trailing comments */
- cp = strupr(buffer); /* map to uppercase */
-
- switch (*cp) {
-
- case 0: /* full-line comment, ignore it */
- break;
-
- case 'S': /* Slot: ss call phonenumber */
- i = sscanf(++cp, "%d\t%s\t%s", &slot, call, number);
- if (i != 3) goto badfmt;
- else programslot(slot,call,number);
- break;
-
- case 'C': /* Config command */
- if (*++cp == 'L') exit_config();
- else if (*cp == 'U') enter_config();
- else if (*cp == 'S' || *cp == 'O') { /* send all after CS/CO */
- if (*cp == 'S') sprintf(progseq, "%s%s#%s", USRHEAD, ++cp, USRTAIL);
- else sprintf(progseq, "%s%s%s#%s", USRHEAD, ctrlop_code, ++cp, USRTAIL);
- send(progseq);
- /* Auto readback takes a while, so vary sleep time */
- i = pausesec + strlen(progseq)/3;
- if (i > 50) i = 50; /* but not too long */
- sleep(i);
- }
- else goto badfmt;
- break;
-
- case 'M': /* Voice message command */
- if (*++cp == 'P') *cp = '0'; /* program */
- else if (*cp == 'R') *cp = '2'; /* readback */
- else if (*cp == 'A') *cp = '4'; /* abort */
- else goto badfmt;
-
- sprintf(progseq, "%s*%c#%s", USRHEAD, *cp, USRTAIL);
- send(progseq);
- sleep(pausesec+5);
- if (*cp != '4') sleep(5); /* longer unless abort */
- break;
-
- default: /* Unknown cmd */
- badfmt:
- fprintf(stderr,"%s: line %d: unknown or malformed command %s (ignored)\n",
- me, lineno, cp);
- break;
- } /* end switch */
- } /* end while */
-
-
- hangup();
-
-
- return(0);
- }
-
- void programslot(slot,call,number)
- int slot;
- char *call,*number;
- {
- char progprefix[10];
- char secure[2]; /* * secure code, else null */
-
- strcpy(secure, "*"); /* default is to NOT speak the programmed number */
- if (slot < 0 ) {
- secure[0]=0;
- slot = -slot;
- }
-
- else if (slot > 199) {
- fprintf(stderr,"%s: illegal slot number %d for %s (ignored)\n",
- me, slot, call);
- return;
- }
-
- if (slot < 10) { /* emergency slot */
- if (!cunlocked) enter_config();
-
- sprintf(progseq, "%s%s%d%s#%s", USRHEAD, RC1SLOT, slot, number, USRTAIL);
- send(progseq);
- sleep(pausesec+5);
- }
- else {
- if (slot < 100) /* 2-digit slot */
- strcpy(progprefix,rc2slot);
- else /* 3-digit slot */
- strcpy(progprefix,rc3slot);
-
- /* First unlock as needed */
- if (cunlocked) exit_config();
- if (unlock && !aunlocked) {
- sprintf(progseq, "%s%s%s#%s", USRHEAD, ctrlop_code, RCAU, USRTAIL);
- send(progseq);
- sleep(pausesec); /* await AU */
- aunlocked++;
- }
-
- sprintf(progseq, "%s%s%d#%s",
- USRHEAD, progprefix, slot, USRTAIL);
- send(progseq);
- sleep (pausesec); /* await finish of 'autodial clear' */
-
- sprintf(progseq, "%s%s%s%d%s#%s",
- USRHEAD, progprefix, secure, slot, number, USRTAIL);
- send(progseq);
- sleep (pausesec); /* await finish of 'autodial program' */
- }
-
- printf("%s: did %d\t%s\t%s\n", me, slot, call, number);
- }
-
- void dialup()
- {
- int errcode;
- char dialstr[64];
-
- sprintf(dialstr, "%s%s%s", USRHEAD, dialup_num, USRTAIL);
- send(dialstr);
- if (!test) sleep (waitsec); /* await finish of greeting msg */
- }
-
- void hangup()
- {
- if (cunlocked) exit_config(); /* exit owner config mode */
-
- if (unlock && aunlocked) { /* relock user autodialer? */
- sprintf(progseq, "%s%s%s#%s", USRHEAD, ctrlop_code, RCAL, USRTAIL);
- send(progseq);
- sleep(pausesec); /* await AL */
- aunlocked = 0;
- }
-
- sprintf(progseq, "%s%s%s#%s", USRHEAD, ctrlop_code, RCHANGUP, USRTAIL);
- send(progseq);
- sleep(pausesec); /* await 'call complete' */
-
- send(HANGUP); /* tell modem to go onhook */
- }
-
-
- void enter_config (void) /* enter owner config mode */
- {
- sprintf(progseq, "%s%s#%s", USRHEAD, owner_code, USRTAIL);
- send(progseq);
- sleep(pausesec); /* await UL */
- cunlocked = 1;
- }
-
-
- void exit_config(void) /* exit owner config mode */
- {
- sprintf(progseq, "%s%s#%s", USRHEAD, RCLOCK, USRTAIL);
- send(progseq);
- sleep(pausesec); /* await LOCK */
- cunlocked = 0;
- }
-
-
- void send(s_str) /* Send s_str to the comport, then read the OK */
- char *s_str;
- {
- int errcode;
- char logstr[128];
-
- if (writecom(s_str)) {
- fprintf(stderr,"%s: Unable to write %s to COM%d (aborting)\n",
- me, s_str, comport+1);
- exit (1);
- }
-
- errcode = waitfor(OK,pausesec+strlen(s_str)/2,logstr,sizeof(logstr));
- if (errcode) {
- fprintf(stderr,"%s: Expected %s, got %s (aborting)\n",
- me, OK, logstr);
- exit(1);
- }
- }
-
-
- int writecom(w_str) /* Write w_str to the comport, return 0 if OK */
- char *w_str;
- {
- int retcode;
- char *sp;
- #define CR 0x0D
- #define SP 0x20
-
- if (verbose) printf("Writing %s\n", w_str);
- for (retcode=0, sp=w_str; *sp; sp++)
- if (*sp != SP && *sp != '\t') retcode++;
- if (retcode > USRMAXSZ) fprintf(stderr,"%s: Warning: %s may exceed modem buffer capacity.\n",
- me, w_str);
-
- if (test) return(0);
-
- while (*w_str) {
- retcode = bioscom(SENDCH, *w_str++, comport);
- if (retcode & GOODWRITE) return (-1);
- }
- if (*--w_str != CR) {
- retcode = bioscom(SENDCH, CR, comport);
- if (retcode & GOODWRITE) return (-1);
- }
- return (0);
- }
-
-
- int waitfor(w_str, w_time, logstr, loglen)
- char *w_str; /* search string */
- int w_time; /* time limit (seconds) */
- char *logstr; /* log string */
- int loglen; /* sizeof logstr */
-
- /* wait a max of "w_time" seconds for "w_str" to appear on comport.
- append all characters read to "logstr".
- Return 0 if w_str read successfully, -1 if timeout, else errorcode.
- */
-
- {
- #include <time.h>
- int strindx, strln, retval;
- char ch;
- long done;
-
- if (test) return(0);
-
- done = w_time + time((long *) 0);
- logstr[0] = '\0';
- strindx = 0;
- strln = strlen(w_str);
- while (done > time((long *) 0)) {
- if (bioscom(READST, 0, comport) & STDAV) {
- retval = bioscom(READCH, 0, comport);
- if (retval & GOODREAD) /* error */
- return(retval);
- ch = retval & 0x7f;
- if (strlen(logstr) < loglen)
- strncat(logstr, &ch, 1);
- if (ch == w_str[strindx]) {
- strindx++;
- if (strindx >= strln) return(0); /* all done */
- }
- else strindx=0; /* start over (ie, ignore leading chs */
- }
- }
-
- return(-1); /* timeout */
- }
-
- void parse_args(argc, argv) /* scan command-line */
- int argc;
- char **argv;
- {
- char *cp;
- int i;
-
- /* Get our entry name for use in error msgs */
- me = strrchr(*argv,'/');
- if (me == NULL) me = strrchr(*argv,'\\');
- if (me == NULL) me=*argv;
- else me++;
- if ((cp=strchr(me,'.')) != NULL) *cp=0; /* drop trailing .EXE */
-
- argv++;
-
- if (parse_comport(DEFPORT)) { /* init baudetc and comport */
- fprintf(stderr,"%s: Illegal default port spec: %s\n",
- me, DEFPORT);
- exit(1);
- }
-
- while (--argc) {
- if (**argv == '-' )
- switch (*(++*argv)) {
- case 'm': /* -m modem_port_spec */
- ++argv; --argc;
- if (!argc || parse_comport(*argv)) goto usage;
- ++argv;
- break;
-
- case 'w': /* -w Nsecs */
- ++argv; --argc;
- if (!argc) goto usage;
- waitsec = atoi(*argv);
- ++argv;
- break;
-
- case 'p': /* -p Nsecs */
- ++argv; --argc;
- if (!argc) goto usage;
- pausesec = atoi(*argv);
- ++argv;
- break;
-
- case 'd': /* -d phonenum */
- ++argv; --argc;
- if (!argc) goto usage;
- dialup_num = *argv;
- ++argv;
- break;
-
- case 'o': /* -o owner_code */
- ++argv; --argc;
- if (!argc) goto usage;
- owner_code = *argv;
- ++argv;
- if (strlen(owner_code) != 10)
- fprintf(stderr,"%s: Warning: 10 digits expected, got %s\n",
- me, owner_code);
- break;
-
- case 'c': /* -c ctrl_op_code */
- ++argv; --argc;
- if (!argc) goto usage;
- ctrlop_code = *argv;
- ++argv;
- i=strlen(ctrlop_code);
- if (i<1 || i>7) fprintf(stderr, "%s: Warning: ctrl op code length is illegal: %s\n",
- me, ctrlop_code);
- break;
-
- case '2': /* -2 2digit_slot_code */
- ++argv; --argc;
- if (!argc) goto usage;
- rc2slot = *argv;
- ++argv;
- break;
-
- case '3': /* -3 3digit_slot_code */
- ++argv; --argc;
- if (!argc) goto usage;
- rc3slot = *argv;
- ++argv;
- break;
-
- case 'v':
- verbose++;
- argv++;
- break;
-
- case 'u':
- unlock = 0; /* already unlocked */
- argv++;
- break;
-
- case 't':
- test++; /* enable test mode */
- argv++;
- break;
-
- default:
- usage: fprintf(stderr,"USAGE: %s [options] infile\n", me);
- fprintf(stderr,"where infile contains lines of the form:\n");
- fprintf(stderr,"S slotnum call phonenumber\nor commands CU,CL,CS,CO,MP,MA,MR\n\n");
- fprintf(stderr,"options are:\t-v for verbose mode\n");
- fprintf(stderr,"\t\t-t for test mode: simulate operations\n");
- fprintf(stderr,"\t\t-u if autodialer is kept unlocked\n");
- fprintf(stderr,"\t\t-w N to wait N secs after dialing the RC85\n");
- fprintf(stderr,"\t\t-p N to pause N secs after each command\n");
- fprintf(stderr,"\t\t-m COMn:baud,8N1 to select a modem port and parameters\n");
- fprintf(stderr,"\t\t-d phonenumber to override the default phone number\n");
- fprintf(stderr,"\t\t-o owner_code to override the default owner unlock code\n");
- fprintf(stderr,"\t\t-c ctrlop_code to override the default control op code\n");
- fprintf(stderr,"\t\t-2 code to override the default 2-digit slot programming code\n");
- fprintf(stderr,"\t\t-3 code to override the default 3-digit slot programming code\n");
- fprintf(stderr,"defaults are -w %d -p %d -m %s -d %s -o %s -c %s -2 %s -3 %s\n",
- waitsec, pausesec, DEFPORT, dialup_num, owner_code,
- ctrlop_code, rc2slot, rc3slot);
- exit (1);
- } /* end of if () switch */
- else { /* not an option, so assume is an input file */
- if (freopen(*argv, "r", stdin) == NULL) {
- fprintf(stderr,"%s: %s: %s\n", me, *argv, strerror(errno));
- exit(2);
- }
- }
- } /* end while (--argc) */
- }
-
-
- int parse_comport(ap) /* ap -> "COM1:9600,8N1" */
- char *ap;
- /* Sets global variables comport, baudetc */
-
- {
- char *p, *s;
- int i,j;
-
- (void)strupr(ap);
- s = strchr(ap,':');
- if (s == NULL) {
- fprintf(stderr,"%s: Unknown port %s\n", me, ap);
- return (1);
- }
- *s++ = 0; /* terminate COMx, hop to baud */
-
- if (strncmp(ap, "COM", 3)==0)
- comport=atoi(ap+3) - 1; /* COMn */
- else {
- fprintf(stderr,"%s: Unknown port %s\n",me, ap);
- return (1);
- }
-
- p = strchr(s,','); /* Where is comma separating baud from par? */
- if (p == NULL) return (1);
- *p++ = 0; /* replace comma by EOS, point p to 8N1 string */
- j = atoi(s); /* baud */
-
- for (i=0; i < (sizeof(baudtab)/sizeof(int)); i++)
- if (j == baudtab[i]) {
- baudetc = (i << 5);
- break;
- }
-
- if (i >= sizeof(baudtab)/sizeof(int)) {
- fprintf(stderr, "%s: Illegal baud %s\n", me, s);
- return (1);
- }
-
- if (*p < '5' || *p > '8') {
- fprintf(stderr,"%s: Illegal word length %c\n", me, *p);
- return (1);
- }
- baudetc |= (*p - '5');
- p++;
- for (i=0; i < 3; i++)
- if (*p == partab[i][0]) {
- baudetc |= partab[i][1];
- break;
- }
- if (i >= 3) {
- fprintf(stderr,"%s: Unknown parity %c\n",me, *p);
- return (1);
- }
-
- p++;
- if (*p < '1' || *p > '2') {
- fprintf(stderr,"%s: Illegal stop bit %c\n", *p);
- return (1);
- }
- baudetc |= (*p - '1') << 2;
- return (0);
- }
-
-
- int hndlbrk()
- {
- char abort[] = "\rAT\r"; /* \r to terminate possible cmd */
- char i;
-
- /* cancel any modem cmd in progress */
- writecom(abort); /* This MAY produce an OK, OR start a cmd going! */
- for (i=0; i<15; i++) { /* try 15 times */
- if (!waitfor(OK, 2, "", 0)) break; /* wait 2 secs for an OK */
- writecom(abort); /* try to elicit an OK again */
- }
- hangup(); /* undo what we did so far */
- return(0); /* 0 => abort */
- }
-