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

Last change on this file since 9 was 9, checked in by sven, 16 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
RevLine 
[5]1/**
[8]2 * The Paper Tape Project -- Punching subsystem
3 * Linux backend implementation
4 *
[5]5 * FACIT 4070 Tape punch-75 CPS
6 * Linux parallel port userspace driver (ppdev)
7 *
[8]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.
[5]11 *
[8]12 * (c) 2008 Sven Köppel
[5]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
[8]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 */
[5]30#include <sys/ioctl.h> 
31#include <linux/ppdev.h>
32#include <linux/parport.h>
[8]33#include <sys/time.h> /*  debugging */
[5]34
[8]35int puncher_backend_mtime(long long since) {
[5]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
[8]45PuncherBackend* puncher_backend_new(int debug_flag) {
[5]46        int mode; /* IEEE1284_MODE_COMAT == compatibility mode */
[8]47        PuncherBackend* c = malloc(sizeof(PuncherBackend));
48        c->debug_flag = debug_flag;
49
[5]50        printf("FACIT 4070 Tape punch-75 CPS userspace driver\n");
[8]51        printf("Starting up...\n");
[5]52
[8]53        //PUNCHER_BACKEND_DPRINTF("opening device...\n");
54        c->parport_fd = open(PARPORT_DEVICE, O_RDWR);
55        if(c->parport_fd == -1) {
[5]56                perror("opening device failed");
[8]57                return NULL;
[5]58        }
59
60        /* Claim the port */
[8]61        //PUNCHER_BACKEND_DPRINTF("claiming port...\n");
62        if(ioctl(c->parport_fd, PPCLAIM)) {
[5]63                perror ("claiming port (PPCLAIM)");
[8]64                close (c->parport_fd);
65                return NULL;
66        }
[5]67
68        /* Go straight into compatibility mode: */
[8]69        //PUNCHER_BACKEND_DPRINTF("Setting compatibility mode...\n");
[5]70        mode = IEEE1284_MODE_COMPAT;
[8]71        if(ioctl(c->parport_fd, PPNEGOT, &mode)) {
[5]72                perror ("Setting compatibilty mode (PPNEGOT)");
[8]73                close (c->parport_fd);
74                return NULL;
[5]75        }
76       
[8]77        PUNCHER_BACKEND_DPRINTF("Waiting for Puncher beeing ready for signals...\n");
[5]78        {
79                unsigned char status;
[8]80                if(ioctl(c->parport_fd, PPRSTATUS, &status)) return NULL;
[5]81                if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) {
[8]82                        PUNCHER_BACKEND_DPRINTF("Puncher is BUSY!\n");
[5]83                        usleep(8000);
84                }
85        }
86
[8]87        PUNCHER_BACKEND_DPRINTF("Puncher ready.\n");
88        return c;
[5]89}
90
[8]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;
[9]98        PUNCHER_BACKEND_DPRINTF("Setting null mask to control pins (strobe,etc.)...\n");
[8]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;
[5]105}
106
[8]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;
[5]112        }
[8]113        close(c->parport_fd);
114        PUNCHER_BACKEND_DPRINTF("Goodbye from the parport.\n");
115        return 0;
[5]116}
117
[8]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         **/
[5]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) {
[8]141                        PUNCHER_BACKEND_DPRINTF("Puncher ready to recieve (%x)\n", status);
[5]142                        x=-1;
143                        break;
144                }
145                usleep(10);
146        }*/
147
148        /* Puncher hatte noch kein PR gesetzt. */
149        //if(x<0)
[8]150          //      PUNCHER_BACKEND_DPRINTF("Waited for Puncher ready (status=%x)... ", status);
[5]151               
152                //usleep(8000);
153                /* 1/2 Sekunde ist fuer debugzwecke besser als die vorherigen 8000. */
154        //}
155
156        /* set data pins */
[8]157        if(ioctl(c->parport_fd, PPWDATA, &buf))
[5]158                return -2;
[8]159        time = puncher_backend_mtime(0);
[5]160
161        usleep(10); // take some time...
162       
163        /* "pulse" strobe ==> turn off strobe! (strange behaviour) */
[8]164        if(ioctl(c->parport_fd, PPWCONTROL, &null_mask))
[5]165                return -3;
[8]166        PUNCHER_BACKEND_DPRINTF("data set; strobe pulsed...\n");
[5]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 */
[8]173        if(ioctl(c->parport_fd, PPRSTATUS, &status))
[5]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 *
[8]182                        PUNCHER_BACKEND_DPRINTF("ERROR: Punch Ready has NOT FALLEN (%x)\n",status);
[5]183                        usleep(5*1000); // noch mal 5ms warten.
184                } else break;
185        }*/
186
187        /* end strobe + data pins */
[8]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;
[5]192
193        /* wait untill Puncher is ready to success */
194        {
[8]195                int wait = 40*1000-puncher_backend_mtime(time); // war 13*1000
196                PUNCHER_BACKEND_DPRINTF("\nWaiting for Puncher Ready (%i usec)...", wait);
[5]197                if(wait>0) usleep(wait);
198        }
199       
[8]200        if(ioctl(c->parport_fd, PPRSTATUS, &status)) return -6;
[5]201        if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) {
[8]202                PUNCHER_BACKEND_DPRINTF("Still busy (%x).\n", status);
[5]203                return 1;
204        } else  {
[8]205                PUNCHER_BACKEND_DPRINTF("Finished successfully (%x)\n", status);
[5]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) {
[8]219                        //PUNCHER_BACKEND_DPRINTF("%x=%x ",status1,status2);
[5]220                        status = status2;
221
222                        if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) {
[8]223                                PUNCHER_BACKEND_DPRINTF("- Puncher finished successfully (%x)\n",status);
[5]224                                return 0;
225                        }
226                }
227                usleep(10);
228                }//for
229
[8]230                PUNCHER_BACKEND_DPRINTF("Cycle passed. Still busy (%x/%x). Going on.\n",status1,status2);
[5]231               
232                //usleep(10000); // 20ms was
[9]233                 * Der Komplettintervall betraegt 13.33 Microsekunden -
[5]234                 * 10ms ist vielleicht angemessen
235                 * */
236        //}
237        //return 0;
[8]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