Line Printer Automation

Home Projects Research About

I have an Epson dot-marix printer, which I use for quickly and reliably printing large volumes of text-based information. It is pretty loud and it's annoying to feed the paper out a few centimeters once I'm done sending data. I have written some code that fixes these issues by allowing me to send data to it remotely (i.e. from a room where the printer won't obliterate my ears) and automatically feeding the paper out.

The two programs I've written can be taken advantage of using something like cat file.txt | nc 192.168.0.20 10000 on the client-side (to send file.txt to the device connected to the printer) and lpr-server 10000 | lpr-peek > /dev/lp0 on the server-side (to listen on port 10000, pass the data through lpr-peek, and write it to the printer at /dev/lp0

lpr-peek

lpr-peek is a C program takes in the data I want to print in stdin and outputs it to stdout. But the important thing is that, when no data has been received for some time, it sends the printer a control code to feed the paper out a few centimeters for easy tearing, and when data is received again, it sends the printer a control code to feed the paper back in. It also has some optional lines to switch the printer's font.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>

void feedOut(){
    
//printf("SIMULATED FEED OUT\n");
    printf
("\x1BJ\xD8\x1BJ\xD8\x1BJ\x6C");
    fflush
(stdout);
}
void feedIn(){
    
//printf("SIMULATED FEED IN\n");
    printf
("\x1Bj\xD8\x1Bj\xD8\x1Bj\x6C");
    fflush
(stdout);
}

int main(){

    
//set font to Roman:
    printf
("\ex1");
    printf
("\ek0");

    printf
("\n\n");
    feedIn
();
    
    
int linelength=80;
    
char buf[linelength+2];
    
int eof=0;
    
while(!eof){
        
pid_t pid=fork();
        
if(pid==0){ //child timer process
            sleep
(5);
            feedOut
();
            
exit(0);
        
}
        
else{
            eof
=!fgets(buf,sizeof(buf),stdin);
            buf
[strlen(buf)-1]='\n';
            
if(waitpid(pid, NULL, WNOHANG)<=0){
                kill
(pid, SIGKILL);
                waitpid
(pid, NULL, 0);
                
if(eof){
                    feedOut
();
                
}
            
}
            
else if (!eof){
                feedIn
();
                fflush
(stdout);
            
}
            
if(!eof) fputs(buf,stdout);
            fflush
(stdout);
        
}
    
}
    
}

Compiled binary: lpr-peek

Source: lpr-peek.c

Makefile: Makefile

lpr-server

lpr-server is a C program intended to be used on a device connected to a line printer. It just makes connections with clients and outputs the data to stdout.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

static void die(const char *s) { perror(s); exit(1); }

int main(int argc, char **argv){
    
    
if(argc != 2){
        fprintf
(stderr, "usage: %s <server-port>\n", argv[0]);
        
exit(1);
    
}

    
unsigned short port = atoi(argv[1]);

    
//START BOILERPLATE
    
int servsock;
    
if ((servsock = socket (AF_INET, SOCK_STREAM, 0)) < 0){
        
die("socket failed");
    
}
    
struct sockaddr_in servaddr;
    memset
(&servaddr, 0, sizeof(servaddr));
    servaddr
.sin_family = AF_INET;
    servaddr
.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr
.sin_port = htons(port);

    
if (bind(servsock, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
        
die("bind failed");

    
if (listen(servsock, 5 /* queue size for connection requests */ ) < 0)
        
die("listen failed");
    
    
int clntsock;
    
socklen_t clntlen;
    
struct sockaddr_in clntaddr;
    
while(1){
        
//fprintf(stderr, "waiting for client ... ");

        clntlen 
= sizeof(clntaddr);

        
if ((clntsock = accept(servsock,
                        
(struct sockaddr *) &clntaddr, &clntlen)) < 0)
            
die("accept failed");
        
//fprintf(stderr, "client ip: %s\n", inet_ntoa(clntaddr.sin_addr));
        
//END BOILERPLATE
        
        
char buf[1000];
        
int bytes=0;
        
while ((bytes = recv(clntsock, buf, sizeof(buf)-1, 0)) > 0) {
            
/*char *p=buf;
            while(*p++!='\n');
            *p='\0';*/

            buf
[bytes]='\0';
            fputs
(buf,stdout);
            fflush
(stdout);
        
}
        
if (bytes < 0) {
            fprintf
(stderr, "ERR: recv failed\n");
        
}
        close
(clntsock);


    
}

}

Compiled binary: lpr-server

Source: lpr-server.c

Makefile: Makefile