root/paper-tape-project/trunk/puncher/backend.linux.c

Revision 25, 7.2 kB (checked in by sven, 3 years ago)

Clean up of repository before renaming the whole project
to

old media project

since we will shortly add punch card support to the whole
project.

-- sven @ workstation

Line 
1/**
2 * The Paper Tape Project -- Punching subsystem
3 * Linux backend implementation
4 *
5 * FACIT 4070 Tape punch-75 CPS
6 * Linux parallel port userspace driver (ppdev)
7 *
8 * This driver assumes the Linux kernel module "ppdev"
9 * being loaded and PARPORT_DEVICE (see symbol below)
10 * being writable for the current UID.
11 *
12 * (c) 2008 Sven Köppel
13 *
14 **/
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <unistd.h>
19#include <fcntl.h> /* lowlevel io */
20#include <errno.h>
21#include <stdarg.h> /* var argument list */
22#include <math.h>
23
24#include "backend.h"
25#define PARPORT_DEVICE "/dev/parport0"
26
27
28/* Linux specific header files */
29#include <sys/ioctl.h> 
30#include <linux/ppdev.h>
31#include <linux/parport.h>
32#include <sys/time.h> /*  debugging */
33
34int puncher_backend_mtime(long long since) {
35        /* gibt millisekunden zurueck seit since. since sind dabei die
36           Millisekunden seit der Unix-Epoche. Ein initiales since kann
37           per mtime(0) gefunden werden. */
38        struct timeval time;
39        gettimeofday(&time, NULL);
40              // Sec*10^6
41        return (time.tv_sec * 1000000 + time.tv_usec) - since;
42}
43
44PuncherBackend* puncher_backend_new(int debug_flag) {
45        int mode; /* IEEE1284_MODE_COMAT == compatibility mode */
46        PuncherBackend* c = malloc(sizeof(PuncherBackend));
47        c->debug_flag = debug_flag;
48
49        printf("FACIT 4070 Tape punch-75 CPS userspace driver\n");
50        printf("Starting up...\n");
51
52        //PUNCHER_BACKEND_DPRINTF("opening device...\n");
53        c->parport_fd = open(PARPORT_DEVICE, O_RDWR);
54        if(c->parport_fd == -1) {
55                perror("opening device failed");
56                return NULL;
57        }
58
59        /* Claim the port */
60        //PUNCHER_BACKEND_DPRINTF("claiming port...\n");
61        if(ioctl(c->parport_fd, PPCLAIM)) {
62                perror ("claiming port (PPCLAIM)");
63                close (c->parport_fd);
64                return NULL;
65        }
66
67        /* Go straight into compatibility mode: */
68        //PUNCHER_BACKEND_DPRINTF("Setting compatibility mode...\n");
69        mode = IEEE1284_MODE_COMPAT;
70        if(ioctl(c->parport_fd, PPNEGOT, &mode)) {
71                perror ("Setting compatibilty mode (PPNEGOT)");
72                close (c->parport_fd);
73                return NULL;
74        }
75       
76        PUNCHER_BACKEND_DPRINTF("Waiting for Puncher beeing ready for signals...\n");
77        {
78                unsigned char status;
79                if(ioctl(c->parport_fd, PPRSTATUS, &status)) return NULL;
80                if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) {
81                        PUNCHER_BACKEND_DPRINTF("Puncher is BUSY!\n");
82                        usleep(8000);
83                }
84        }
85
86        PUNCHER_BACKEND_DPRINTF("Puncher ready.\n");
87        return c;
88}
89
90int puncher_backend_emergency_stop(PuncherBackend* c) {
91        /**
92         * This method implements the setoff-strobe mechanism.
93         * It should be called whenever you want the puncher simply to
94         * *stop*.
95         **/
96        static unsigned char mask = PARPORT_CONTROL_STROBE;
97        PUNCHER_BACKEND_DPRINTF("Setting null mask to control pins (strobe,etc.)...\n");
98        if(ioctl(c->parport_fd, PPWCONTROL, &mask)) {
99                perror("backend emergency exit: null mask");
100                close(c->parport_fd);
101                return 1;
102        }
103        return 0;
104}
105
106int puncher_backend_destroy(PuncherBackend* c) {
107        puncher_backend_emergency_stop(c); // stop it.
108        if(ioctl(c->parport_fd, PPRELEASE)) {
109                perror ("Releasing the parport");
110                return 1;
111        }
112        close(c->parport_fd);
113        PUNCHER_BACKEND_DPRINTF("Goodbye from the parport.\n");
114        return 0;
115}
116
117
118
119int puncher_backend_write_byte(PuncherBackend* c, unsigned char buf) {
120        /**
121         * This will write one byte on the puncher. Return
122         * values:
123         * r  < 0  => Failure Error (see errno)
124         * r == 0  => Perfect write, no error
125         * r == 1  => After writing still "busy" signal (continue, anywhere)
126         **/
127        static unsigned char strobe_on = (PARPORT_CONTROL_STROBE);
128        static unsigned char null_mask = 0x00;
129        unsigned char status;
130        long long time;
131
132        /* (falls nötig) warten bis PR (Punch ready == busy) kommt */
133        /*for(;;) *///{
134        /*int x;
135        for(x=0;x<5;x++) {
136                if(ioctl(fd, PPRSTATUS, &status))
137                        return -1;
138
139                if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) {
140                        PUNCHER_BACKEND_DPRINTF("Puncher ready to recieve (%x)\n", status);
141                        x=-1;
142                        break;
143                }
144                usleep(10);
145        }*/
146
147        /* Puncher hatte noch kein PR gesetzt. */
148        //if(x<0)
149          //      PUNCHER_BACKEND_DPRINTF("Waited for Puncher ready (status=%x)... ", status);
150               
151                //usleep(8000);
152                /* 1/2 Sekunde ist fuer debugzwecke besser als die vorherigen 8000. */
153        //}
154
155        /* set data pins */
156        if(ioctl(c->parport_fd, PPWDATA, &buf))
157                return -2;
158
159    time = puncher_backend_mtime(0);
160
161        usleep(10); // take some time...
162       
163        /* "pulse" strobe ==> turn off strobe! (strange behaviour) */
164        if(ioctl(c->parport_fd, PPWCONTROL, &null_mask))
165                return -3;
166        PUNCHER_BACKEND_DPRINTF("data set; strobe pulsed...\n");
167
168        /* Puncher: PI (=strobe) minimum == 100us */
169        usleep(220); // DTL TRY
170        // was: 220 => wir gehen jetzt auf 2ms
171
172        /* check if Punch Ready has fallen */
173        if(ioctl(c->parport_fd, PPRSTATUS, &status))
174            return -4;
175        // bringts ja eh nicht -- also lassen.
176
177        /*for(;;) {
178                if(ioctl(fd, PPRSTATUS, &status))
179                        return -4;
180                if((status & PARPORT_STATUS_BUSY) != PARPORT_STATUS_BUSY) {
181                        * it has not - quite bad, but we will continue *
182                        PUNCHER_BACKEND_DPRINTF("ERROR: Punch Ready has NOT FALLEN (%x)\n",status);
183                        usleep(5*1000); // noch mal 5ms warten.
184                } else break;
185        }*/
186
187        /* end strobe + data pins */
188        PUNCHER_BACKEND_DPRINTF("Control is %x. Ending data pins... ",status);
189        if(ioctl(c->parport_fd, PPWDATA, &null_mask)) return -5;
190        PUNCHER_BACKEND_DPRINTF("+ strobe... ");
191        if(ioctl(c->parport_fd, PPWCONTROL, &strobe_on)) return -5;
192
193        /* wait untill Puncher is ready to success */
194        {
195                int wait = 40*1000-puncher_backend_mtime(time); // war 13*1000
196                PUNCHER_BACKEND_DPRINTF("\nWaiting for Puncher Ready (%i usec)...", wait);
197                if(wait>0) usleep(wait);
198        }
199       
200        if(ioctl(c->parport_fd, PPRSTATUS, &status)) return -6;
201        if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) {
202                PUNCHER_BACKEND_DPRINTF("Still busy (%x).\n", status);
203                return 1;
204        } else  {
205                PUNCHER_BACKEND_DPRINTF("Finished successfully (%x)\n", status);
206                return 0;
207        }
208       
209       
210        //for(;;) {
211        /*
212                int x;
213                unsigned char status1,status2;
214                for(x=0;x<(100);x++) {
215                if(ioctl(fd, PPRSTATUS, &status1)) return -6;
216                usleep(15);
217                if(ioctl(fd, PPRSTATUS, &status2)) return -6;
218                if(status1 == status2) {
219                        //PUNCHER_BACKEND_DPRINTF("%x=%x ",status1,status2);
220                        status = status2;
221
222                        if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) {
223                                PUNCHER_BACKEND_DPRINTF("- Puncher finished successfully (%x)\n",status);
224                                return 0;
225                        }
226                }
227                usleep(10);
228                }//for
229
230                PUNCHER_BACKEND_DPRINTF("Cycle passed. Still busy (%x/%x). Going on.\n",status1,status2);
231               
232                //usleep(10000); // 20ms was
233                 * Der Komplettintervall betraegt 13.33 Microsekunden -
234                 * 10ms ist vielleicht angemessen
235                 * */
236        //}
237        //return 0;
238} /* puncher_backend_write_byte */
239
240/* EOF. */
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