home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HAM Radio 1
/
HamRadio.cdr
/
misc
/
rc85_prg
/
rc85prg.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-10-11
|
16KB
|
610 lines
/* 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 */
}