source: projects/userspace-driver/puncher.c @ 3

Last change on this file since 3 was 1, checked in by sven, 12 years ago

Erstimport

File size: 11.2 KB
Line 
1/**
2 * FACIT 4070 Tape punch-75 CPS
3 * Linux parallel port userspace driver (ppdev)
4 *
5 * Reads bytes from stdin and transfers them to
6 * the puncher.
7 * Verbose output will be on stderr, standard on
8 * stdout.
9 *
10 * CHANGELOG:
11 *    Feb 2007  initially written
12 *    16.11.07  kleinigkeiten geaendert.
13 *    31.03.08  Endlich mal funktionsfaehig gemacht, ohne
14 *              unnoetigen Debugausgaben
15 * bis 06.04.08 Komplett umgeschrieben, sodass jetzt
16 *              der Zyklus nachempfunden wird, weil die
17 *              busy-Leitung sowieso tut, was sie will.
18 *              Ordentliche Ausgaben auf stdout, Debug
19 *              Flag (-d)
20 *
21 * Dieses Programm soll sich nur aufs Punchen beschraenken,
22 * eine luxerioesere Variante (mit Beschriftung, Nullbytes
23 * vorne dran) gibt es mit einem Perl-Tool.
24 *
25 *
26 **/
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <unistd.h>
31#include <fcntl.h> /* lowlevel io */
32#include <errno.h>
33#include <stdarg.h> /* var argument list */
34#include <math.h>
35
36#include <sys/ioctl.h> 
37#include <linux/ppdev.h>
38#include <linux/parport.h>
39
40#include <sys/time.h> //  debugging
41
42#define PARPORT_DEVICE "/dev/parport0"
43
44/*#ifdef DEBUG
45#define DPRINTF(bla...)  fprintf(stderr,bla)
46#else
47#define DPRINTF(bla...)
48#endif*/
49
50#define DPRINTF(bla...) { if(debug_flag) fprintf(stderr,bla); }
51
52
53unsigned char debug_flag; /* switch: Debug an/aus? */
54size_t write_puncher(int fd, unsigned char buf);
55void visualize_byte(unsigned char buf);
56void calculate_time(int already_punched_bytes, int estimated_punch_length, int mtime_since_beginning);
57
58
59int mtime(long long since) {
60        /* gibt millisekunden zurueck seit since. since sind dabei die
61           Millisekunden seit der Unix-Epoche. Ein initiales since kann
62           per mtime(0) gefunden werden. */
63        struct timeval time;
64        gettimeofday(&time, NULL);
65              // Sec*10^6
66        return (time.tv_sec * 1000000 + time.tv_usec) - since;
67}
68
69int main(int argc, char **argv) {
70        int parport_fd;
71        int mode; /* IEEE1284_MODE_COMAT == compatibility mode */
72        long long time_since_beginning; // etwas lustige Zeitmessung
73        int already_punched = 0; // Anzahl bereits gepunchte bytes
74        int estimated_data_length = 0; // per Schalter -l angegebbare Datenlaenge
75       
76        printf("FACIT 4070 Tape punch-75 CPS userspace driver\n");
77        printf("time ms |123.45678|  hex=dec status: =) punch successful / :-( still busy\n");
78       
79        // Aufrufparameter analsyieren
80        debug_flag = 0;
81        opterr = 0;
82        int c;
83        while( (c = getopt(argc, argv, "dhl:s:")) != -1)
84            switch(c) {
85                case 'd':
86                    debug_flag = 1;
87                    break;
88                case 'h':
89                    fprintf(stderr, "Usage: %s [-d] [-h] [-lNUM]\n"
90                      "  optional parameters:\n"
91                      "   -d   debug mode, print out verbose informations about signals\n"
92                      "        if not set, only normal verbosity will be printed out on\n"
93                      "        stdout, painting an ASCII paper tape which visualizes the\n"
94                      "        bytes (see above for the caption)\n\n"
95                      "   -h   display this help message\n\n"
96                      "   -s   same as -l\n"
97                      "   -l   sets the NUMBER OF BYTES which are expected on stdin.\n"
98                      "        with this information we can complete the status information\n"
99                      "        with useful informations about the estimated remaining time\n"
100                      "        to punch (useful for longer data)\n"
101                      "        example: cat 2k-data-file | %s -l2000\n",
102                      argv[0], argv[0]);
103                    return 0;
104                case 'l':
105                case 's':
106                    c = atoi(optarg);
107                    if( c > 0 ) {
108                        estimated_data_length = c;
109                        break;
110                    }
111                    printf("%s: data length must be a positive integer, like '123', not %s\n", argv[0], optarg);
112                case '?': break;
113            }
114
115        //DPRINTF("opening device...\n");
116        parport_fd = open(PARPORT_DEVICE, O_RDWR);
117        if(parport_fd == -1) {
118                perror("opening device failed");
119                return 1;
120        }
121
122        /* Claim the port */
123        //DPRINTF("claiming port...\n");
124        if(ioctl(parport_fd, PPCLAIM)) {
125                perror ("claiming port (PPCLAIM)");
126                close (parport_fd);
127                return 1;
128        }       
129
130        /* Go straight into compatibility mode: */
131        //DPRINTF("Setting compatibility mode...\n");
132        mode = IEEE1284_MODE_COMPAT;
133        if(ioctl(parport_fd, PPNEGOT, &mode)) {
134                perror ("Setting compatibilty mode (PPNEGOT)");
135                close (parport_fd);
136                return 1;
137        }
138       
139        DPRINTF("Waiting for Puncher beeing ready for signals...\n");
140        {
141                unsigned char status;
142                if(ioctl(parport_fd, PPRSTATUS, &status)) return -1;
143                if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) {
144                        DPRINTF("Puncher is BUSY!\n");
145                        usleep(8000);
146                }
147        }
148
149        /* The main loop (reading stdin and printing out) */
150        /* We will just read 1 byte at one time to handle
151         * it nicely... */
152        DPRINTF("Start reading from stdin...\n");
153        time_since_beginning = mtime(0);
154        for(;;) {
155                unsigned char buf; /* stdin 1 byte buffer */
156                size_t ret; /* multipurpose return value */
157
158                ret = read(0, &buf, 1); /* 1 byte from stdin */
159                if(ret < 0) {
160                        perror("read stdin");
161                        close(parport_fd);
162                        return 1;
163                }
164
165                if(ret == 0) {/* EOF, end of input, etc. */
166                        DPRINTF("stdin EOF\n");
167                        break;
168                }
169
170                /* Visualisierung der Zeile */
171                printf("%5ims ", (int)(mtime(time_since_beginning)/1000));
172                visualize_byte(buf);
173                printf(" 0x%02x=%03i ", buf, buf);
174                calculate_time(++already_punched, estimated_data_length, (int)(mtime(time_since_beginning)/1000));
175
176                /* und Ausdrucken */
177                ret = write_puncher(parport_fd, buf);
178                if(ret < 0) {
179                        perror("write puncher");
180                        close(parport_fd);
181                        return 1;
182                } else if(ret == 0) {
183                        printf("=)\n"); // Smiley freut sich
184                } else if(ret == 1) {
185                        printf(":-(\n"); // Smile traurig
186                }
187        } /* for stdin */
188   
189    DPRINTF("Transmission finished\n");
190    ioctl(parport_fd, PPRELEASE);
191    close(parport_fd);
192    return 0;
193}
194
195void visualize_byte(unsigned char buf) {
196        /* Zeichnet Lochstreifen-Byte (wie das Perl-Proggi) */
197        unsigned char against = 0x01;
198        unsigned char check;
199        int pos;
200       
201        printf("|");
202        for(pos=0; pos < 8; pos++) {
203                if(pos == 3) /* Streifenfuehrung */
204                        printf(".");
205                check = buf;
206                check >>= pos;
207               
208                if((check & against) == 0)
209                        printf(" "); /* bit nicht gesetzt */
210                else
211                        printf("*"); /* bit gesetzt */
212        } /*for */
213        printf("|");
214}
215
216void calculate_time(int already_punched_bytes, int estimated_punch_length, int mtime_since_beginning) {
217        /* In jeder Zeile berechnen, wie lange noch gepuncht wird,
218         * und ausgeben. Nur wenn Laenge per "-l" oder "-s" angegeben
219         * wird. In Bytes.
220         *
221         * Irgendwie ist der Berechnungsalgorithmus etwas schrottig und
222         * produziert in den ersten Sekunden nur Müll, aber ansonsten
223         * ist er ganz okay.
224         */
225        int percentage, remaining_sec = 0;
226         
227        if(!estimated_punch_length) return; // wenn es gar nicht abgegeben wurde
228       
229        //printf("%i %i ", already_punched_bytes, estimated_punch_length, mtime_since_beginning);
230       
231        percentage = (int)rint(((float)already_punched_bytes / (float)estimated_punch_length) * 100);
232        if(mtime_since_beginning != 0) // erst nach dem ersten Zyklus berechenbar
233            remaining_sec = (int)rint(((float)mtime_since_beginning / ((float)already_punched_bytes / (float)estimated_punch_length) - mtime_since_beginning)/1000);
234       
235        if(already_punched_bytes <= estimated_punch_length) {
236               printf("| %i%% (%i sec remaining)  ", percentage, remaining_sec);
237        }
238}
239
240size_t write_puncher(int fd, unsigned char buf) {
241        /* Der eigentliche, Geraetespezifische Treiber
242         * befindet sich erst in dieser Schreib-Funktion
243         *
244         * return: <0 => Fehler; ==0 => Alles perfekt; 1 => Am Ende noch busy
245         *
246         */
247        //DPRINTF("\n");
248        static unsigned char strobe_on = (PARPORT_CONTROL_STROBE);
249        static unsigned char null_mask = 0x00;
250        unsigned char status;
251        long long time;
252
253        /* (falls nötig) warten bis PR (Punch ready == busy) kommt */
254        /*for(;;) *///{
255        /*int x;
256        for(x=0;x<5;x++) {
257                if(ioctl(fd, PPRSTATUS, &status))
258                        return -1;
259
260                if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) {
261                        DPRINTF("Puncher ready to recieve (%x)\n", status);
262                        x=-1;
263                        break;
264                }
265                usleep(10);
266        }*/
267
268        /* Puncher hatte noch kein PR gesetzt. */
269        //if(x<0)
270          //      DPRINTF("Waited for Puncher ready (status=%x)... ", status);
271               
272                //usleep(8000);
273                /* 1/2 Sekunde ist fuer debugzwecke besser als die vorherigen 8000. */
274        //}
275
276        /* set data pins */
277        if(ioctl(fd, PPWDATA, &buf))
278                return -2;
279        time = mtime(0);
280
281        usleep(10); // take some time...
282       
283        /* "pulse" strobe ==> turn off strobe! (strange behaviour) */
284        if(ioctl(fd, PPWCONTROL, &null_mask))
285                return -3;
286        DPRINTF("data set; strobe pulsed...\n");
287
288        /* Puncher: PI (=strobe) minimum == 100us */
289        usleep(220); // DTL TRY
290        // was: 220 => wir gehen jetzt auf 2ms
291
292        /* check if Punch Ready has fallen */
293        if(ioctl(fd, PPRSTATUS, &status))
294            return -4;
295        // bringts ja eh nicht -- also lassen.
296
297        /*for(;;) {
298                if(ioctl(fd, PPRSTATUS, &status))
299                        return -4;
300                if((status & PARPORT_STATUS_BUSY) != PARPORT_STATUS_BUSY) {
301                        * it has not - quite bad, but we will continue *
302                        DPRINTF("ERROR: Punch Ready has NOT FALLEN (%x)\n",status);
303                        usleep(5*1000); // noch mal 5ms warten.
304                } else break;
305        }*/
306
307        /* end strobe + data pins */
308        DPRINTF("Control is %x. Ending data pins... ",status);
309        if(ioctl(fd, PPWDATA, &null_mask)) return -5;
310        DPRINTF("+ strobe... ");
311        if(ioctl(fd, PPWCONTROL, &strobe_on)) return -5;
312
313        /* wait untill Puncher is ready to success */
314        {
315                int wait = 40*1000-mtime(time); // war 13*1000
316                DPRINTF("\nWaiting for Puncher Ready (%i usec)...", wait);
317                if(wait>0) usleep(wait);
318        }
319       
320        if(ioctl(fd, PPRSTATUS, &status)) return -6;
321        if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) {
322                DPRINTF("Still busy (%x).\n", status);
323                return 1;
324        } else  {
325                DPRINTF("Finished successfully (%x)\n", status);
326                return 0;
327        }
328       
329       
330        //for(;;) {
331        /*
332                int x;
333                unsigned char status1,status2;
334                for(x=0;x<(100);x++) {
335                if(ioctl(fd, PPRSTATUS, &status1)) return -6;
336                usleep(15);
337                if(ioctl(fd, PPRSTATUS, &status2)) return -6;
338                if(status1 == status2) {
339                        //DPRINTF("%x=%x ",status1,status2);
340                        status = status2;
341
342                        if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) {
343                                DPRINTF("- Puncher finished successfully (%x)\n",status);
344                                return 0;
345                        }
346                }
347                usleep(10);
348                }//for
349
350                DPRINTF("Cycle passed. Still busy (%x/%x). Going on.\n",status1,status2);
351               
352                //usleep(10000); // 20ms was
353                /* Der Komplettintervall betraegt 13.33 Microsekunden -
354                 * 10ms ist vielleicht angemessen
355                 * */
356        //}
357        //return 0;
358} /* write_puncher */
Note: See TracBrowser for help on using the repository browser.
© 2008 - 2013 technikum29 • 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