[34] | 1 | /** |
---|
| 2 | * Linux parallel port userspace driver (ppdev) for the |
---|
| 3 | * Nixdorf 0043/44 punch card reader with |
---|
| 4 | * buffer 0377.01 (8 bit encoding) |
---|
| 5 | * |
---|
| 6 | * Copyright (c) March 2009 Sven Koeppel |
---|
| 7 | * |
---|
| 8 | * This program is free software; you can redistribute |
---|
| 9 | * it and/or modify it under the terms of the GNU General |
---|
| 10 | * Public License as published by the Free Software |
---|
| 11 | * Foundation; either version 3 of the License, or (at |
---|
| 12 | * your option) any later version. |
---|
| 13 | * |
---|
| 14 | * This program is distributed in the hope that it will |
---|
| 15 | * be useful, but WITHOUT ANY WARRANTY; without even the |
---|
| 16 | * implied warranty of MERCHANTABILITY or FITNESS FOR A |
---|
| 17 | * PARTICULAR PURPOSE. See the GNU General Public License |
---|
| 18 | * for more details. |
---|
| 19 | * |
---|
| 20 | * You should have received a copy of the GNU General |
---|
| 21 | * Public License along with this program; if not, see |
---|
| 22 | * <http://www.gnu.org/licenses/>. |
---|
| 23 | * |
---|
| 24 | **/ |
---|
| 25 | |
---|
| 26 | #include <stdio.h> |
---|
| 27 | #include <unistd.h> |
---|
| 28 | #include <stdlib.h> |
---|
| 29 | #include <errno.h> |
---|
| 30 | #include <time.h> |
---|
| 31 | #include <fcntl.h> |
---|
| 32 | |
---|
| 33 | #include <sys/ioctl.h> |
---|
| 34 | #include <linux/ppdev.h> |
---|
| 35 | #include <linux/parport.h> |
---|
| 36 | |
---|
| 37 | #include <sys/time.h> |
---|
| 38 | #include <sys/select.h> |
---|
| 39 | |
---|
| 40 | #define PARPORT_DEVICE "/dev/parport0" |
---|
| 41 | |
---|
| 42 | int parport_fd; |
---|
| 43 | |
---|
| 44 | typedef enum { |
---|
| 45 | MAGNET_ON, |
---|
| 46 | MAGNET_OFF |
---|
| 47 | } magnet_status_t; |
---|
| 48 | |
---|
| 49 | void set_magnet(magnet_status_t target_status) { |
---|
| 50 | unsigned char mask = (target_status==MAGNET_OFF ? PARPORT_CONTROL_AUTOFD : 0x0); |
---|
| 51 | if(ioctl(parport_fd, PPWCONTROL, &mask)) { |
---|
| 52 | perror("Setting magnet status (control lines)"); |
---|
| 53 | exit(0); |
---|
| 54 | } |
---|
| 55 | } |
---|
| 56 | |
---|
| 57 | int mtime(long long since) { |
---|
| 58 | /* gibt Millisekunden zurueck seit since. since sind dabei die |
---|
| 59 | Millisekunden seit der Unix-Epoche. Ein initiales since kann |
---|
| 60 | per mtime(0) gefunden werden. */ |
---|
| 61 | struct timeval time; |
---|
| 62 | gettimeofday(&time, NULL); |
---|
| 63 | // Sec*10^3 |
---|
| 64 | return (time.tv_sec * 1000 + (long long)(time.tv_usec / 1000)) - since; |
---|
| 65 | } |
---|
| 66 | |
---|
| 67 | void print_bit(char* label, int pos, unsigned char byte) { |
---|
| 68 | int value = ((byte >> pos) & 0x01)==0 ? 0 : 1; |
---|
| 69 | if(label == NULL) |
---|
| 70 | printf("%i=%i ", pos, value); |
---|
| 71 | else |
---|
| 72 | printf("%s=%i ", label, value); |
---|
| 73 | } |
---|
| 74 | |
---|
| 75 | void simple_reading_program() { |
---|
| 76 | // this will never touch the magnet... |
---|
| 77 | long long abs_time = mtime(0); |
---|
| 78 | for(;;) { |
---|
| 79 | fflush(NULL); |
---|
| 80 | unsigned char data; |
---|
| 81 | unsigned char status; |
---|
| 82 | fd_set rfds; |
---|
| 83 | FD_ZERO (&rfds); |
---|
| 84 | FD_SET (parport_fd, &rfds); |
---|
| 85 | //printf("Waiting for interrupt...\n"); |
---|
| 86 | if (!select (parport_fd + 1, &rfds, NULL, NULL, NULL)) { |
---|
| 87 | /* Caught a signal? */ |
---|
| 88 | printf("Caught a signal..."); |
---|
| 89 | continue; |
---|
| 90 | } |
---|
| 91 | |
---|
| 92 | // we've got that interrupt |
---|
| 93 | // fetch current register values |
---|
| 94 | if(ioctl(parport_fd, PPRDATA, &data)) { |
---|
| 95 | perror("Interrupt data readout"); |
---|
| 96 | exit(1); |
---|
| 97 | } |
---|
| 98 | if(ioctl(parport_fd, PPRSTATUS, &status)) { |
---|
| 99 | perror("Status data readout"); |
---|
| 100 | exit(1); |
---|
| 101 | } |
---|
| 102 | |
---|
| 103 | // display status: |
---|
| 104 | printf("%i: ",(int)mtime(abs_time)); |
---|
| 105 | if(status & PARPORT_STATUS_SELECT) { |
---|
| 106 | |
---|
| 107 | printf("DATA: "); |
---|
| 108 | int pos; |
---|
| 109 | for(pos=0; pos<8; print_bit(NULL, pos++, data)); |
---|
| 110 | printf("| STATUS: "); |
---|
| 111 | print_bit("ERROR", 3, status); |
---|
| 112 | print_bit("SEL", 4, status); |
---|
| 113 | print_bit("PE", 5, status); |
---|
| 114 | print_bit("ACK", 6, status); |
---|
| 115 | print_bit("BUSY", 7, status); |
---|
| 116 | printf("\n"); |
---|
| 117 | |
---|
| 118 | } else { |
---|
| 119 | printf("no card.\n"); |
---|
| 120 | } |
---|
| 121 | |
---|
| 122 | // clear the interrupt |
---|
| 123 | unsigned char irqc; |
---|
| 124 | ioctl(parport_fd, PPCLRIRQ, &irqc); |
---|
| 125 | if(irqc > 1) |
---|
| 126 | printf("MISSED %d INTTERUPT%s!!!!!\n", irqc-1, irqc == 2 ? "S" : ""); |
---|
| 127 | } |
---|
| 128 | } // function |
---|
| 129 | |
---|
| 130 | void magnet_testing_program() { |
---|
| 131 | printf("Looping.\n"); |
---|
| 132 | |
---|
| 133 | int x = 10; |
---|
| 134 | //for(x=0; x<10; x++) { |
---|
| 135 | while(x > 0) { |
---|
| 136 | printf("m = Magnet, o = Magnet off, q = Quit\n> "); |
---|
| 137 | fflush(NULL); |
---|
| 138 | switch(getchar()) { |
---|
| 139 | case '\n': break; |
---|
| 140 | case 'm': |
---|
| 141 | printf("Magnet is ON!\n"); |
---|
| 142 | set_magnet(MAGNET_ON); break; |
---|
| 143 | case 'q': |
---|
| 144 | printf("Quitting\n"); |
---|
| 145 | x = -42; |
---|
| 146 | break; |
---|
| 147 | case 'o': |
---|
| 148 | default: |
---|
| 149 | printf("Magnet is OFF!\n"); |
---|
| 150 | set_magnet(MAGNET_OFF); |
---|
| 151 | } |
---|
| 152 | } |
---|
| 153 | } |
---|
| 154 | |
---|
| 155 | int main(int arvc, char** argv) { |
---|
| 156 | printf("opening device %s...\n", PARPORT_DEVICE); |
---|
| 157 | parport_fd = open(PARPORT_DEVICE, O_RDWR); |
---|
| 158 | if(parport_fd == -1) { |
---|
| 159 | perror("opening device failed"); |
---|
| 160 | return 1; |
---|
| 161 | } |
---|
| 162 | |
---|
| 163 | printf("claiming port...\n"); |
---|
| 164 | if(ioctl(parport_fd, PPCLAIM)) { |
---|
| 165 | perror("claiming port (PPCLAIM)"); |
---|
| 166 | return 1; |
---|
| 167 | } |
---|
| 168 | |
---|
| 169 | printf("setting compatibility mode...\n"); |
---|
| 170 | int mode = IEEE1284_MODE_COMPAT; //BYTE; //COMPAT; |
---|
| 171 | if(ioctl(parport_fd, PPNEGOT, &mode)) { |
---|
| 172 | perror("Setting compatibilty mode (PPNEGOT)"); |
---|
| 173 | return 1; |
---|
| 174 | } |
---|
| 175 | |
---|
| 176 | printf("Disabling data line drivers...\n"); |
---|
| 177 | mode = 1; |
---|
| 178 | if(ioctl(parport_fd, PPDATADIR, &mode)) { |
---|
| 179 | perror("Setting PPDATADIR"); |
---|
| 180 | return 1; |
---|
| 181 | } |
---|
| 182 | |
---|
| 183 | printf("Ready to start.\n"); |
---|
| 184 | printf("Setting up control mask\n"); |
---|
| 185 | |
---|
| 186 | set_magnet(MAGNET_OFF); |
---|
| 187 | //magnet_testing_program(); |
---|
| 188 | |
---|
| 189 | // now fetch interrupts and give out data at these times. |
---|
| 190 | // never use the magnet. |
---|
| 191 | simple_reading_program(); |
---|
| 192 | |
---|
| 193 | |
---|
| 194 | printf("Finished. Turning magnet off and quitting.\n"); |
---|
| 195 | set_magnet(MAGNET_OFF); |
---|
| 196 | return 0; |
---|
| 197 | } // main |
---|
| 198 | |
---|