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

Last change on this file since 9 was 9, checked in by sven, 11 years ago
  • Recreated Makefiles in visualisator/ and puncher/
  • All /visualisator/ sources now compile with -Wall compiler flag
  • The basic /puncher/ sources compile with -Wall, too.
  • Added Readme for schriften/

Current development is now focussed at /puncher/frontend.gtk.c.

-- 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        PUNCHER_BACKEND_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