/* */ /* Smith-Corona PCLabel printer (device is obsolete) */ /* Label printer pgm, uses text from files given as arguments */ /* Copyright One Vista Associates 1998-2007 */ /* Non-commercial use without fee permitted */ /* written by johna (modified Aug 2007) */ /* */ #include #include #include #include #include #include #include #include #include #include #include #define HAS6LINES #define USAGE "USAGE: %s [-n count] [-f font_family] [-p pointsize] labelfiles ...\n" // label size in bits #define LBLY 192 #define LBLX 640 #define VIS_LBL_LEN (LBLX-64) // site specific constants #define LBLBAUDRATE B19200 #define LBL_TTY "/dev/ttyUSB0" #define DEFAULT_FONT "Helvetica" #define DEFAULT_PTSIZE 22 #define TEMPFILE "/tmp/lblgs.out" #define STARTX 16 /* was 8 */ #define MAXBUF 1024 // GhostScript does the rendering #define GS_EXEC "/usr/bin/gs" #define GS_CMD0 "echo | " #define GS_CMD1 " -sDEVICE=bit -dNOPAUSE -sOutputFile=" #define GS_CMD2 " -r100 -g" #define GS_CMD3 " >" // printer specific constants #define OFFLINE 10001 #define PAPERJAM 10002 #define NOPAPER 10003 #ifdef HAS6LINES #define MAXLINE 6 #else #define MAXLINE 5 #endif char outline[MAXBUF]; char bm[LBLY][LBLX]; char control1[3] = {0x1B, 0x42, 0x40}; // 'ESC B' BaudRate ? char control2[3] = {0x1B, 0x53, 0x1C}; // 'ESC S' Setup ? char control3[3] = {0x1B, 0x52, 0x00}; // 'ESC R' Ready ? char control4[2] = {0x1B, 0x45}; // 'ESC E' Eject int tty = -1; // fd for label printer char *lbl_tty = LBL_TTY; // USB0 char *progname; struct termios oldsb, newsb; // keep tty info int print_lbl(char *filename, int count); char *dopixels(unsigned char x, char *q); int GetLabelText(char *infile, char *font, int ptsize, char *psf); void PrintOneLabel(char *labelfilename, int count, int ptsize, char *font); void Usage(); /*****************************************************************/ main(int argc, char **argv) { int count = 1; // number of copies int pointsize = DEFAULT_PTSIZE; // pointsize char our_font[128] = DEFAULT_FONT; // font family progname = argv[0]; argc--; argv++; if (argc == 0) Usage(); while (**argv == '-') { if (argc < 2) Usage(); switch(argv[0][1]) { case 'f': strcpy(our_font, argv[1]); break; case 'p': pointsize = atoi(argv[1]); break; case 'n': count = atoi(argv[1]); break; default: Usage(); } argc -= 2; argv += 2; if (argc == 0) Usage(); } while (argc > 0) { PrintOneLabel(*argv, count, pointsize, our_font); argc--; argv++; } exit(0); } /*****************************************************************/ void PrintOneLabel(char *labelfilename, int count, int ptsize, char *font) { int pid, fd, i, j, k; int colht; // column height in bytes int rowlen; // row length in bytes unsigned char x, pixels, *p; char *q, ibuf[2]; char psfin[64]; char psfout[64]; char printfilename[64]; char gserrs[64]; pid = getpid(); colht = LBLY / 8; rowlen = LBLX / 8; sprintf(psfin, "/tmp/lblpsin%d", pid); sprintf(psfout, "/tmp/lblpsout%d", pid); sprintf(gserrs, "/tmp/gserrs%d", pid); // build a PostScript file describing the label if (GetLabelText(labelfilename, font, ptsize, psfin)) return; // failed // build a bitmap using Ghostscript sprintf(outline, "%s%s%s%s%s%dx%d %s%s%s\n", GS_CMD0, GS_EXEC, GS_CMD1, psfout, GS_CMD2, LBLX, LBLY, psfin,GS_CMD3, gserrs); pclose(popen(outline, "r")); unlink(psfin); // remove the generated PostScript if (!fontOK(gserrs)) { fprintf(stderr, "See /usr/local/lib/labels/Fontlist for fontnames\n"); return; } // build bitmap by row from GhostScript output file fd = open(psfout, 0); for (i=(LBLY-1); i >= 0; i--) { q = bm[i]; for (j=0; j>= 1; } *p++ = pixels; // I don't know why this is here, // or what its for, but its required!!! // it might be needed every 16 vertical bytes!! // only 7 works for me, everything else locks up the printer // printer lockup requires plug-pulling to reset it // // setting colht to 15 and outline[0-3] to 0x1b 0x50 0x15 0x11 // and appending 0 0xf7 0 // prints the lower half of a label if ((j % 16) == 15) { // 16 bytes written? *p++ = 7; // insert extra byte (length-1 of rem?) } } *p++ = 0xff; // unknown?? (required; maybe EOT mark) *p = 0; // 8 pixels of white at top write(fd, outline, colht + 9); } write(fd, control4, 2); // add Eject command close(fd); // print the label while (i = print_lbl(printfilename, count)) { if (i < OFFLINE) { // remaining count iff small integer count = i; continue; } switch(i) { case OFFLINE: p = "Label Printer is off-line."; break; case PAPERJAM: p = "Label Printer has a paper jam."; break; case NOPAPER: p = "Label Printer is out of paper."; break; default: p = "Unknown Label Printer status."; break; } fprintf(stderr, "%s\nPress when ready", p); read(0, outline, 1); } unlink(printfilename); // remove the evidence } /*****************************************************************/ void Usage() { fprintf(stderr, USAGE, progname); exit(1); } /*****************************************************************/ int GetLabelText(char *infile, char *font, int ptsize, char *psf) { int i, fd, lines=0; int len, y; char *mem, *p, *q; char *line[MAXLINE+1]; // pointers to label lines int linelen[MAXLINE+1]; // lengths of lines char buf[128]; struct stat st; fd = stat(infile, &st); if (fd < 0) { fprintf(stderr, "Can't stat %s (%s)\n", infile, strerror(errno)); return 1; } fd = open(infile, O_RDONLY); if (fd == -1) { fprintf(stderr, "Can't open %s for reading (%s)\n", infile, strerror(errno)); return 1; } mem = (char *)malloc(st.st_size + 1); if (!mem) { fprintf(stderr, "Can't get memory for %s\n",infile); exit(1); } if (read(fd, mem, st.st_size) != st.st_size) { fprintf(stderr, "Can't read %s (%s)\n", infile, strerror(errno)); close(fd); return 1; } close(fd); q = mem; if ((q[0] == '%') && (q[1] == '!')) { // its a PostScript file! fd = open(psf, O_RDWR|O_TRUNC|O_CREAT,0666); write(fd, mem, st.st_size); // copy it write(fd, "\n", 1); // add trailing linefeed close(fd); return 0; // we're done } mem[st.st_size] = 0; if (q[0] == '#') { // line contains a font and pointsize spec q++; p = font; while (*q && (*q != ';')) *p++ = *q++; *p = *q++ = 0; p = q; while (*q && (*q != '\n')) q++; ptsize = atoi(p); *q++ = 0; } for (i=0; i MAXLINE) { fprintf(stderr,"Too many text lines for label\n"); return 1; } } q++; } // attempt to center lines vertically if (ptsize <= 22) { switch (--lines) { case 1: line[2] = line[0]; line[0] = " "; line[1] = " "; line[3] = " "; line[4] = " "; break; case 2: line[2] = line[1]; line[1] = line[0]; line[0] = " "; line[3] = " "; line[4] = " "; break; case 3: line[3] = line[2]; line[2] = line[1]; line[1] = line[0]; line[0] = " "; line[4] = " "; break; case 4: line[4] = " "; break; #ifdef HAS6LINES case 5: line[5] = " "; break; #endif } } for (i=0; i 22) y = 139 - ptsize; len = sprintf(buf, "%d %3d moveto\n", STARTX, y); write(fd, buf, len); write(fd, "(", 1); write(fd, line[0], linelen[0]); write(fd, ") show\n", 7); y -= ptsize + 4; len = sprintf(buf, "%d %3d moveto\n", STARTX, y); write(fd, buf, len); write(fd, "(", 1); write(fd, line[1], linelen[1]); write(fd, ") show\n", 7); y -= ptsize + 4; len = sprintf(buf, "%d %3d moveto\n", STARTX, y); write(fd, buf, len); write(fd, "(", 1); write(fd, line[2], linelen[2]); write(fd, ") show\n", 7); y -= ptsize + 4; len = sprintf(buf, "%d %3d moveto\n", STARTX, y); write(fd, buf, len); write(fd, "(", 1); write(fd, line[3], linelen[3]); write(fd, ") show\n", 7); y -= ptsize + 4; len = sprintf(buf, "%d %3d moveto\n", STARTX, y); write(fd, buf, len); write(fd, "(", 1); write(fd, line[4], linelen[4]); write(fd, ") show\n", 7); #ifdef HAS6LINES y -= ptsize + 4; len = sprintf(buf, "%d %3d moveto\n", STARTX, y); write(fd, buf, len); write(fd, "(", 1); write(fd, line[5], linelen[5]); write(fd, ") show\n", 7); #endif write(fd, "showpage\n", 9); close(fd); free(mem); return 0; } /*****************************************************************/ char *dopixels(unsigned char x, char *q) { int j; for (j=0; j<8; j++) { if (x & 0x80) *q++ = 1; // black else *q++ = 0; // white x <<= 1; } return q; } /**************************************************************************/ int print_lbl(char *filename, int count) { int j, fd, size; unsigned char ibuf[MAXBUF]; setup_tty(LBLBAUDRATE); fd = open(filename, O_RDONLY); for (j=0; j<3; j++) { // send BaudRate command read(fd, ibuf, 1); write(tty, ibuf, 1); } for (j=0; j<4; j++) { // wait for 4 byte status read(tty, &ibuf[j], 1); } if ((ibuf[2] & 1) == 0) return OFFLINE; if ((ibuf[2] & 2) == 0) return NOPAPER; if ((ibuf[2] & 4) == 0) return PAPERJAM; for (j=0; j<3; j++) { // send Setup command read(fd, ibuf, 1); write(tty, ibuf, 1); } read(tty,ibuf,4); // wait for 4 byte status for (j=0; j<3; j++) { // send Ready command read(fd, ibuf, 1); write(tty, ibuf, 1); } while ((size = read(fd, ibuf, MAXBUF)) > 0) { // send the data write(tty, ibuf, size); } sleep(1); // need this delay for printer restore_tty(); return --count; } /**************************************************************************/ setup_tty(int baud) { int s; tty = open(lbl_tty, O_RDWR); if (tty < 0) { fprintf(stderr,"can't open tty line (%s)\n", strerror(errno)); exit(1); } s = tcgetattr(tty, &oldsb); if (s < 0) { perror("ttopen tcgetattr"); exit(1); } newsb = oldsb; /* no output flags at all */ newsb.c_oflag = 0; /* no line flags at all */ newsb.c_lflag = 0; /* disable parity, both in and out */ newsb.c_cflag &= ~PARENB; /* one stop bit on transmit */ /* no modem control, 8bit chars, */ /* receiver enabled, */ newsb.c_cflag |= CLOCAL|CS8|CREAD; /* XON/XOFF, ignore break, ignore parity errors */ newsb.c_iflag = IXON | IGNBRK | IGNPAR; newsb.c_cc[VMIN] = 1; newsb.c_cc[VTIME] = 0; newsb.c_cc[VSUSP] = 0; s = cfsetospeed (&newsb, baud); if (s < 0) { perror("ttopen cfsetospeed"); exit(1); } s = cfsetispeed (&newsb, baud); if (s < 0) { perror("ttopen cfsetispeed"); exit(1); } s = tcsetattr(tty, TCSAFLUSH, &newsb); if (s < 0) { perror("ttopen tcsetattr"); exit(1); } } /***************************************************************************/ int fontOK(char *gs_error_file) { FILE *fildes; char buf[MAXBUF]; fildes = fopen(gs_error_file, "r"); unlink(gs_error_file); while (fgets(buf, MAXBUF, fildes)) { if (!strncmp("Can't find ", buf, 11)) { fprintf(stderr, buf); fclose(fildes); return 0; } } fclose(fildes); return 1; // success } /***************************************************************************/ restore_tty() { tcsetattr(tty, TCSADRAIN, &oldsb); close(tty); tty = -1; } /**************************************************************************/