Changeset 8 in projects
- Timestamp:
- Aug 28, 2008, 6:44:11 PM (16 years ago)
- Location:
- puncher
- Files:
-
- 3 added
- 2 moved
Legend:
- Unmodified
- Added
- Removed
-
puncher/backend.linux.c
r5 r8 1 1 /** 2 * The Paper Tape Project -- Punching subsystem 3 * Linux backend implementation 4 * 2 5 * FACIT 4070 Tape punch-75 CPS 3 6 * Linux parallel port userspace driver (ppdev) 4 7 * 5 * Reads bytes from stdin and transfers them to 6 * the puncher. 7 * Verbose output will be on stderr, standard on 8 * stdout. 9 * 10 * CHANGELOG: 11 * Feb 2007 initially written 12 * 16.11.07 kleinigkeiten geaendert. 13 * 31.03.08 Endlich mal funktionsfaehig gemacht, ohne 14 * unnoetigen Debugausgaben 15 * bis 06.04.08 Komplett umgeschrieben, sodass jetzt 16 * der Zyklus nachempfunden wird, weil die 17 * busy-Leitung sowieso tut, was sie will. 18 * Ordentliche Ausgaben auf stdout, Debug 19 * Flag (-d) 20 * 21 * Dieses Programm soll sich nur aufs Punchen beschraenken, 22 * eine luxerioesere Variante (mit Beschriftung, Nullbytes 23 * vorne dran) gibt es mit einem Perl-Tool. 24 * 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 25 13 * 26 14 **/ … … 34 22 #include <math.h> 35 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 */ 36 30 #include <sys/ioctl.h> 37 31 #include <linux/ppdev.h> 38 32 #include <linux/parport.h> 39 40 #include <sys/time.h> // debugging 41 42 #define PARPORT_DEVICE "/dev/parport0" 43 44 /*#ifdef DEBUG 45 #define DPRINTF(bla...) fprintf(stderr,bla) 46 #else 47 #define DPRINTF(bla...) 48 #endif*/ 49 50 #define DPRINTF(bla...) { if(debug_flag) fprintf(stderr,bla); } 51 52 53 unsigned char debug_flag; /* switch: Debug an/aus? */ 54 size_t write_puncher(int fd, unsigned char buf); 55 void visualize_byte(unsigned char buf); 56 void calculate_time(int already_punched_bytes, int estimated_punch_length, int mtime_since_beginning); 57 58 59 int mtime(long long since) { 33 #include <sys/time.h> /* debugging */ 34 35 int puncher_backend_mtime(long long since) { 60 36 /* gibt millisekunden zurueck seit since. since sind dabei die 61 37 Millisekunden seit der Unix-Epoche. Ein initiales since kann … … 67 43 } 68 44 69 int main(int argc, char **argv) { 70 int parport_fd; 45 PuncherBackend* puncher_backend_new(int debug_flag) { 71 46 int mode; /* IEEE1284_MODE_COMAT == compatibility mode */ 72 long long time_since_beginning; // etwas lustige Zeitmessung 73 int already_punched = 0; // Anzahl bereits gepunchte bytes 74 int estimated_data_length = 0; // per Schalter -l angegebbare Datenlaenge 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 } 75 76 76 printf("FACIT 4070 Tape punch-75 CPS userspace driver\n"); 77 printf("time ms |123.45678| hex=dec status: =) punch successful / :-( still busy\n"); 78 79 // Aufrufparameter analsyieren 80 debug_flag = 0; 81 opterr = 0; 82 int c; 83 while( (c = getopt(argc, argv, "dhl:s:")) != -1) 84 switch(c) { 85 case 'd': 86 debug_flag = 1; 87 break; 88 case 'h': 89 fprintf(stderr, "Usage: %s [-d] [-h] [-lNUM]\n" 90 " optional parameters:\n" 91 " -d debug mode, print out verbose informations about signals\n" 92 " if not set, only normal verbosity will be printed out on\n" 93 " stdout, painting an ASCII paper tape which visualizes the\n" 94 " bytes (see above for the caption)\n\n" 95 " -h display this help message\n\n" 96 " -s same as -l\n" 97 " -l sets the NUMBER OF BYTES which are expected on stdin.\n" 98 " with this information we can complete the status information\n" 99 " with useful informations about the estimated remaining time\n" 100 " to punch (useful for longer data)\n" 101 " example: cat 2k-data-file | %s -l2000\n", 102 argv[0], argv[0]); 103 return 0; 104 case 'l': 105 case 's': 106 c = atoi(optarg); 107 if( c > 0 ) { 108 estimated_data_length = c; 109 break; 110 } 111 printf("%s: data length must be a positive integer, like '123', not %s\n", argv[0], optarg); 112 case '?': break; 113 } 114 115 //DPRINTF("opening device...\n"); 116 parport_fd = open(PARPORT_DEVICE, O_RDWR); 117 if(parport_fd == -1) { 118 perror("opening device failed"); 119 return 1; 120 } 121 122 /* Claim the port */ 123 //DPRINTF("claiming port...\n"); 124 if(ioctl(parport_fd, PPCLAIM)) { 125 perror ("claiming port (PPCLAIM)"); 126 close (parport_fd); 127 return 1; 128 } 129 130 /* Go straight into compatibility mode: */ 131 //DPRINTF("Setting compatibility mode...\n"); 132 mode = IEEE1284_MODE_COMPAT; 133 if(ioctl(parport_fd, PPNEGOT, &mode)) { 134 perror ("Setting compatibilty mode (PPNEGOT)"); 135 close (parport_fd); 136 return 1; 137 } 138 139 DPRINTF("Waiting for Puncher beeing ready for signals...\n"); 77 PUNCHER_BACKEND_DPRINTF("Waiting for Puncher beeing ready for signals...\n"); 140 78 { 141 79 unsigned char status; 142 if(ioctl( parport_fd, PPRSTATUS, &status)) return -1;80 if(ioctl(c->parport_fd, PPRSTATUS, &status)) return NULL; 143 81 if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) { 144 DPRINTF("Puncher is BUSY!\n");82 PUNCHER_BACKEND_DPRINTF("Puncher is BUSY!\n"); 145 83 usleep(8000); 146 84 } 147 85 } 148 86 149 /* The main loop (reading stdin and printing out) */ 150 /* We will just read 1 byte at one time to handle 151 * it nicely... */ 152 DPRINTF("Start reading from stdin...\n"); 153 time_since_beginning = mtime(0); 154 for(;;) { 155 unsigned char buf; /* stdin 1 byte buffer */ 156 size_t ret; /* multipurpose return value */ 157 158 ret = read(0, &buf, 1); /* 1 byte from stdin */ 159 if(ret < 0) { 160 perror("read stdin"); 161 close(parport_fd); 162 return 1; 163 } 164 165 if(ret == 0) {/* EOF, end of input, etc. */ 166 DPRINTF("stdin EOF\n"); 167 break; 168 } 169 170 /* Visualisierung der Zeile */ 171 printf("%5ims ", (int)(mtime(time_since_beginning)/1000)); 172 visualize_byte(buf); 173 printf(" 0x%02x=%03i ", buf, buf); 174 calculate_time(++already_punched, estimated_data_length, (int)(mtime(time_since_beginning)/1000)); 175 176 /* und Ausdrucken */ 177 ret = write_puncher(parport_fd, buf); 178 if(ret < 0) { 179 perror("write puncher"); 180 close(parport_fd); 181 return 1; 182 } else if(ret == 0) { 183 printf("=)\n"); // Smiley freut sich 184 } else if(ret == 1) { 185 printf(":-(\n"); // Smile traurig 186 } 187 } /* for stdin */ 188 189 DPRINTF("Transmission finished\n"); 190 ioctl(parport_fd, PPRELEASE); 191 close(parport_fd); 192 return 0; 193 } 194 195 void visualize_byte(unsigned char buf) { 196 /* Zeichnet Lochstreifen-Byte (wie das Perl-Proggi) */ 197 unsigned char against = 0x01; 198 unsigned char check; 199 int pos; 200 201 printf("|"); 202 for(pos=0; pos < 8; pos++) { 203 if(pos == 3) /* Streifenfuehrung */ 204 printf("."); 205 check = buf; 206 check >>= pos; 207 208 if((check & against) == 0) 209 printf(" "); /* bit nicht gesetzt */ 210 else 211 printf("*"); /* bit gesetzt */ 212 } /*for */ 213 printf("|"); 214 } 215 216 void calculate_time(int already_punched_bytes, int estimated_punch_length, int mtime_since_beginning) { 217 /* In jeder Zeile berechnen, wie lange noch gepuncht wird, 218 * und ausgeben. Nur wenn Laenge per "-l" oder "-s" angegeben 219 * wird. In Bytes. 220 * 221 * Irgendwie ist der Berechnungsalgorithmus etwas schrottig und 222 * produziert in den ersten Sekunden nur Müll, aber ansonsten 223 * ist er ganz okay. 224 */ 225 int percentage, remaining_sec = 0; 226 227 if(!estimated_punch_length) return; // wenn es gar nicht abgegeben wurde 228 229 //printf("%i %i ", already_punched_bytes, estimated_punch_length, mtime_since_beginning); 230 231 percentage = (int)rint(((float)already_punched_bytes / (float)estimated_punch_length) * 100); 232 if(mtime_since_beginning != 0) // erst nach dem ersten Zyklus berechenbar 233 remaining_sec = (int)rint(((float)mtime_since_beginning / ((float)already_punched_bytes / (float)estimated_punch_length) - mtime_since_beginning)/1000); 234 235 if(already_punched_bytes <= estimated_punch_length) { 236 printf("| %i%% (%i sec remaining) ", percentage, remaining_sec); 237 } 238 } 239 240 size_t write_puncher(int fd, unsigned char buf) { 241 /* Der eigentliche, Geraetespezifische Treiber 242 * befindet sich erst in dieser Schreib-Funktion 243 * 244 * return: <0 => Fehler; ==0 => Alles perfekt; 1 => Am Ende noch busy 245 * 246 */ 247 //DPRINTF("\n"); 87 PUNCHER_BACKEND_DPRINTF("Puncher ready.\n"); 88 return c; 89 } 90 91 int 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 107 int 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 120 int 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 **/ 248 128 static unsigned char strobe_on = (PARPORT_CONTROL_STROBE); 249 129 static unsigned char null_mask = 0x00; … … 259 139 260 140 if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) { 261 DPRINTF("Puncher ready to recieve (%x)\n", status);141 PUNCHER_BACKEND_DPRINTF("Puncher ready to recieve (%x)\n", status); 262 142 x=-1; 263 143 break; … … 268 148 /* Puncher hatte noch kein PR gesetzt. */ 269 149 //if(x<0) 270 // DPRINTF("Waited for Puncher ready (status=%x)... ", status);150 // PUNCHER_BACKEND_DPRINTF("Waited for Puncher ready (status=%x)... ", status); 271 151 272 152 //usleep(8000); … … 275 155 276 156 /* set data pins */ 277 if(ioctl( fd, PPWDATA, &buf))157 if(ioctl(c->parport_fd, PPWDATA, &buf)) 278 158 return -2; 279 time = mtime(0);159 time = puncher_backend_mtime(0); 280 160 281 161 usleep(10); // take some time... 282 162 283 163 /* "pulse" strobe ==> turn off strobe! (strange behaviour) */ 284 if(ioctl( fd, PPWCONTROL, &null_mask))164 if(ioctl(c->parport_fd, PPWCONTROL, &null_mask)) 285 165 return -3; 286 DPRINTF("data set; strobe pulsed...\n");166 PUNCHER_BACKEND_DPRINTF("data set; strobe pulsed...\n"); 287 167 288 168 /* Puncher: PI (=strobe) minimum == 100us */ … … 291 171 292 172 /* check if Punch Ready has fallen */ 293 if(ioctl( fd, PPRSTATUS, &status))173 if(ioctl(c->parport_fd, PPRSTATUS, &status)) 294 174 return -4; 295 175 // bringts ja eh nicht -- also lassen. … … 300 180 if((status & PARPORT_STATUS_BUSY) != PARPORT_STATUS_BUSY) { 301 181 * it has not - quite bad, but we will continue * 302 DPRINTF("ERROR: Punch Ready has NOT FALLEN (%x)\n",status);182 PUNCHER_BACKEND_DPRINTF("ERROR: Punch Ready has NOT FALLEN (%x)\n",status); 303 183 usleep(5*1000); // noch mal 5ms warten. 304 184 } else break; … … 306 186 307 187 /* end strobe + data pins */ 308 DPRINTF("Control is %x. Ending data pins... ",status);309 if(ioctl( fd, PPWDATA, &null_mask)) return -5;310 DPRINTF("+ strobe... ");311 if(ioctl( fd, PPWCONTROL, &strobe_on)) return -5;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; 312 192 313 193 /* wait untill Puncher is ready to success */ 314 194 { 315 int wait = 40*1000- mtime(time); // war 13*1000316 DPRINTF("\nWaiting for Puncher Ready (%i usec)...", wait);195 int wait = 40*1000-puncher_backend_mtime(time); // war 13*1000 196 PUNCHER_BACKEND_DPRINTF("\nWaiting for Puncher Ready (%i usec)...", wait); 317 197 if(wait>0) usleep(wait); 318 198 } 319 199 320 if(ioctl( fd, PPRSTATUS, &status)) return -6;200 if(ioctl(c->parport_fd, PPRSTATUS, &status)) return -6; 321 201 if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) { 322 DPRINTF("Still busy (%x).\n", status);202 PUNCHER_BACKEND_DPRINTF("Still busy (%x).\n", status); 323 203 return 1; 324 204 } else { 325 DPRINTF("Finished successfully (%x)\n", status);205 PUNCHER_BACKEND_DPRINTF("Finished successfully (%x)\n", status); 326 206 return 0; 327 207 } … … 337 217 if(ioctl(fd, PPRSTATUS, &status2)) return -6; 338 218 if(status1 == status2) { 339 // DPRINTF("%x=%x ",status1,status2);219 //PUNCHER_BACKEND_DPRINTF("%x=%x ",status1,status2); 340 220 status = status2; 341 221 342 222 if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) { 343 DPRINTF("- Puncher finished successfully (%x)\n",status);223 PUNCHER_BACKEND_DPRINTF("- Puncher finished successfully (%x)\n",status); 344 224 return 0; 345 225 } … … 348 228 }//for 349 229 350 DPRINTF("Cycle passed. Still busy (%x/%x). Going on.\n",status1,status2);230 PUNCHER_BACKEND_DPRINTF("Cycle passed. Still busy (%x/%x). Going on.\n",status1,status2); 351 231 352 232 //usleep(10000); // 20ms was … … 356 236 //} 357 237 //return 0; 358 } /* write_puncher */ 238 } /* puncher_backend_write_byte */ 239 240 /* EOF. */ -
puncher/frontend.gtk.c
r5 r8 16 16 #include <math.h> 17 17 #include <stdlib.h> 18 #include "backend.h" 18 19 #include "../visualisator/gtkpapertape.h" 19 20 … … 24 25 25 26 /* The master structure... */ 26 struct my_frontend {27 struct puncher_frontend { 27 28 /* The state of our punching process */ 28 enum MY_PROGRESS_STATE {29 enum PUNCHER_FRONTEND_PROGRESS_STATE { 29 30 PROGRESS_RUNNING, 30 31 PROGRESS_PAUSED, … … 67 68 68 69 gboolean progress_update_time(); 69 void punch_byte(unsigned char byte); 70 71 void prepare_my_frontend(GtkWidget *window) { 72 /** 73 * This function will prepare the big struct my_frontend which is 70 71 void puncher_frontend_prepare(GtkWidget *window) { 72 /** 73 * This function will prepare the big struct puncher_frontend which is 74 74 * globally known as "d" 75 75 * … … 85 85 d.progress_bar = gtk_progress_bar_new(); 86 86 87 #define MY_FRONTEND_FAST_LABEL(a) { d.a = gtk_label_new("x"); \87 #define PUNCHER_FRONTEND_FAST_LABEL(a) { d.a = gtk_label_new("x"); \ 88 88 gtk_label_set_selectable(GTK_LABEL(d.a), TRUE); } 89 MY_FRONTEND_FAST_LABEL(progress_holes_total);90 MY_FRONTEND_FAST_LABEL(progress_holes_punched);91 MY_FRONTEND_FAST_LABEL(progress_holes_todo);92 MY_FRONTEND_FAST_LABEL(progress_total_time);93 MY_FRONTEND_FAST_LABEL(progress_estimated_time);94 MY_FRONTEND_FAST_LABEL(progress_elapsed_time);95 MY_FRONTEND_FAST_LABEL(progress_time_per_hole);96 MY_FRONTEND_FAST_LABEL(progress_frequency);89 PUNCHER_FRONTEND_FAST_LABEL(progress_holes_total); 90 PUNCHER_FRONTEND_FAST_LABEL(progress_holes_punched); 91 PUNCHER_FRONTEND_FAST_LABEL(progress_holes_todo); 92 PUNCHER_FRONTEND_FAST_LABEL(progress_total_time); 93 PUNCHER_FRONTEND_FAST_LABEL(progress_estimated_time); 94 PUNCHER_FRONTEND_FAST_LABEL(progress_elapsed_time); 95 PUNCHER_FRONTEND_FAST_LABEL(progress_time_per_hole); 96 PUNCHER_FRONTEND_FAST_LABEL(progress_frequency); 97 97 98 98 d.button_start = gtk_button_new_with_mnemonic(_("Punch!")); … … 111 111 } 112 112 113 void p rogress_set() {113 void puncher_frontend_progress_set() { 114 114 /** 115 115 * set information about holes … … 127 127 } 128 128 129 gboolean gui_puncher_start(GtkWidget *start_widget, gpointer nada) {129 gboolean puncher_frontend_puncher_start(GtkWidget *start_widget, gpointer nada) { 130 130 /** 131 131 * The callback for the "start punching" button. This will prepare … … 149 149 150 150 // start the punching loop 151 gui_punch();152 } 153 154 gboolean gui_punch() {151 puncher_frontend_punch_loop(); 152 } 153 154 gboolean puncher_frontend_punch_loop() { 155 155 /** 156 156 * The Punch main loop, as the gui drives it. … … 161 161 162 162 for(x = 0; x < d.length; x++) { 163 p rogress_set();164 p rogress_update_time();163 puncher_frontend_progress_set(); 164 puncher_frontend_progress_update_time(); 165 165 gtk_paper_tape_set_highlight(d.papertape, x, TRUE); // TRUE: Abhängig von Checkbox! 166 166 UPDATE_GTK_GUI; … … 173 173 } 174 174 175 void punch_byte(unsigned char byte) { 176 usleep(20*1000); 177 } 178 179 gboolean progress_update_time() { 175 gboolean puncher_frontend_progress_update_time() { 180 176 /** 181 177 * This does exactly what the low level function "calculate_time" does; … … 215 211 216 212 217 gboolean open_file_dialog(GtkWidget *menuitem, GtkPaperTape* papertape) {213 gboolean puncher_frontend_open_file_dialog(GtkWidget *menuitem, GtkPaperTape* papertape) { 218 214 /** 219 215 * displays an "open file" dialog which runs gtk_paper_tape_read_from_file() if success, … … 254 250 } // open_file_dialog 255 251 256 void quit_application(GtkWidget *window, gpointer *nada) { 252 void puncher_frontend_quit_application(GtkWidget *window, gpointer *nada) { 253 puncher_backend_finish(); 257 254 exit(0); 258 255 // on window close: manage punching interaction!! … … 267 264 gtk_window_set_default_size(GTK_WINDOW(window), 600, 600); 268 265 gtk_window_set_title(GTK_WINDOW(window), _("Papertape Puncher")); 269 g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK( quit_application), NULL);266 g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(puncher_frontend_quit_application), NULL); 270 267 271 268 // above-main-box generation (contains menubar + mainbox) 272 p repare_my_frontend(window);269 puncher_frontend_prepare(window); 273 270 widget = gtk_vbox_new(FALSE, 0); 274 271 gtk_container_add(GTK_CONTAINER(window), widget); … … 286 283 // Oeffnen 287 284 g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_OPEN)), 288 "activate", G_CALLBACK( open_file_dialog), d.papertape);285 "activate", G_CALLBACK(puncher_frontend_open_file_dialog), d.papertape); 289 286 fast_menu_seperator(menu); 290 287 gtk_paper_tape_menu_export(d.papertape, menu);
Note: See TracChangeset
for help on using the changeset viewer.