source: projects/puncher/backend.linux.c @ 8

Last change on this file since 8 was 8, checked in by sven, 11 years ago

Puncher subsystem development. The Linux and dummy backends should work right
now, the cli frontend should work, too. GTK frontend still in development.
Windows backend still... in preparation ;-)

-- Sven @ workstation

File size: 7.2 KB
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#define PUNCHER_BACKEND_DPRINTF(bla...) { if(c->debug_flag) fprintf(stderr,bla); }
27
28
29/* Linux specific header files */
30#include <sys/ioctl.h> 
31#include <linux/ppdev.h>
32#include <linux/parport.h>
33#include <sys/time.h> /*  debugging */
34
35int puncher_backend_mtime(long long since) {
36        /* gibt millisekunden zurueck seit since. since sind dabei die
37           Millisekunden seit der Unix-Epoche. Ein initiales since kann
38           per mtime(0) gefunden werden. */
39        struct timeval time;
40        gettimeofday(&time, NULL);
41              // Sec*10^6
42        return (time.tv_sec * 1000000 + time.tv_usec) - since;
43}
44
45PuncherBackend* puncher_backend_new(int debug_flag) {
46        int mode; /* IEEE1284_MODE_COMAT == compatibility mode */
47        PuncherBackend* c = malloc(sizeof(PuncherBackend));
48        c->debug_flag = debug_flag;
49
50        printf("FACIT 4070 Tape punch-75 CPS userspace driver\n");
51        printf("Starting up...\n");
52
53        //PUNCHER_BACKEND_DPRINTF("opening device...\n");
54        c->parport_fd = open(PARPORT_DEVICE, O_RDWR);
55        if(c->parport_fd == -1) {
56                perror("opening device failed");
57                return NULL;
58        }
59
60        /* Claim the port */
61        //PUNCHER_BACKEND_DPRINTF("claiming port...\n");
62        if(ioctl(c->parport_fd, PPCLAIM)) {
63                perror ("claiming port (PPCLAIM)");
64                close (c->parport_fd);
65                return NULL;
66        }
67
68        /* Go straight into compatibility mode: */
69        //PUNCHER_BACKEND_DPRINTF("Setting compatibility mode...\n");
70        mode = IEEE1284_MODE_COMPAT;
71        if(ioctl(c->parport_fd, PPNEGOT, &mode)) {
72                perror ("Setting compatibilty mode (PPNEGOT)");
73                close (c->parport_fd);
74                return NULL;
75        }
76       
77        PUNCHER_BACKEND_DPRINTF("Waiting for Puncher beeing ready for signals...\n");
78        {
79                unsigned char status;
80                if(ioctl(c->parport_fd, PPRSTATUS, &status)) return NULL;
81                if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) {
82                        PUNCHER_BACKEND_DPRINTF("Puncher is BUSY!\n");
83                        usleep(8000);
84                }
85        }
86
87        PUNCHER_BACKEND_DPRINTF("Puncher ready.\n");
88        return c;
89}
90
91int puncher_backend_emergency_stop(PuncherBackend* c) {
92        /**
93         * This method implements the setoff-strobe mechanism.
94         * It should be called whenever you want the puncher simply to
95         * *stop*.
96         **/
97        static unsigned char mask = PARPORT_CONTROL_STROBE;
98        DPRINTF("Setting null mask to control pins (strobe,etc.)...\n");
99        if(ioctl(c->parport_fd, PPWCONTROL, &mask)) {
100                perror("backend emergency exit: null mask");
101                close(c->parport_fd);
102                return 1;
103        }
104        return 0;
105}
106
107int puncher_backend_destroy(PuncherBackend* c) {
108        puncher_backend_emergency_stop(c); // stop it.
109        if(ioctl(c->parport_fd, PPRELEASE)) {
110                perror ("Releasing the parport");
111                return 1;
112        }
113        close(c->parport_fd);
114        PUNCHER_BACKEND_DPRINTF("Goodbye from the parport.\n");
115        return 0;
116}
117
118
119
120int puncher_backend_write_byte(PuncherBackend* c, unsigned char buf) {
121        /**
122         * This will write one byte on the puncher. Return
123         * values:
124         * r  < 0  => Failure Error (see errno)
125         * r == 0  => Perfect write, no error
126         * r == 1  => After writing still "busy" signal (continue, anywhere)
127         **/
128        static unsigned char strobe_on = (PARPORT_CONTROL_STROBE);
129        static unsigned char null_mask = 0x00;
130        unsigned char status;
131        long long time;
132
133        /* (falls nötig) warten bis PR (Punch ready == busy) kommt */
134        /*for(;;) *///{
135        /*int x;
136        for(x=0;x<5;x++) {
137                if(ioctl(fd, PPRSTATUS, &status))
138                        return -1;
139
140                if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) {
141                        PUNCHER_BACKEND_DPRINTF("Puncher ready to recieve (%x)\n", status);
142                        x=-1;
143                        break;
144                }
145                usleep(10);
146        }*/
147
148        /* Puncher hatte noch kein PR gesetzt. */
149        //if(x<0)
150          //      PUNCHER_BACKEND_DPRINTF("Waited for Puncher ready (status=%x)... ", status);
151               
152                //usleep(8000);
153                /* 1/2 Sekunde ist fuer debugzwecke besser als die vorherigen 8000. */
154        //}
155
156        /* set data pins */
157        if(ioctl(c->parport_fd, PPWDATA, &buf))
158                return -2;
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 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