Imported Upstream version 5.1
[debian/gcpegg] / reg_orion.c
1 /* PROGRAM:     eggsh
2  * FILE:        $Header: /home/egg/src/RCS/reg_orion.c,v 1.1 1998/12/31 22:04:39 ghn Exp $
3  * PURPOSE:     PEAR (Bradish box/micro-REG) hardware interface
4  * AUTHOR:      Greg Nelson
5  * DATE:        98-04-12
6  *
7  * REVISED:     $Log: reg_orion.c,v $
8  * REVISED:     Revision 1.1  1998/12/31 22:04:39  ghn
9  * REVISED:     Initial revision
10  * REVISED:
11  * REVISED:     Revision 1.3  1998/08/01 18:50:39  ghn
12  * REVISED:     Added John's byte-order-independence changes and PSEUDO support.
13  * REVISED:
14  * REVISED:     Revision 1.2  1998/08/01 17:13:51  ghn
15  * REVISED:     Added John's Solaris support and DUMPREG option.
16  * REVISED:
17  * REVISED:     Revision 1.1  1998/07/21 11:37:41  ghn
18  * REVISED:     Initial revision
19  * REVISED:
20  * Copyright 1998 - Greg Nelson
21  * Redistributable under the terms of the GNU Public Licence (GPL)
22  */
23
24 /* Define this to dump samples from the REG which we actually use into
25    a file named dumpreg.dat.  This can be used to debug serial port
26    mode problems (for example, setting the character frame to 7 bits,
27    or telling it to ignore breaks, which will lose all zero bytes. */
28 /* #define DUMPREG */
29
30 #include <stdio.h>
31 #ifdef __USE_BSD
32 #undef __USE_BSD
33 #endif
34 #define __USE_BSD
35 #include <termios.h>
36 #undef __USE_BSD
37 #include <unistd.h>
38 #include <fcntl.h>
39 #define __USE_BSD
40 #include <errno.h>
41 #undef __USE_BSD
42
43 #include "global.h"
44 #include "genlib.h"
45 #include "reg.h"
46
47 #define MAXDEV  20
48
49 /*  The Orion REG is powered by the serial port into which
50     it is plugged.  If the port is not providing power to
51     the REG before we initialise it, the REG may deliver
52     garbage data as the power comes up.  To guard against
53     this we take two precautions.  First of all, we sleep
54     REG_INIT seconds after initialising the serial port to
55     let the REG start up and stabilise after power is
56     turned on, and we further discard REG_DISCARD initial
57     samples which may have been queued as the REG was
58     powering up.  If either of these symbols is not defined
59     or zero, the corresponding start-up action will not
60     be taken.  */
61
62 #define REG_INIT        10            /* REG power on delay */
63 #define REG_DISCARD     1024          /* Bytes to discard at start-up */
64
65 static int32 oldbits[MAXDEV], bitsleft[MAXDEV];
66
67 #ifdef DUMPREG
68 static FILE *dumpfile;                /* REG dump file handle */
69 static unsigned char dumpbuf[1024];   /* REG dump buffer */
70 static int dumpptr = 0;               /* Pointer into dump buffer */
71 #endif
72
73 #ifdef FLUSH
74 extern int flush_fd;                  /* File descriptor for auto-flush */
75 #endif
76
77 static int32 OpenDev(DevOpts *opts) {
78   char ttydev[30];
79   speed_t baudcon;
80   struct termios tt;
81   int32 TTY_fd, res;
82
83 #ifdef DUMPREG
84   dumpfile = fopen("dumpreg.dat", "w");
85   setbuf(dumpfile, NULL);
86   dumpptr = 0;
87 #endif
88
89 #ifdef Solaris
90   /* Serial ports (at least built-in ones) have names of
91      /dev/term/a, /dev/term/b, etc.  Map the port numbers
92      from the RC file into this nomenclature, with "1"
93      designating /dev/term/a. */
94 #ifdef Irix
95   sprintf(ttydev, "/dev/ttyd%d", opts->port);
96 #else
97   sprintf(ttydev, "/dev/term/%c", 'a' + (opts->port - 1));
98 #endif
99 #else
100   sprintf(ttydev, "/dev/ttyS%d", opts->port);
101 #endif
102
103   switch(opts->baud) {
104   case 1200: baudcon = B1200; break;
105   case 2400: baudcon = B2400; break;
106   case 4800: baudcon = B4800; break;
107   case 9600: baudcon = B9600; break;
108   case 19200: baudcon = B19200; break;
109   case 38400: baudcon = B38400; break;
110 #ifndef Irix
111   case 115200: baudcon = B115200; break;
112 #endif
113   default:
114     printf("%s: Baud rate %ld not supported.\n", pgmname, opts->baud);
115     return -1;
116   }
117
118   fprintf(stderr, "Opening %s at %ld\n", ttydev, opts->baud);
119   if ((TTY_fd = open(ttydev, O_RDONLY
120 #ifdef CPU_BOUND
121                                     | O_NDELAY
122 #endif
123       )) < 0) {
124     perror(pgmname);
125 fprintf(stderr, "Error in open(%s)\n", ttydev);
126     return -1;
127   }
128
129   if (TTY_fd >= MAXDEV) {
130     fprintf(stderr, "%s: Too many devices open.\n", pgmname);
131     close(TTY_fd);
132     return -1;
133   }
134
135   res = tcgetattr(TTY_fd, &tt);
136 #ifdef Solaris
137   tt.c_iflag = 0;
138   tt.c_oflag = 0;
139 #ifdef SWITCH_READ
140   tt.c_cflag = baudcon | CS8 | CLOCAL;
141 #else
142   tt.c_cflag = baudcon | CS8 | CREAD | CLOCAL;
143 #endif
144   tt.c_lflag = 0;
145   tt.c_cc[VMIN] = 1;    /* This many chars satisfies reads */
146   tt.c_cc[VTIME] = 0;   /* or in this many tenths of seconds */
147 #else
148   res = cfsetospeed(&tt, baudcon); 
149   cfmakeraw(&tt);
150   tt.c_oflag &= (~(TABDLY | ONLCR));
151 #endif
152   res = tcsetattr(TTY_fd, TCSANOW, &tt);
153
154   oldbits[TTY_fd] = bitsleft[TTY_fd] = 0;
155
156   /* Perform start-up power on delay and data flush. */
157
158 #ifdef REG_INIT
159   if (REG_INIT > 0) {
160     sleep(REG_INIT);
161   }
162 #endif
163
164 #ifdef REG_DISCARD
165   if (REG_DISCARD > 0) {
166     int d, n1;
167     char c1;
168
169     for (d = 0; d < REG_DISCARD; d++) {
170       do {
171         n1 = read(TTY_fd, &c1, 1);
172       } while (n1 == 0 || (n1 == -1 && errno == EAGAIN));
173     }
174   }
175 #endif
176
177 #ifdef FLUSH
178   flush_fd = TTY_fd;
179 #endif
180
181   return TTY_fd;
182 }
183
184 static int32 Sample(int32 dd, uint16 bits) {
185   int32 bc, sum, n1;
186   uint8 c1;
187
188 #ifdef Solaris
189 #ifdef SWITCH_READ
190   struct termios tt;
191
192   tcgetattr(dd, &tt);
193   tt.c_cflag |= CREAD;
194   tcsetattr(dd, TCSANOW, &tt);
195 #endif
196 #endif
197
198   if (dd < 0) return -1;
199
200   sum = bc = 0;
201   while (bc < bits) {
202     if (bitsleft[dd]) {
203       sum += (oldbits[dd] & 0x01);
204       oldbits[dd] >>= 1;
205       bitsleft[dd]--;
206       bc++;
207     } else {
208       do {
209         n1 = read(dd, &c1, 1);
210       } while (n1 == 0 || (n1 == -1 && errno == EAGAIN));
211       if (n1 == -1) {
212         /* Fatal error occurred, die now? */
213         return -1;
214       }
215
216       /* Orion REG does not compensate for first order bias.  XOR
217          each sample with 01010101b to invert the sense of
218          alternate bits in the samples. */
219
220       c1 ^= 0x55;
221 #ifdef DUMPREG
222       dumpbuf[dumpptr++] = c1;
223       if (dumpptr >= sizeof(dumpbuf)) {
224         fwrite(dumpbuf, sizeof(dumpbuf), 1, dumpfile);
225         dumpptr = 0;
226       }
227 #endif
228       oldbits[dd] = c1;
229       bitsleft[dd] = 8;
230     }
231   }
232
233 #ifdef Solaris
234 #ifdef SWITCH_READ
235   tcgetattr(dd, &tt);
236   tt.c_cflag &= ~CREAD;
237   tcsetattr(dd, TCSANOW, &tt);
238 #endif
239 #endif
240   return sum;
241 }
242
243 #define SAMP_PERIOD     1000    /* msec */
244 #define MARGIN          .95     /* how much to headroom to allow in
245                                    speed measurement */
246
247 static int32 EvalSpeed(int32 dd) {
248   struct timeval start, end;
249   int32 bitct, samp;
250
251   if (dd < 0) return -1;
252
253   gettimeofday(&start, NULL);
254   bitct = 0;
255   while (1) {
256     gettimeofday(&end, NULL);
257     if (deltams(&end, &start) >= SAMP_PERIOD) break;
258     samp = Sample(dd, 1);
259     bitct++;
260   }
261
262   return (int32)(bitct * MARGIN);
263 }
264
265 static int32 Discard(int32 dd) {
266   int32 disc;
267 #ifdef CPU_BOUND
268   int32  n1;
269   uint8 c1;
270 #endif
271   
272   if (dd < 0) return -1;
273
274   disc = bitsleft[dd];
275   bitsleft[dd] = 0;
276
277 #ifdef CPU_BOUND
278   do {
279     n1 = read(dd, &c1, 1);
280     if (n1 == 1) disc++;
281   } while (n1 == 1);
282 #else
283   tcflush(dd, TCIFLUSH);
284 #endif
285
286   return disc;
287 }
288
289 static int32 CloseDev(int32 dd) {
290   if (dd < 0) return -1;
291
292   close(dd);
293   return 0;
294 }
295
296 /*  Driver description table.  */
297
298 REG_driver REG_orion = {
299                         "ORION", 
300                         1000,
301                         OpenDev,
302                         EvalSpeed,
303                         Sample,
304                         Discard,
305                         CloseDev
306                       };