/* @(#)tekdrv.c 17.1.1.1 (ES0-DMD) 01/25/02 17:33:38 */ /*=========================================================================== Copyright (C) 1995 European Southern Observatory (ESO) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, MA 02139, USA. Corresponding concerning ESO-MIDAS should be addressed as follows: Internet e-mail: midas@eso.org Postal address: European Southern Observatory Data Management Division Karl-Schwarzschild-Strasse 2 D 85748 Garching bei Muenchen GERMANY ===========================================================================*/ /* @(#)tekdrv.c 17.1.1.1 (OAA-ASTRONET) 01/25/02 17:33:38 */ /* * HEADER : tekdrv.c - Vers 3.6.002 - Sep 1993 - L. Fini, F. Tribioli * - Vers 3.6.001 - Jan 1992 - L. Fini, F. Tribioli * Generalized AGL device driver for "Tektronix like" devices * This driver can control any device emulating a tektronix 401x or 41xx, * provided device dependent sequences are stored in a file on the AGL * standard directory. Sequences are stored in the file as decimal integer * values with a terminating value 0. * The first line of the file must be a string equal to either tt, if the * device is a terminal, or to any name to be used as output file name * template (the full file name will be obtained by appending to the * template a number (0,1,...). * The second line must contain physical dimensions of device, the number * of line styles allowed (ignored since ver. 3.3 of AGL) and an optional * parameter for the number of colors allowed. When this parameter is there * a line must be added to the end of the file with the escape sequence * needed to change drawing color. * E.g.: for the plain tektronix 4010 the caps file will be as follows: * * tt # The device is a terminal * 18 12 0 # Screen dimensions , number of line styles (*) * 0 # Initialization string * 29 0 # set the graphic mode * 31 0 # Reset alpha mode * 29 27 26 0 # Enable cursor * 29 27 12 31 0 # Erase screen * 0 # Termination string * For the QMS laser printer in Tektronix emulation mode: * QMSPLOT # Output to the file QMSPLOT.n * 26.0 19.8 0 # Paper sheet dimensions, number of line styles * 94 80 89 94 95 10 94 # Initialization sequence (long sequences may be * 73 71 84 94 95 10 94 # Subdivided into more than a single line) * 80 78 94 95 10 0 # End of initialization sequence * 22 29 0 # Set the graphic mode * 27 10 0 # Reset alpha mode * 0 # Enable cursor (unsupported) * 27 12 0 # Erase screen (newpage) * 94 80 89 94 95 10 94 # Termination sequence * 73 71 69 94 95 10 94 * 80 78 94 95 10 0 # End of termination sequence * For the tektronix 41xx-42xx (color terminals): * tt # Output to terminal * 18 12 0 16 # Screen dim., # of line styles, # of colors * 27 37 33 48 0 # Initialization sequence * 29 0 # Set graphic mode * 31 0 # Reset alpha mode * 29 27 26 0 # Enable cursor * 29 27 12 31 0 # Erase screen * 27 37 33 49 0 # Termination sequence (reset ansi mode) * 27 77 76 0 # Escape sequence to change color * (*) the number of line styles on line 2 of device file is actually * ignored since vers. 3.3 of AGL * The device is selected via the string passed to init service: if the * is (e.g.:) tt\0vt640\0\0, then the file /agl/vt640.cap is used * This means that the device is declared as: tt:tkg.vt640 in the AGLDEV.DAT * file */ #include #include #include #include #include #define TRUE 1 #define FALSE 0 /* */ /* The following entry points have been defined: */ /* */ /* Function Entry point */ /* */ /* Initialize AGLINTKG */ /* Cursor en. AGLCUTKG */ /* Erase AGLERTKG */ /* Escape AGLESTKG */ /* Polyline AGLPLTKG */ /* Flush buff. AGLSETKG */ /* Finish AGLTETKG */ /* */ #define TKGDEFBAKGRN TKGWHITE /* Default Background */ #define TKGDEFFORGRN TKGBLACK /* Default foreground */ static struct /* Character buffer */ { char *BUFPNT; char DRVBUF [80]; } AGLDVBUF; #define USEFULBUF 70 #define BUFGRD (AGLDVBUF.DRVBUF+USEFULBUF) /* Buffer limit for tests */ #define CVTX(c) ((int)((c)*TKGFACTX+0.5)); #define CVTY(c) ((int)((c)*TKGFACTY+0.5)); #define INVCVTX(c) ((c)*TKGINPX); #define INVCVTY(c) ((c)*TKGINPY); /******************* Tektronix 4010 Characteristics **************************/ #define VERSCODE 36 /* Declare driver version */ #define TKGXPIXEL 1024 #define TKGYPIXEL 780 #define TKGCLR01 1 #define TKGCLR02 2 #define TKGCLR03 3 #define TKGNWIDTH 0 #define TKGBLACK 0 #define TKGRED 1 #define TKGGREEN 2 #define TKGBLUE 4 #define TKGYELLOW 6 #define TKGMAGENTA 3 #define TKGCYAN 7 #define TKGWHITE 15 #define CHARMULT 1.50 #define TKGFACTX 1023.0 /* Normalized to device coordinate */ #define TKGFACTY 779.0 /* conversion factors */ #define TKGINPX 0.0009775171 /* Device to normalized coordinate */ #define TKGINPY 0.001283697 /* conversion factors */ #define MOVE 29 #define DRAW 0 /*****************************************************************************/ /* global status variables */ /* The driver allows NDEVS different tektronix like devices to be accessed */ /* at the same time */ #define NDEVS 2 /* Number of tek-alike devices concurr. open */ #define CMDBUFLNG 100 /* Space for commands for each device */ static int isterm[NDEVS]; static int tkflags[NDEVS]; static FILE *channel[NDEVS] = { NULL, NULL }; static FILE *inchann[NDEVS]; static int color[NDEVS] = { TKGCLR01, TKGCLR01 }; static char *init[NDEVS]; static char *graph[NDEVS]; static char *alpha[NDEVS]; static char *tenable[NDEVS]; static char *erase[NDEVS]; static char *term[NDEVS]; static int ncolors[NDEVS]; static char *changecolor[NDEVS]; static char cmdbuf[NDEVS][CMDBUFLNG]; static int untouched[NDEVS]; static FILE *chn; /* current file pointer */ static float xleng,yleng; /*****************************************************************************/ /* generic static variables */ static int sendflg; /* Buffer not empty flag */ static char check[4]; /* Tektronix command character buffer */ static char iplt[4]; /************************************************************************* */ static char *fgetnxt(buf,curlng,filpt) /* get the next line from caps file */ /* and puts data into the command */ /* buffer, followed by 0 */ /* Returns pointer to first free */ /* byte of buffer */ char *buf; /* Pointer to first byte of buffer */ int *curlng; /* Remaining buffer length */ FILE *filpt; /* caps file pointer */ { int aux; char line[132]; char *pt; if(buf==NULL) return buf; if(*curlng==0) return NULL; pt=AG_GETS(line,132,filpt); if(pt==NULL) return NULL; do { int n; n=sscanf(pt,"%d",&aux); if(n==EOF) { pt=AG_GETS(line,132,filpt); if(pt==NULL) return NULL; } else { *buf = aux; (*curlng)--; if(aux==0) break; buf++; while(*pt) if(isspace(*pt)) break; else pt++; /* scan to next blank */ while(*pt) if(!isspace(*pt))break; else pt++; /* scan to next non blnk */ } } while(*curlng>0); buf++; return (buf); } static int setdev(AGLDVCOM) /* Set up device info at open. Return dev idx */ struct bufcom *AGLDVCOM; { char *pt; char *cmdbufpt; int bufspace; int i,npar,dummy; FILE *filpt; char aux[PHNAMLNG]; extern void AG_DMSG(); FILE *AGL_fopen(); for(i=0; i=NDEVS) { /* No free slot for the device */ ERRCODE=DEVOPNSEV; return(-1); } pt=CHARBUF+strlen(CHARBUF)+1; /* Skip to device type */ filpt=AG_STDO(pt,".cap",0); /* Open caps file */ if(filpt==NULL) { ERRCODE=CAPOPNSEV; return (-1); } { char line[132]; char *pt; pt=AG_GETS(line,132,filpt); sscanf(pt,"%s",aux); /* Get device type */ AG_DMSG("1st line:",aux); if(strncmp(aux,"tt",2)==0) { /* The device is a terminal */ tkflags[i]=INTERACTIVE|ERASEIT; strcpy(aux,CHARBUF); /* get device name from call buff. */ AG_DMSG("Out to:",aux); channel[i]=AGL_fopen(aux); /* Open the device */ if(channel[i] == stdout) /* Fix for OS which don't allow */ inchann[i] = stdin; /* to read from stdout */ else inchann[i] = channel[i]; isterm[i] = TRUE; /* Signal it is a terminal */ *CHARBUF='\0'; } else { /* The device is spooled */ tkflags[i]=SEPALPHA; AG_NEWN(aux); if(*aux == '\0') { ERRCODE=DEVOPNSEV; return(-1); } strcpy(CHARBUF,aux); /* pass back file name */ AG_DMSG("Out to:",aux); channel[i]=fopen(aux,B_CREATE); /* Open the file */ isterm[i] = FALSE; /* Signal it is a file */ untouched[i]=TRUE; } if(channel[i]==NULL) { ERRCODE = DEVOPNSEV; return(-1); } pt=AG_GETS(line,132,filpt); /* Read screen dimensions, line style (not used)*/ /* and number of colors (optional) */ npar=sscanf(pt, "%f %f %d %d", &xleng, &yleng, &dummy, &ncolors[i]); } bufspace = CMDBUFLNG; cmdbufpt = cmdbuf[i]; init[i] = cmdbufpt; cmdbufpt=fgetnxt(init[i],&bufspace,filpt); graph[i]=cmdbufpt; cmdbufpt=fgetnxt(graph[i],&bufspace,filpt); alpha[i]=cmdbufpt; cmdbufpt=fgetnxt(alpha[i],&bufspace,filpt); tenable[i]=cmdbufpt; cmdbufpt=fgetnxt(tenable[i],&bufspace,filpt); erase[i]=cmdbufpt; cmdbufpt=fgetnxt(erase[i],&bufspace,filpt); term[i]=cmdbufpt; cmdbufpt=fgetnxt(term[i],&bufspace,filpt); if(npar==4) /* color parameter is present in .cap file */ { ncolors[i]--; if(ncolors[i]<1) ncolors[i]=1; /* check for correct values */ changecolor[i]=cmdbufpt; cmdbufpt=fgetnxt(changecolor[i],&bufspace,filpt); } else ncolors[i]=1; /* B/W terminal (no color parameter present) */ fclose(filpt); if(cmdbufpt==NULL) { ERRCODE=CAPRDSEV; return(-1); } else return(i); } /************************************************************************* */ /* SEND Buffer Entry points */ /* */ void AGLSETKG (AGLDVCOM) /* send buffer routine */ struct bufcom *AGLDVCOM; { int nbytes; int curchn; curchn=CHANNEL; chn = channel[curchn]; if (sendflg) { char *pt = alpha[curchn]; while ( *pt ) *AGLDVBUF.BUFPNT++ = *pt++; /* set epilog command */ nbytes=AGLDVBUF.BUFPNT-AGLDVBUF.DRVBUF; /* Compute buffer leng. */ AGLDVBUF.BUFPNT = AGLDVBUF.DRVBUF; /* Reset buffer pointer */ if(isterm[curchn]) /* Send the buffer */ { AGL_fwrite(AGLDVBUF.BUFPNT,1,nbytes,chn); AGL_fflush(chn); } else fwrite(AGLDVBUF.BUFPNT,1,nbytes,chn); pt = graph[curchn]; while(*pt) *AGLDVBUF.BUFPNT++ = *pt++; /* Preset prolog command */ if ( check[0] != 0 ) /* Preset for a dummy */ { /* move to the last */ *AGLDVBUF.BUFPNT++ = MOVE; /* point, if not the */ *AGLDVBUF.BUFPNT++ = iplt[0]; /* first buffer */ *AGLDVBUF.BUFPNT++ = iplt[1]; *AGLDVBUF.BUFPNT++ = iplt[2]; *AGLDVBUF.BUFPNT++ = iplt[3]; } } sendflg = FALSE; ERRCODE=AGLNOERR; } /************************************************************************* */ /* Generic move/draw routine */ /* */ static void movtra (curchn,xx,yy,code,AGLDVCOM) int curchn; float xx,yy; int code; struct bufcom *AGLDVCOM; { static int ix0=(-1), iy0; /* Previous point memory to avoid retracing */ int ix1,iy1; if(color[curchn]==TKGDEFBAKGRN) return; /* emulate null color drawing */ ix1 = CVTX(xx); iy1 = CVTY(yy); if((ix1==ix0)&&(iy1==iy0)) /* Test if same point */ return; if ( AGLDVBUF.BUFPNT > BUFGRD ) AGLSETKG(AGLDVCOM); if ( code==MOVE ) *AGLDVBUF.BUFPNT++ = code; /* put raise "pen" code */ else untouched[curchn]=FALSE; /* Compute plot characters */ /* to get to ix, iy */ /* Order is: */ /* HIY, LOY, HIX, LOX */ ix0=ix1; iy0=iy1; iplt[0] = ((iy0>>5) & 037) | 040; iplt[1] = (iy0 & 037) | 0140; iplt[2] = ((ix0>>5) & 037) | 040; iplt[3] = (ix0 & 037) | 0100; /* Optimize output */ /* string length */ if(check[0]!=iplt[0]) { /* Include HIY */ check[0] = iplt[0]; *AGLDVBUF.BUFPNT++ = iplt[0]; } if((check[1]!=iplt[1])||(check[2]!=iplt[2])) { /* Include LOY */ check[1] = iplt[1]; *AGLDVBUF.BUFPNT++ = iplt[1]; } if(check[2]!=iplt[2]) { /* Include HIX */ check[2] = iplt[2]; *AGLDVBUF.BUFPNT++ = iplt[2]; } check[3] = iplt[3]; /* Include LOX */ *AGLDVBUF.BUFPNT++ = iplt[3]; if(code==MOVE) /* "forget" point if MOVE */ ix0= -1; sendflg = TRUE; /* Set buffer not empty flag */ } /*****************************************************************************/ /* CURSOR READ Entry points */ void AGLCUTKG (AGLDVCOM) /* Enable cursor and read position */ struct bufcom *AGLDVCOM; { int nread,flag,exprd; int curchn; char cbuf[5]; void AGL_setraw(); void AGL_reset(); curchn = CHANNEL; if( !(isterm[curchn]) ) { ERRCODE=UNSFEATINF; return; } chn = channel[curchn]; flag = (IBUFFR(1)>=0); /* Get cursor enable flag */ if(isterm[curchn]) { AGL_setraw(inchann[curchn]); /* Defined in dep.c file */ } if (flag) { int len,cnt; char *pt=cbuf; len = strlen(tenable[curchn]); AGL_fwrite(tenable[curchn],1,len,chn); /* Enable cursor */ AGL_fflush(chn); exprd=5; /* Number of chars sent when keypressed */ for(nread=0;nreaddep.c file */ } if ( nread != exprd ) { ERRCODE = DEVIOSEV; return; } if(flag) { int ixx,iyy; ixx = ((cbuf[1]&037)<<5)|(cbuf[2]&037); iyy = ((cbuf[3]&037)<<5)|(cbuf[4]&037); RBUFFR(0) = INVCVTX(ixx); RBUFFR(1) = INVCVTY(iyy); IBUFFR(2) = 0; /* Return pixel value is not supported */ } IBUFFR(1) = cbuf[0]; ERRCODE = AGLNOERR; } /*****************************************************************************/ /* ERASE SCREEN Entry points */ /* */ void AGLERTKG (AGLDVCOM) struct bufcom *AGLDVCOM; { int len; int curchn; curchn = CHANNEL; chn = channel[curchn]; len=strlen(erase[curchn]); if(isterm[curchn]) /* Send erase command */ { AGL_fwrite(erase[curchn],1,len,chn); /* Enable cursor */ AGL_fflush(chn); } else fwrite(erase[curchn],1,len,chn); ERRCODE = AGLNOERR; } /************************************************************************* */ /* DEVICE INIT Entry points */ /* */ void AGLINTKG (AGLDVCOM) /* Tektronix 4010 specific init */ struct bufcom *AGLDVCOM; { register int i=1; register char *ckpt = check; int curchn; ERRCODE=AGLNOERR; switch((int)IBUFFR(0)) { case 0: /* device hardware initialization */ curchn=setdev(AGLDVCOM); if ( curchn != (-1) ) { int len; char *pt; CHANNEL=curchn; len=strlen(init[curchn]); if(isterm[curchn]) /* Send init string */ AGL_fwrite(init[curchn],1,len,channel[curchn]); else fwrite(init[curchn],1,len,channel[curchn]); AGLDVBUF.BUFPNT = AGLDVBUF.DRVBUF; pt = graph[curchn]; while(*pt) /* Preset prolog command */ *AGLDVBUF.BUFPNT++ = *pt++; while (i++<=4) /* Set status buffer */ *ckpt++=0; sendflg = FALSE; /* Signal buffer empty */ } break; case 1: /* Pass back device characteristics */ curchn = CHANNEL; *(CHARBUF) = '\0'; RBUFFR(0) = xleng; RBUFFR(1) = yleng; IBUFFR(1) = tkflags[curchn]; IBUFFR(2) = ncolors[curchn]; IBUFFR(3) = TKGXPIXEL; IBUFFR(4) = TKGYPIXEL; IBUFFR(5) = VERSCODE; IBUFFR(6) = TKGNWIDTH; if(ncolors[curchn] > 1) { IBUFFR(7) = TKGDEFBAKGRN; IBUFFR(8) = TKGDEFFORGRN; IBUFFR(9) = TKGBLACK; IBUFFR(10) = TKGRED; IBUFFR(11) = TKGGREEN; IBUFFR(12) = TKGBLUE; IBUFFR(13) = TKGYELLOW; IBUFFR(14) = TKGMAGENTA; IBUFFR(15) = TKGCYAN; IBUFFR(16) = TKGWHITE; } else { IBUFFR(7) = 0; /* Default Background */ IBUFFR(8) = 1; /* Default foreground */ IBUFFR(9) = 0; IBUFFR(10) = 1; IBUFFR(11) = 1; IBUFFR(12) = 1; IBUFFR(13) = 1; IBUFFR(14) = 1; IBUFFR(15) = 1; IBUFFR(16) = 1; } RBUFFR(2) = CHARMULT; RBUFFR(3) = 0.0; RBUFFR(4) = 0.0; RBUFFR(5) = 0.0; RBUFFR(6) = xleng; RBUFFR(7) = yleng; RBUFFR(8) = 0.0; RBUFFR(9) = 0.0; break; case 2: /* Set color */ curchn=CHANNEL; color[curchn]=IBUFFR(1); if(ncolors[curchn]>1) { /* More than 1 color allowed */ char *pt; /* Force color number between limits */ if(color[curchn]>ncolors[curchn]) color[curchn]=ncolors[curchn]; if(color[curchn]<0) color[curchn]=0; pt=changecolor[curchn]; while(*pt) { /* Put escape seq. to change */ /* color in output buffer */ if ( AGLDVBUF.BUFPNT > BUFGRD ) AGLSETKG(AGLDVCOM); *AGLDVBUF.BUFPNT++ = *pt++; } if ( AGLDVBUF.BUFPNT > BUFGRD ) /* Put color number */ AGLSETKG(AGLDVCOM); *AGLDVBUF.BUFPNT++ = (char) color[curchn]+'0'; } break; case 3: /* set line style and line width */ ERRCODE=AGLNOERR; /* Not used since AGL 3.3 */ break; case 6: { /* Coordinate roundoff */ int ixx,iyy; ixx = CVTX(RBUFFR(0)); iyy = CVTY(RBUFFR(1)); RBUFFR(0)=INVCVTX(ixx); RBUFFR(1)=INVCVTY(iyy); } break; default: break; } } /************************************************************************* */ /* ESCAPE function */ void AGLESTKG (AGLDVCOM) struct bufcom *AGLDVCOM; { ERRCODE=UNSFEATINF; } /************************************************************************* */ /* TERMINATE Entry points */ /* */ void AGLTETKG (AGLDVCOM) struct bufcom *AGLDVCOM; { int curchn; int len,istat; extern void AG_DMSG(); curchn=CHANNEL; chn=channel[curchn]; len=strlen(term[curchn]); ERRCODE=AGLNOERR; if(isterm[curchn]) { /* Send term string */ AGL_fwrite(term[curchn],1,len,chn); AGL_fflush(chn); if(chn!=stdout) { /* Don't close std files */ istat = AGL_fclose(chn); AG_DMSG("Close","out device"); } } else { fwrite(term[curchn],1,len,chn); istat=fclose(chn); AG_DMSG("Close","out file"); IBUFFR(0)=untouched[curchn]; } if(istat==(-1)) ERRCODE=DEVIOSEV; channel[curchn] = NULL; CHANNEL = (-1); } /*****************************************************************************/ /* DRAW Entry points */ /* */ /* */ void AGLPLTKG (AGLDVCOM) /* Tektronix 4010 */ struct bufcom *AGLDVCOM; { int n; float *vectx, *vecty; int curchn; ERRCODE=AGLNOERR; n=NPOINTS; if(n<2) return; curchn=CHANNEL; vectx=VECTX; vecty=VECTY; movtra (curchn,(*vectx++),(*vecty++),MOVE,AGLDVCOM); while(n-->1) movtra (curchn,(*vectx++),(*vecty++),DRAW,AGLDVCOM); }