root/paper-tape-project/trunk/reader/reader.c

Revision 6, 8.2 kB (checked in by sven, 4 years ago)

Completed documentation (everything in english) and licence issues (everything is
GPLv3 now).

Line 
1/**
2 * GHIELMETTI FER 201 paper tape reader
3 * Linux parallel port userspace driver (ppdev)
4 *
5 * Reads bytes from the reader and prints them to
6 * STDOUT. Verbose output will be on stderr.
7 *
8 * CHANGELOG:
9 *    12.04.08  initially written
10 *
11 * The sourcecode of this program was branched from
12 * the FACIT userspace driver.
13 *
14 * Copyright (C) 2008 Sven Köppel
15 *
16 * This program is free software; you can redistribute
17 * it and/or modify it under the terms of the GNU General
18 * Public License as published by the Free Software
19 * Foundation; either version 3 of the License, or (at
20 * your option) any later version.
21 *
22 * This program is distributed in the hope that it will
23 * be useful, but WITHOUT ANY WARRANTY; without even the
24 * implied warranty of MERCHANTABILITY or FITNESS FOR A
25 * PARTICULAR PURPOSE. See the GNU General Public License
26 * for more details.
27 *
28 * You should have received a copy of the GNU General
29 * Public License along with this program; if not, see
30 * <http://www.gnu.org/licenses/>.
31 *
32 **/
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <unistd.h>
37#include <fcntl.h> /* lowlevel io */
38#include <errno.h>
39#include <stdarg.h> /* var argument list */
40#include <time.h> /* nanosleep */
41
42#include <sys/ioctl.h> 
43#include <linux/ppdev.h>
44#include <linux/parport.h>
45
46#include <sys/time.h> //  debugging
47
48#define PARPORT_DEVICE "/dev/parport0"
49
50/*#ifdef DEBUG
51#define DPRINTF(bla...)  fprintf(stderr,bla)
52#else
53#define DPRINTF(bla...)
54#endif*/
55
56#define DPRINTF(bla...) { if(debug_flag) fprintf(stderr,bla); }
57
58
59unsigned char debug_flag; /* switch: Debug an/aus? */
60size_t write_puncher(int fd, unsigned char buf);
61void visualize_byte(unsigned char buf);
62
63
64int mtime(long long since) {
65        /* gibt Millisekunden zurueck seit since. since sind dabei die
66           Millisekunden seit der Unix-Epoche. Ein initiales since kann
67           per mtime(0) gefunden werden. */
68        struct timeval time;
69        gettimeofday(&time, NULL);
70              // Sec*10^3
71        return (time.tv_sec * 1000 + (long long)(time.tv_usec / 1000)) - since;
72}
73
74int u_time(long long since) {
75        /* gibt Mikrosekunden zurueck seit since. since sind dabei die
76           Mikrosekunden seit der Unix-Epoche. Ein initiales since kann
77           per mtime(0) gefunden werden. */
78        struct timeval time;
79        gettimeofday(&time, NULL);
80              // Sec*10^6
81        return (time.tv_sec * 1000 * 1000 + time.tv_usec) - since;
82}
83
84
85int main(int argc, char **argv) {
86        int parport_fd;
87        int mode; /* IEEE1284_MODE_COMAT == compatibility mode */
88        long long time_since_beginning; // etwas lustige Zeitmessung
89        int x; // debug
90       
91        fprintf(stderr, "FER 201 Paper tape reader user space driver\n");
92        fprintf(stderr, "time ms |123.45678|  hex=dec\n");
93       
94        // Aufrufparameter analsyieren
95        debug_flag = 0;
96        opterr = 0;
97        int c;
98        while( (c = getopt(argc, argv, "dh")) != -1)
99            switch(c) {
100                case 'd':
101                    debug_flag = 1;
102                    break;
103                case 'h':
104                    fprintf(stderr, "Usage: program [-d] [-h]\n");
105                    return 0;
106                //default:
107            }
108
109        DPRINTF("opening device...\n");
110        parport_fd = open(PARPORT_DEVICE, O_RDWR);
111        if(parport_fd == -1) {
112                perror("opening device failed");
113                return 1;
114        }
115
116        /* Claim the port */
117        DPRINTF("claiming port...\n");
118        if(ioctl(parport_fd, PPCLAIM)) {
119                perror ("claiming port (PPCLAIM)");
120                close (parport_fd);
121                return 1;
122        }
123       
124        /*DPRINTF("Setting IEEE protocol..\n");
125        mode = IEEE1284_MODE_COMPAT;
126        if(ioctl(parport_fd, PPSETMODE, &mode)) {
127                perror("Setting PPSETMODE");
128                close(parport_fd);
129                return 1;
130        }*/
131
132        /* Go straight into compatibility mode: */
133        DPRINTF("Setting IEEE netogation...\n");
134        mode = IEEE1284_MODE_COMPAT; //BYTE; //COMPAT;
135        if(ioctl(parport_fd, PPNEGOT, &mode)) {
136                perror ("Setting compatibilty mode (PPNEGOT)");
137                close (parport_fd);
138                return 1;
139        }
140       
141        DPRINTF("Setting off data line drivers..\n");
142        mode = 1;
143        if(ioctl(parport_fd, PPDATADIR, &mode)) {
144                perror("Setting PPDATADIR");
145                close(parport_fd);
146                return 1;
147        }
148       
149        DPRINTF("Resetting reader...\n");
150        {
151                unsigned char mask = (PARPORT_CONTROL_STROBE|PARPORT_CONTROL_AUTOFD);
152                if(ioctl(parport_fd, PPWCONTROL, &mask))
153                        return -3;
154                usleep(20);
155        }
156       
157        /*
158        DPRINTF("Waiting for Puncher beeing ready for signals...\n");
159        {
160                unsigned char status;
161                if(ioctl(parport_fd, PPRSTATUS, &status)) return -1;
162                if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) {
163                        DPRINTF("Puncher is BUSY!\n");
164                        usleep(8000);
165                }
166        }
167        */
168
169        time_since_beginning = mtime(0);
170        for(x=0;;x++) {
171                unsigned char buf; /* the read-in-byte buffer */
172                int ret; /* multipurpose return value */
173
174                ret = read_byte(parport_fd, &buf);
175                if(ret < 0) {
176                        printf("read byte: %i!", ret);
177                        //perror("read byte");
178                        close(parport_fd);
179                        return 1;
180                }
181               
182                /* Visualisierung der Zeile */
183                fprintf(stderr, "%5ims ", (int)(mtime(time_since_beginning)));
184                visualize_byte(buf);
185                fprintf(stderr, " 0x%02x=%03i\n", buf, buf);
186               
187                // ausgeben auf STDOUT.
188                putchar((int)buf);
189                fflush(stdout); // kein buffern.
190               
191                usleep(10*1000);
192        }
193
194    DPRINTF("finished\n");
195    ioctl(parport_fd, PPRELEASE);
196    close(parport_fd);
197    return 0;
198}
199
200void visualize_byte(unsigned char buf) {
201        /* Zeichnet Lochstreifen-Byte (wie das Perl-Proggi) */
202        unsigned char against = 0x01;
203        unsigned char check;
204        int pos;
205       
206        fprintf(stderr, "|");
207        for(pos=0; pos < 8; pos++) {
208                if(pos == 3) /* Streifenfuehrung */
209                        fprintf(stderr, ".");
210                check = buf;
211                check >>= pos;
212               
213                if((check & against) == 0)
214                        fprintf(stderr, " "); /* bit nicht gesetzt */
215                else
216                        fprintf(stderr, "*"); /* bit gesetzt */
217        } /*for */
218        fprintf(stderr, "|");
219}
220
221int read_byte(int fd, unsigned char *byte) {
222        /**
223         * Der eigentliche, geraetespezifische Treiber befindet
224         * sich auch erst hier.
225         *
226         */
227        static unsigned char mask_strobe = (PARPORT_CONTROL_STROBE|PARPORT_CONTROL_INIT);
228        static unsigned char mask_null = (0x00);
229        unsigned char status;
230        long long time;
231        int x; // temporaer
232       
233        // erst mal warten, bis Schalter geschlossen ist.
234        if(ioctl(fd, PPRSTATUS, &status))
235                return -5;
236        if(!(status & PARPORT_STATUS_SELECT)) {
237                DPRINTF("Warte, bis Schalter geschlossen ist");
238                while(!(status & PARPORT_STATUS_SELECT)) {
239                        if(ioctl(fd, PPRSTATUS, &status))
240                                return -5;
241                        DPRINTF(".");
242                        sleep(1);
243                }
244        }
245
246        //DPRINTF("Strobe pulsed.\n");
247        if(ioctl(fd, PPWCONTROL, &mask_strobe))
248                return -3;
249        time = u_time(0);
250
251        // in den ersten 2ms passiert selten etwas
252        for(x=0;;) {
253                //DPRINTF("%5i. Signale: ", (int)(u_time(time)));
254                if(ioctl(fd, PPRSTATUS, &status))
255                        return -4;
256                if(!(status & PARPORT_STATUS_ACK)) {
257                        //DPRINTF("Lesesignal ");
258                        if(!x) {
259                                if(u_time(time) > 4*1000) {
260                                        DPRINTF("Lesesignal erst nach 4ms!\n");
261                                }
262                                ioctl(fd, PPRDATA, byte);
263                                ioctl(fd, PPWCONTROL, &mask_null);
264                                x++;
265                        }
266                } else if(u_time(time) > 9*1000) {
267                        DPRINTF("Lesesignal kommt nicht!\n");
268                        usleep(2);
269                }
270               
271                if(!(status & PARPORT_STATUS_BUSY)) {
272                        //DPRINTF("Busy ");
273                        if(u_time(time) > 10*1000) {
274                                break; // alles klar.
275                        }
276                } else if(u_time(time) > 90*1000) {
277                        DPRINTF("Busy missing nach 9ms!\n");
278                        DPRINTF("BEende.\n");
279                        exit(0);
280                }
281               
282                if(!(status & PARPORT_STATUS_SELECT))
283                        DPRINTF("Schalter offen! ");
284                //DPRINTF("\n");
285
286                if(0==1) {
287                        struct timespec a;
288                        a.tv_sec = 0;
289                        a.tv_nsec = 1000;
290                        nanosleep(&a, NULL);
291                }
292        }
293
294        // auf ACK = RS Lesesignal warten um Daten
295        // abzuholen.
296
297        /*
298        for(;;) {
299                ioctl(fd, PPRSTATUS, &status);
300                if((status & PARPORT_STATUS_ACK) == PARPORT_STATUS_ACK) {
301                        if(mtime(time) > 4) {
302                                DPRINTF("Waiting over 4ms for ACK!\n");
303                                sleep(2);
304                        } else {
305                                usleep(10);
306                        }
307                } else break;
308        }*/
309
310        // warten bis Busy verschwindet.
311        /*
312        for(;;) {
313                ioctl(fd, PPRSTATUS, &status);
314                if(status & PARPORT_STATUS_BUSY) {
315                        if(mtime(time) > 5) {
316                                DPRINTF("Still busy =(\n");
317                                break;
318                        } else
319                                usleep(10);
320                } else break;
321        }*/
322
323        return 0;
324}
325
326
327
Note: See TracBrowser for help on using the browser.
© 2008 - 2010 Sven Köppel • Some rights reserved
Powered by Trac
Expect where otherwise noted, content on this site is licensed under a Creative Commons 3.0 License