char *ckxv = "Comm line I/O CTOS/BTOS Version-2.00, May 1992"; /* C-Kermit interrupt, terminal control & i/o functions for CTOS systems */ /* Joel Dunn, UNC-CH Administrative Data Processing */ /* Modifications - Joel Dunn 9/21/87 Set video pause off in ttpkt and on in ttres to allow large files to be sent without having to press next-page - Joel Dunn 12/8/87 Return 0 on erc 602 in coninc, otherwise it streams when run under CM/VM Doug Drury May 1991 Implemented HANGUP command in TTHANG patterned after UNIX TTHANG Modified TTPKT to fix BTOS problem that occured when an erc was incorrectly detected during line conditioning Evan Arnerich - Mar 1992 Modified parity logic to set databits to 8 whenever parity is none, otherwise set databits to 7 for all other parity settings. Evan Arnerich/Doug Drury - May 1992 Modified logic to set flow control according to operator-set parameter. **/ char *ckxsys = " CTOS 11.2 Standard Software"; /* Variables available to outside world: dftty -- Pointer to default tty name string, like "[comm]x". dfloc -- 0 if dftty is console, 1 if external line. dfprty -- Default parity dfflow -- Default flow control ckxech -- Flag for who echoes console typein: 1 - The program (system echo is turned off) 0 - The system (or front end, or terminal). functions that want to do their own echoing should check this flag before doing so. Functions for assigned communication line (either external or console tty): ttopen(ttname,local,mdmtyp) -- Open the named tty for exclusive access. ttclos() -- Close & reset the tty ttpkt(speed,flow) -- Put the tty in packet mode and set the speed. ttvt(speed,flow) -- Put the tty in virtual terminal mode. or in DIALING or CONNECTED modem control state. ttinl(dest,max,timo,eol)-- Timed read line from the tty. ttinc(timo) -- Timed read character from tty. myread() -- timed or untimed comm line read ttol(string,length) -- Write a string to the tty. ttoc(c) -- Write a character to the tty. ttflui() -- Flush tty input buffer. tthang() -- Hangup line. */ /* Functions for console terminal: congm() -- Get console terminal modes. concb(esc) -- Put the console in single-character wakeup mode with no echo. conbin(esc) -- Put the console in binary (raw) mode. conres() -- Restore the console to mode obtained by congm(). conoc(c) -- Unbuffered output, one character to console. conol(s) -- Unbuffered output, null-terminated string to the console. conola(s) -- Unbuffered output, array of strings to the console. conxo(n,s) -- Unbuffered output, n characters to the console. conchk() -- Check if characters available at console coninc(timo) -- Timed get a character from the console. conint() -- Enable terminal interrupts on the console if not background. connoi() -- Disable terminal interrupts on the console if not background. Time functions msleep(m) -- Millisecond sleep ztime(&s) -- Return pointer to date/time string */ /* Includes */ #include "ctermi.h" #ifndef DIRSIZ #ifdef MAXNAMLEN #define DIRSIZ MAXNAMLEN #else #define DIRSIZ 14 #endif #endif /* Declarations */ /* dftty is the device name of the default device for file transfer */ /* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */ struct configtype { /* config area for acquirebytestreamc */ char cctype; /* is a comm config area */ int cspeed; /* baud rate*/ char cstop; /* stop bits */ char cdummy1; char cdatab; /* data bits */ char cparity; /* 1 = even parity, 0 = none, 2 = odd, 3 = mark, 4 = space */ char clinec; /* line control, 0 = none, 1 = xon, 2 = cts, 3 = both */ int cdummy2; char cnlmap; /* new line mapping, 0 = binary, 1 = CR, 2 = CR/LF */ char clfmap; /* LF mapping, 0 = binary, 1 = CR/LF */ int ctrto; /* transmit timeout */ int crecto; /* receive timeout */ int ceofb; /* EOF byte */ int cdummy3; char cunknown1; char cunknown2; char cunknown3; char cunknown4; char cunknown5; char cunknown6; char cunknown7; char cunknown8; char cdummy4[34]; int cunknown9; char cdummy5[448]; }; static struct configtype configarea; char *dftty = "[comm]x"; static char BSWA[130]; extern char bsvid[130]; int dfloc = 0; int dfprty = 'e'; /* Parity ('e' = even) */ int dfflow = 1; /* Xon/Xoff flow control */ int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */ extern int parity; /* pick up parity for use in writebytestreamparamc */ /* Declarations of variables global within this module */ static conif = 0, /* Console interrupts on/off flag */ cgmf = 0, /* Flag that console modes saved */ xlocal = 0, /* Flag for tty local or remote */ ttyfd = -1; /* TTY file descriptor */ static char escchr; /* Escape or attn character */ static char commbuff[4096]; /* bytestream buffer area */ static int erc; /* CTOS error number */ unsigned int ttsspd(); /* make sure baud rate is a "real word" */ /* T T O P E N -- Open a tty for exclusive access. */ /* Returns 0 on success, -1 on failure. */ ttopen(ttname,lcl,modem) char *ttname; int lcl, modem; { int openmode=0x6d6d; if (ttyfd > -1) return(0); /* If already open, ignore this call */ if (*ttname != '[') return(-1); /* ignore bad format */ configarea.cctype = 0x03; configarea.cspeed = 0x4b0; configarea.cstop = 0x01; configarea.cdatab = 0x07; switch(parity) { case 'e' : configarea.cparity = 0x01; break; case 'o' : configarea.cparity = 0x02; break; case 'm' : configarea.cparity = 0x03; break; case 's' : configarea.cparity = 0x04; break; case 0 : configarea.cdatab = 0x08; configarea.cparity = 0x00; break; default : parity = 'e'; configarea.cparity = 0x01; break; } configarea.clinec = 0x01; configarea.cnlmap = 0x00; configarea.clfmap = 0x00; configarea.ctrto = 0x00; configarea.crecto = 0x00; configarea.ceofb = 0x00; configarea.cunknown1 = 0x01; configarea.cunknown2 = 0x02; configarea.cunknown3 = 0x02; configarea.cunknown4 = 0x02; configarea.cunknown5 = 0x01; configarea.cunknown6 = 0x02; configarea.cunknown7 = 0x02; configarea.cunknown8 = 0x01; configarea.cunknown9 = 0x5454; erc = acquirebytestreamc(&BSWA[0], ttname, strlen(ttname), openmode, &configarea, &commbuff[0], 1024, &commbuff[1024], 3072, 512, 0); debug(F101,"ttopen, acquirebytestream erc","",erc); if (erc > 0) { ttyfd = -1; return(-1); } ttyfd = 0; erc = setimagemodec(&BSWA[0], 2); debug(F101,"ttopen, setimagemodec erc","",erc); return(0); } /* T T C L O S -- Close the TTY */ ttclos() { debug(F101,"ttclos, ttyfd","",ttyfd); if (ttyfd < 0) return(0); /* Wasn't open. */ ttres(); /* Reset modes. */ erc = closebytestream(&BSWA[0]); debug(F101,"ttclos, closebytestream erc","",erc); ttyfd = -1; /* Mark it as closed. */ return(0); } /* T T R E S -- Restore terminal to "normal" mode. */ ttres() { /* Restore the tty to normal. */ int cbwritten; char s[3] = {'\377','P','N'}; if (ttyfd < 0) return(-1); /* Not open. */ /* set video pause on */ erc = writebsrecord(&bsvid[0], s, 3, &cbwritten); return(0); } /* T T P K T -- Condition the communication line for packets. */ /* or for modem dialing */ /* If called with speed > -1, also set the speed. */ /* Returns 0 on success, -1 on failure. */ ttpkt(speed,flow) int speed, flow; { extern char ttname[]; unsigned int s; unsigned int p; int parmno=2; int b; int cbwritten; int x; char v[3] = {'\377','P','F'}; if (ttyfd < 0) return(-1); /* Not open. */ s = ttsspd(speed); /* Check the speed */ /* set speed */ debug(F101,"ttpkt, speed","",s); if (s > 0) { /* the following FOR loop was added because of a problem that sometimes occures where the modem IS ready but still returns an ERC of 300 */ for(x=0; x<5; x++) { erc = writebytestreamparameterc(&BSWA[0], parmno, s); if (erc == 0) break; delay (1); } x = erc; /* save ERC so debug doesn't reset it */ debug(F101,"ttpkt, speed erc","",erc); if (x > 0) return(-1); } /* set parity */ parmno = 1; switch(parity) { case 'e' : p = 1; b = 7; break; case 'o' : p = 2; b = 7; break; case 'm' : p = 3; b = 7; break; case 's' : p = 4; b = 7; break; case 0 : p = 0; b = 8; break; default : return(-1); } debug(F101,"ttpkt, parity","",p); /* the following FOR loop was added because of a problem that sometimes occures where the modem IS ready but still returns an ERC of 300 */ for(x=0; x<5; x++) { erc = writebytestreamparameterc(&BSWA[0], parmno, p); if (erc == 0) break; delay (1); } x = erc; /* Save ERC so debug doesn't reset it */ debug(F101,"ttpkt, parity erc","",erc); if (x > 0) return(-1); /* set data bits */ parmno = 0; debug(F101,"ttpkt, data bits","",b); /* the following FOR loop was added because of a problem that sometimes occures where the modem IS ready but still returns an ERC of 300 */ for(x=0; x<5; x++) { erc = writebytestreamparameterc(&BSWA[0], parmno, b); if (erc == 0) break; delay (1); } x = erc; /* Save ERC so debug doesn't reset it */ debug(F101,"ttpkt, data bits erc","",erc); if (x > 0) return(-1); /* set flow control */ parmno = 8; debug(F101,"ttpkt, flow control","",flow); /* the following FOR loop was added because of a problem that sometimes occures where the modem IS ready but still returns an ERC of 300 */ for(x=0; x<5; x++) { erc = writebytestreamparameterc(&BSWA[0], parmno, flow); if (erc == 0) break; delay (1); } x = erc; /* Save ERC so debug doesn't reset it */ debug(F101,"ttpkt, flow control erc","",erc); if (x > 0) return(-1); /* set video pause off */ erc = writebsrecord(&bsvid[0], v, 3, &cbwritten); ttflui(); /* Flush any pending input */ return(0); } /* T T V T -- Condition communication line for use as virtual terminal */ ttvt(speed,flow) int speed, flow; { extern char ttname[]; unsigned int s; unsigned int p; int parmno=2; int b; int settry=0; if (ttyfd < 0) return(-1); /* Not open. */ s = ttsspd(speed); /* Check the speed */ /* set speed */ debug(F101,"ttvt, speed","",s); if (s > 0) { erc = writebytestreamparameterc(&BSWA[0], parmno, s); debug(F101,"ttvt, speed erc","",erc); while ((settry < 10) && (erc)) { erc = writebytestreamparameterc(&BSWA[0], parmno, s); debug(F101,"ttvt, speed erc (in loop)","",erc); debug(F101,"ttvt, speed set try number","",settry); if (erc) delay(10); /* retry 10 times at 1 second inteveral, may get erc 300 if line is active (this is defensive programming) */ settry++; } if (erc > 0) return(-1); } /* set parity */ parmno = 1; switch(parity) { case 'e' : p = 1; b = 7; break; case 'o' : p = 2; b = 7; break; case 'm' : p = 3; b = 7; break; case 's' : p = 4; b = 7; break; case 0 : p = 0; b = 8; break; default : return(-1); } debug(F101,"ttvt, parity","",p); erc = writebytestreamparameterc(&BSWA[0], parmno, p); debug(F101,"ttvt, parity erc","",erc); if (erc > 0) return(-1); /* set data bits */ parmno = 0; debug(F101,"ttvt, parity","",b); erc = writebytestreamparameterc(&BSWA[0], parmno, b); debug(F101,"ttvt, data bits erc","",erc); if (erc > 0) return(-1); ttflui(); /* Flush any pending input */ return(0); } /* T T S S P D -- Return the internal baud rate code for 'speed'. */ unsigned int ttsspd(speed) { unsigned int s; int spdok; if (speed < 0) return(-1); spdok = 1; /* Assume arg ok */ switch (speed) { case 0: s = 0; break; case 300: s = 300; break; case 1200: s = 1200; break; case 2400: s = 2400; break; case 4800: s = 4800; break; case 9600: s = 9600; break; default: spdok = 0; fprintf(stderr,"Unsupported line speed - %d\n",speed); fprintf(stderr,"Current speed not changed\n"); break; } if (spdok) return(s); else return(-1); } /* T T F L U I -- Flush tty input buffer */ ttflui() { unsigned int cbdiscard=0; while (myread(0)) cbdiscard++; debug(F101,"ttflui, input bytes discarded: ","",cbdiscard); return(0); } /* T T H A N G -- Hangup the line */ tthang(){ int x,y; y = 0x08; erc = readstatusc(&BSWA[0], y, &x); /*just see if its active */ if (erc != 0) return(0); /* return success if can't access line */ x = 0; y = 0x300; erc = writestatusc(&BSWA[0], y, x); /* drop DTR to hang up */ ttclos(); return(0); } /* C O N I N T -- Console Interrupt setter */ conint(f) int (*f) (); { return 0; } /* C O N N O I -- Reset console terminal interrupts */ connoi () { return 0; } /* M Y R E A D -- read a character, timed or untimed */ myread(timo) int timo; { /* return character or -1 if disconnected */ unsigned char *pch; unsigned int ch; unsigned int badchar=0x04; int cbreceived; int exchwait; int timerexit; struct ctostimer trb1; struct ctostimer *ptrb1; cbreceived = 0; if (timo == 0) { erc = fillbufferasyncc(&BSWA[0], 0, 1, &pch, &cbreceived,0,0l,0); if (erc) debug(F101,"myread, fillbuff erc: ","",erc); if (erc) { switch(erc) { case 2340: case 2341: case 2342: cbreceived = 1; pch = &badchar; break; case 2349: break; default: return(-1); } } if (cbreceived) return(ch = (*pch & 0xff)); else return(0); } else { timerexit = 0; allocexch(&exchwait); trb1.ctt_counter = 10*timo; trb1.ctt_reload = 0; trb1.ctt_cevents = 0; trb1.ctt_exchresp = exchwait; trb1.ctt_ercret = 0; trb1.ctt_rqcode = exchwait; openrtclock(&trb1); while (!timerexit) { erc = fillbufferasyncc(&BSWA[0], 0, 1, &pch, &cbreceived,0,0l,0); if (erc) debug(F101,"myread(timo), fillbuff erc: ","",erc); if (erc) { switch(erc) { case 2340: case 2341: case 2342: cbreceived = 1; pch = &badchar; break; case 2349: break; default: return(-1); } } if (cbreceived) break; if (!check(exchwait, &ptrb1)) if (ptrb1->ctt_rqcode == exchwait) timerexit = 1; } closertclock(&trb1); deallocexch(exchwait); if ((timerexit) && (!cbreceived)) return(-1); if (cbreceived) return (ch = (*pch & 0xff)); else return(-1); } } /* T T O L -- Similar to "ttinl", but for writing. */ ttol(s,n) int n; char *s; { int x=0; int cbwritten; char no=0; if (ttyfd < 0) return(-1); /* Not open. */ erc = flushbufferc(&BSWA[0], s, n, &cbwritten); if (erc > 0) x = -1; debug(F111,"ttol",s,n); if (x < 0) debug(F101,"ttol failed","",erc); checkpointbsc(&BSWA[0], no); return(x); } /* T T O C -- Output a character to the communication line */ ttoc(c) char c; { int x=0; int cbwritten; if (ttyfd < 0) return(-1); /* Not open. */ erc = flushbufferc(&BSWA[0], &c, 1, &cbwritten); if (erc > 0) x = -1; return(x); } /* T T I N L -- Read a record (up to break character) from comm line. */ /* If no break character encountered within "max", return "max" characters, with disposition of any remaining characters undefined. Otherwise, return the characters that were read, including the break character, in "dest" and the number of characters read as the value of function, or 0 upon end of file, or -1 if an error occurred. Times out & returns error if not completed within "timo" seconds. */ ttinl(dest,max,timo,eol) int max,timo; char *dest; char eol; { int x, c; int exchwait; int timerexit; struct ctostimer trb1; struct ctostimer *ptrb1; if (ttyfd < 0) return(-1); /* Not open. */ allocexch(&exchwait); trb1.ctt_counter = 10*timo; trb1.ctt_reload = 0; trb1.ctt_cevents = 0; trb1.ctt_exchresp = exchwait; trb1.ctt_ercret = 0; trb1.ctt_rqcode = exchwait; openrtclock(&trb1); x = c = 0; timerexit = 0; while ((x < max) && (c != eol) && (!timerexit)) { c = myread(0); if (c > 0) { dest[x] = c; x++; } if (!check(exchwait, &ptrb1)) if (ptrb1->ctt_rqcode == exchwait) timerexit = 1; } if (c > 0) x++; else x = -1; closertclock(&trb1); deallocexch(exchwait); return(x); /* Return the count. */ } /* T T I N C -- Read a character from the communication line */ ttinc(timo) int timo; { int ch; if (ttyfd < 0) return(-1); /* Not open. */ if (timo <= 0) { /* Untimed. */ /* comm line failure returns -1 thru myread, so don't &= 0377 */ return( myread(timo) ); } ch = myread(timo); if (ch > 0) return(ch & 0377); else return(ch); /* Return char or -1. */ } /* T T S N D B -- Send a BREAK signal */ ttsndb() { int x; if (ttyfd < 0) return(-1); /* Not open. */ erc = sendbreakc(&BSWA[0]); if (erc != 0) { conol("Can't send BREAK"); return(-1); } return(0); } /* M S L E E P -- Millisecond version of sleep(). */ /* Intended only for small intervals. For big ones, just use sleep(). */ msleep(m) int m; { delay(m); return(0); } /* Z T I M E -- Return date/time string */ ztime(s) char **s; { static char sbdatetimeret[32]; long int datetimeret; unsigned char expdatetimeret[8]; int i; for (i = 0; i < 31; i++) sbdatetimeret[i] = '\0'; erc = getdatetime(&datetimeret); if (!erc) erc = expanddatetime(datetimeret, &expdatetimeret[0]); if (!erc) erc = formattime(&sbdatetimeret[0], &expdatetimeret[0]); *s = &sbdatetimeret[1]; return(0); } /* C O N G M -- Get console terminal modes. */ /* Saves current console mode, and establishes variables for switching between current (presumably normal) mode and other modes. */ congm() { /* don't know what will be needed under CTOS */ cgmf = 1; } /* C O N C B -- Put console in cbreak mode. */ /* Returns 0 if ok, -1 if not */ concb(esc) char esc; { /* don't know what will be needed under CTOS, this looks good */ if (cgmf == 0) congm(); /* Get modes if necessary. */ escchr = esc; /* Make this available to other fns */ ckxech = 1; /* Program can echo characters */ return(0); } /* C O N B I N -- Put console in binary mode */ /* Returns 0 if ok, -1 if not */ conbin(esc) char esc; { int cbwritten; char s[3] = {'\377','P','F'}; /* set video pause off */ int x = 3; if (cgmf == 0) congm(); /* Get modes if necessary. */ escchr = esc; /* Make this available to other fns */ ckxech = 1; /* Program can echo characters */ erc = writebsrecord(&bsvid[0], s, x, &cbwritten); if (erc == 0) return(0); else return(-1); } /* C O N R E S -- Restore the console terminal */ conres() { int cbwritten; char s[3] = {'\377','P','F'}; /* set video pause back off */ int x = 3; if (cgmf == 0) return(0); /* Don't do anything if modes not saved */ cgmf = 0; ckxech = 0; /* System should echo chars */ erc = writebsrecord(&bsvid[0], s, x, &cbwritten); if (erc == 0) return(0); else return(-1); } /* C O N O C -- Output a character to the console terminal */ conoc(c) char c; { erc = writebyte(&bsvid[0], c); } /* C O N X O -- Write x characters to the console terminal */ conxo(x,s) char *s; int x; { int cbwritten; writebsrecord(&bsvid[0], s, x, &cbwritten); } /* C O N O L -- Write a line to the console terminal */ conol(s) char *s; { int len; int cbwritten; len = strlen(s); writebsrecord(&bsvid[0], s, len, &cbwritten); } /* C O N O L A -- Write an array of lines to the console terminal */ conola(s) char *s[]; { int i; for (i=0 ; *s[i] ; i++) conol(s[i]); } /* C O N O L L -- Output a string followed by CRLF */ conoll(s) char *s; { conol(s); writebyte(&bsvid[0], 0x0d); writebyte(&bsvid[0], 0x0a); } /* C O N C H K -- Check if characters available at console */ conchk() { int ch; erc = readkbddirect(3, &ch); if (erc) return(0); else return(1); } /* C O N I N C -- Get a character from the console */ coninc(timo) int timo; { int exchwait; int timerexit; struct ctostimer trb1; struct ctostimer *ptrb1; int ch; ch = 0; if (timo <= 0 ) { /* untimed */ erc = readkbddirect(1, &ch); /* Read a character. */ if (ch == 0x0a) ch = 0x0d; else if (ch == 0x0d) ch = 0x0a; ch &= 0377; if (erc == 602) return(0); /* 602 means no char is available */ /* chg for CTOS/VM, was just erc = 0 on 602 */ if (erc == 0) return(ch); /* Return the char if read */ else return(-1); /* Return the char, or -1. */ } if (timo = 9999 ) { /* wait forever */ erc = readkbddirect(0, &ch); /* Read a character. */ if (ch == 0x0a) ch = 0x0d; else if (ch == 0x0d) ch = 0x0a; ch &= 0377; if (erc == 0) return(ch); /* Return the char if read */ else return(-1); /* Return the char, or -1. */ } timerexit = 0; allocexch(&exchwait); trb1.ctt_counter = 10*timo; trb1.ctt_reload = 0; trb1.ctt_cevents = 0; trb1.ctt_exchresp = exchwait; trb1.ctt_ercret = 0; trb1.ctt_rqcode = exchwait; openrtclock(&trb1); erc = 602; while ((!timerexit) && (erc == 602)) { erc = readkbddirect(1, &ch); /* Read a character. */ if (!check(exchwait, &ptrb1)) if (ptrb1->ctt_rqcode == exchwait) timerexit = 1; } deallocexch(exchwait); closertclock(&trb1); if (ch == 0x0a) ch = 0x0d; else if (ch == 0x0d) ch = 0x0a; ch &= 0377; if (erc == 0) return(ch); else return(-1); }