Logo Search packages:      
Sourcecode: c2esp version File versions  Download package

command2esp.c

/*
 *
 *   Kodak ESP command filter for CUPS.
 *
 *   Copyright 2011 by P.Newall.
 *
 * Contents:
 *
 *   main() - Main entry and command processing.
 */

/* filter must implement the following:
Exchange for test page
Maintenance=002?
0096, OK, Maintenance Started;

Exchange for alignment
Maintenance=006?
0096, OK, Maintenance Started;

Exchange for clean
Maintenance=003?
0096, OK, Maintenance Started;
*/

#define DEBUGFILES 0 /* DEBUGFILES 1 creates files in /tmp to help debug */
#define TESTING 0 /* TESTING 1 suppresses output to the printer to help debug */

/*
 * Include necessary headers...
 */

#include <cups/cups.h>
#include <cups/driver.h> 
#include <cups/sidechannel.h> //FlushBackChannel, and the side channel functions and constants
#include "string.h"
#include <ctype.h> 
#include <fcntl.h> //files
#include <time.h> //time functions used for debugging
#include <sys/stat.h> //chmod

time_t            StartTime;
FILE        *LogFile = NULL; //file descriptor for log file
FILE        *PrintFile = NULL; //file descriptor for debug file
char        BackBuf[32000]; //for the back channel replies from the printer
int         BackBufLen=sizeof(BackBuf)-1,
            DoBack=1;               /* Enables the back channel comms */ 

/* void
HandleReply()
{
      int BytesRead, i;
      char BackBuf[60], Display[60];
      int BackBufLen=60;
      float ReplyTime=2.0;

      fflush(stdout); //force a packet to the printer so it can reply
      sleep(30); //to allow time for reply
      BytesRead = cupsBackChannelRead(BackBuf, BackBufLen, ReplyTime); //read the reply from printer
      if(BytesRead >= 1) BackBuf[BytesRead]=0; //add null terminator NB BytesRead==-1 if nothing read
      for(i=0;i<59;++i) Display[i] = BackBuf[i]; //copy the first 39 chars to Display
      Display[59] = 0; //add null terminator
      fprintf(stderr, "INFO: c2esp: Got %d byte reply = %s\n", BytesRead, Display);
}
*/

/* DoLog used during development */
void DoLog(char *PrintFormat, int I1, int I2)
{
      //prints a line with 2 integers to the log file
      if (LogFile == NULL)
            return;
char LogFormat[100];
      strcpy(LogFormat, "%d : ");
      strcat(LogFormat,PrintFormat);
      fprintf(LogFile, LogFormat, time(NULL)-StartTime, I1, I2);
}

void DoLogString(char *PrintFormat, char *String)
{
      //prints a line with a string to the log file
      if (LogFile == NULL)
            return;
char LogFormat[100];
      strcpy(LogFormat, "%d : ");
      strcat(LogFormat,PrintFormat);
      fprintf(LogFile, LogFormat, time(NULL)-StartTime, String);
}


/* GoodExchange sends a command gets reply from the printer on the back channel and compares it with the expected reply
      It returns the number of bytes read if the reply was the one expected, 
      otherwise 0 if the reply did not match Expect, or -1 if there was no reply */
int GoodExchange(char *Command, char *Expect, int DoBack, char *BackBuf, int BackBufLen, unsigned int SleepTime, float ReplyTime)
{
      int BytesRead = 0; //int because cupsBackChannel can return -1
      char Display[60];
      int i;

      fprintf(stderr, "c2esp: Sent command = %s\n", Command);
      DoLogString("Sent command = %s\n", Command);
      if(PrintFile) fprintf(PrintFile, "%s", Command); //to the global print file
#if TESTING == 0
      fprintf(stdout, "%s", Command); //printer command
#endif
      fflush(stdout); //force a packet to the printer so it can reply
      sleep(SleepTime); //give it a chance to reply before trying to read the reply (may not be needed)

      if(DoBack)
      {
      BytesRead = cupsBackChannelRead(BackBuf, BackBufLen, ReplyTime); //read the reply from printer
      if(BytesRead >= 1) BackBuf[BytesRead]=0; //add null terminator NB BytesRead==-1 if nothing read
      for(i=0;i<59;++i) Display[i] = BackBuf[i]; //copy the first 39 chars to Display
      Display[59] = 0; //add null terminator
      fprintf(stderr, "DEBUG: c2esp: Got %d byte reply = %s\n", BytesRead, Display);
      DoLog("Got %d byte reply\n", BytesRead, 0);
            if(strncmp(BackBuf, Expect, strlen(Expect)) != 0) 
            {
                  fprintf(stderr, "DEBUG: c2esp: wrong reply = %s\n", Display);
                  DoLogString("Unexpected reply = %s\n", Display);
                  return(0);
            }
            else DoLogString("Reply = %s\n", Display);
      }
      return(BytesRead);
}


time_t KeepAwake(time_t Start, int Interval)
{
// Keeps the printer connection awake by sending DeviceStatus query not sooner than the specified interval in seconds
// Usage:   Start = KeepAwake(Start, Interval);
      if(time(NULL) - Start > Interval)
      {
            DoLog("Keeping printer awake by DeviceStatus?\n",0,0);
            GoodExchange("DeviceStatus?", "0101,DeviceStatus.ImageDevice", DoBack, BackBuf,  BackBufLen,  1,  1.0);
            return (time(NULL));
      }
      else return (Start);
}

void
KeepAwakeFor(int Duration, int Interval)
{
/* Keep the printer connection awake for Duration seconds, doing KeepAwake every Interval seconds */
      time_t      KeepAwakeStart;
      int   i;

      KeepAwakeStart = time(NULL);
      for (i=0;i<Duration;++i)
      {
            sleep(1);
            KeepAwakeStart = KeepAwake(KeepAwakeStart,Interval); 
      }
}

int
MarkerPercent(char *Buf, int GetColour) /* GetColour = 1 for "Color" or 0 for "Black" */
{
      char *MarkerLevelString;
      
            if(GetColour) MarkerLevelString = strstr(Buf, "DeviceStatus.Printer.InkLevelPercent.Color=");
            else MarkerLevelString = strstr(Buf, "DeviceStatus.Printer.InkLevelPercent.Black=");
            MarkerLevelString = strstr(MarkerLevelString, "=")+1;
            if(strncmp(MarkerLevelString,"F",1)==0) return (100);
            else return (atoi(MarkerLevelString));
}

void
MarkerSetup()
{
      fprintf(stderr, "ATTR: marker-colors=black,magenta\n"); //displays ink drops in printer manager
      fprintf(stderr, "ATTR: marker-names=black,colour\n");
}

/*
 * 'main()' - Main entry and processing of driver.
 */

int                                 /* O - Exit status */
main(int  argc,                           /* I - Number of command-line arguments */
     char *argv[])                        /* I - Command-line arguments */
{
  FILE            *fp;                    /* Command file */
  char            line[1024],             /* Line from file */
            *lineptr;               /* Pointer into line */
  ppd_file_t      *ppd;                   /* PPD file */
      int BlackPercent, ColourPercent;
      int StatusLength;

      fputs("INFO: command2esp running\n", stderr);
      StartTime = time(NULL);

#if DEBUGFILES == 1
//fix this log file
      chmod("/tmp/KodakCommandLog", S_IRUSR | S_IWUSR | S_IROTH ); //let anyone read it
      remove("/tmp/KodakCommandLog"); //to be sure I only see the latest
      LogFile = fopen("/tmp/KodakCommandLog", "w"); //open the log file
      setbuf(LogFile, NULL);
      fprintf(LogFile, "KodakCommandLog c2esp\n");
#endif

 /*
  * Check for valid arguments...
  */

  if (argc < 6 || argc > 7)
  {
   /*
    * We don't have the correct number of arguments; write an error message
    * and return.
    */

    fputs("ERROR: command2esp job-id user title copies options [file]\n", stderr);
    return (1);
  }

 /*
  * Open the PPD file... Is this needed?
  */

  if ((ppd = ppdOpenFile(getenv("PPD"))) == NULL)
  {
    fputs("ERROR: Unable to open PPD file!\n", stderr);
    return (1);
  }

 /*
  * Open the command file as needed...
  */

  if (argc == 7)
  {
    if ((fp = fopen(argv[6], "r")) == NULL)
    {
      perror("ERROR: Unable to open command file - ");
      return (1);
    }
  }
  else
    fp = stdin;

 /*
  * Read the commands from the file and send the appropriate commands...
  */

  while (fgets(line, sizeof(line), fp) != NULL)
  {
   /*
    * Drop trailing newline...
    */

    lineptr = line + strlen(line) - 1;
    if (*lineptr == '\n')
      *lineptr = '\0';

   /*
    * Skip leading whitespace...
    */

    for (lineptr = line; isspace(*lineptr); lineptr ++);  /* isspace is in ctype.h */
   /*
    * Skip comments and blank lines...
    */

    if (*lineptr == '#' || !*lineptr)
      continue;

   /*
    * Parse the command...
    */

    if (strncasecmp(lineptr, "Clean", 5) == 0)
    {
     /* Clean heads...*/
      fputs("INFO: command2esp Clean print head\n", stderr);
      fprintf(LogFile, "Clean print head\n");
      GoodExchange("Maintenance=003?", "0096, OK, Maintenance Started;", DoBack, BackBuf,  BackBufLen,  1,  1.0);
      KeepAwakeFor(80,10);      
    }

    else if (strncasecmp(lineptr, "PrintAlignmentPage", 18) == 0)
    {
     /* Print alignment page...*/

      fputs("INFO: command2esp Print alignment page\n", stderr);
      fprintf(LogFile, "Print alignment page\n");
      GoodExchange("Maintenance=006?", "0096, OK, Maintenance Started;", DoBack, BackBuf,  BackBufLen,  1,  1.0);
      KeepAwakeFor(80,10);
    } 

    else if (strncasecmp(lineptr, "PrintSelfTestPage", 17) == 0)
    {
      fputs("INFO: command2esp Print Self Test Page\n", stderr);
      fprintf(LogFile, "Print Self Test Page\n");
      GoodExchange("Maintenance=002?", "0096, OK, Maintenance Started;", DoBack, BackBuf,  BackBufLen,  1,  1.0);
      KeepAwakeFor(80,15);
    }

    else if (strncasecmp(lineptr, "ReportLevels", 12) == 0)
    {
     /* Report ink levels... */

      StatusLength=abs(GoodExchange("DeviceStatus?", "0101,DeviceStatus.ImageDevice", DoBack, BackBuf,  BackBufLen,  1,  1.0));
      DoLog("StatusLength=%d\n",StatusLength,0);
/* you can get unexpected reply if there is an ink low warning then GoodExchange will be -ve */
/* aquire ink levels here? DeviceStatus.Printer.InkLevelPercent.Colour=nn%&DeviceStatus.Printer.InkLevelPercent.Black=nn% */
      if(StatusLength>0)
      {
            ColourPercent = MarkerPercent(BackBuf,1);
            BlackPercent = MarkerPercent(BackBuf,0);

            DoLog("ColourPercent=%d\n",ColourPercent,0);
            DoLog("BlackPercent=%d\n",BlackPercent,0);

            MarkerSetup();
            fprintf(stderr,"ATTR: marker-levels=%d,%d\n",BlackPercent,ColourPercent); // sets the levels displayed in printer manager
      }
    }

    else if (strncasecmp(lineptr, "SetAlignment", 12) == 0)
    {
     /*
      * Set head alignment... may not be possible for ESP printers
      */
    }

    else
      fprintf(stderr, "ERROR: Invalid printer command \"%s\"!\n", lineptr);
  }

 /*
  * Close the files and return...
  */

  ppdClose(ppd);
  if (fp != stdin) fclose(fp);

  if(LogFile != NULL) 
  {
      fclose(LogFile);
      chmod("/tmp/KodakCommandLog", S_IRUSR | S_IWUSR | S_IROTH ); //let anyone read it
  }

  return (0);
}



Generated by  Doxygen 1.6.0   Back to index