Imported Debian patch 5.1-10
[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 #if !defined(__FreeBSD_kernel__)
151   tt.c_oflag &= (~(TABDLY | ONLCR));
152 #endif
153 #endif
154   res = tcsetattr(TTY_fd, TCSANOW, &tt);
155
156   oldbits[TTY_fd] = bitsleft[TTY_fd] = 0;
157
158   /* Perform start-up power on delay and data flush. */
159
160 #ifdef REG_INIT
161   if (REG_INIT > 0) {
162     sleep(REG_INIT);
163   }
164 #endif
165
166 #ifdef REG_DISCARD
167   if (REG_DISCARD > 0) {
168     int d, n1;
169     char c1;
170
171     for (d = 0; d < REG_DISCARD; d++) {
172       do {
173         n1 = read(TTY_fd, &c1, 1);
174       } while (n1 == 0 || (n1 == -1 && errno == EAGAIN));
175     }
176   }
177 #endif
178
179 #ifdef FLUSH
180   flush_fd = TTY_fd;
181 #endif
182
183   return TTY_fd;
184 }
185
186 static int32 Sample(int32 dd, uint16 bits) {
187   int32 bc, sum, n1;
188   uint8 c1;
189
190 #ifdef Solaris
191 #ifdef SWITCH_READ
192   struct termios tt;
193
194   tcgetattr(dd, &tt);
195   tt.c_cflag |= CREAD;
196   tcsetattr(dd, TCSANOW, &tt);
197 #endif
198 #endif
199
200   if (dd < 0) return -1;
201
202   sum = bc = 0;
203   while (bc < bits) {
204     if (bitsleft[dd]) {
205       sum += (oldbits[dd] & 0x01);
206       oldbits[dd] >>= 1;
207       bitsleft[dd]--;
208       bc++;
209     } else {
210       do {
211         n1 = read(dd, &c1, 1);
212       } while (n1 == 0 || (n1 == -1 && errno == EAGAIN));
213       if (n1 == -1) {
214         /* Fatal error occurred, die now? */
215         return -1;
216       }
217
218       /* Orion REG does not compensate for first order bias.  XOR
219          each sample with 01010101b to invert the sense of
220          alternate bits in the samples. */
221
222       c1 ^= 0x55;
223 #ifdef DUMPREG
224       dumpbuf[dumpptr++] = c1;
225       if (dumpptr >= sizeof(dumpbuf)) {
226         fwrite(dumpbuf, sizeof(dumpbuf), 1, dumpfile);
227         dumpptr = 0;
228       }
229 #endif
230       oldbits[dd] = c1;
231       bitsleft[dd] = 8;
232     }
233   }
234
235 #ifdef Solaris
236 #ifdef SWITCH_READ
237   tcgetattr(dd, &tt);
238   tt.c_cflag &= ~CREAD;
239   tcsetattr(dd, TCSANOW, &tt);
240 #endif
241 #endif
242   return sum;
243 }
244
245 #define SAMP_PERIOD     1000    /* msec */
246 #define MARGIN          .95     /* how much to headroom to allow in
247                                    speed measurement */
248
249 static int32 EvalSpeed(int32 dd) {
250   struct timeval start, end;
251   int32 bitct, samp;
252
253   if (dd < 0) return -1;
254
255   gettimeofday(&start, NULL);
256   bitct = 0;
257   while (1) {
258     gettimeofday(&end, NULL);
259     if (deltams(&end, &start) >= SAMP_PERIOD) break;
260     samp = Sample(dd, 1);
261     bitct++;
262   }
263
264   return (int32)(bitct * MARGIN);
265 }
266
267 static int32 Discard(int32 dd) {
268   int32 disc;
269 #ifdef CPU_BOUND
270   int32  n1;
271   uint8 c1;
272 #endif
273   
274   if (dd < 0) return -1;
275
276   disc = bitsleft[dd];
277   bitsleft[dd] = 0;
278
279 #ifdef CPU_BOUND
280   do {
281     n1 = read(dd, &c1, 1);
282     if (n1 == 1) disc++;
283   } while (n1 == 1);
284 #else
285   tcflush(dd, TCIFLUSH);
286 #endif
287
288   return disc;
289 }
290
291 static int32 CloseDev(int32 dd) {
292   if (dd < 0) return -1;
293
294   close(dd);
295   return 0;
296 }
297
298 /*  Driver description table.  */
299
300 REG_driver REG_orion = {
301                         "ORION", 
302                         1000,
303                         OpenDev,
304                         EvalSpeed,
305                         Sample,
306                         Discard,
307                         CloseDev
308                       };