online status with pjl

Sterck Serge serge.sterck at fmsb.be
Sun Jul 25 23:30:30 PDT 2010


> On Jul 23, 2010, at 2:26 AM, Sterck Serge wrote:
> > I need to known the exact status (out of paper,tray missing etc..)of =
> printer placed in a kiosk in real time.
> >=20
> > I have downloaded the hp backend and i saw
> > that they use pjl to enable unsolicited status of device and job
> > @PJL USTATUS DEVICE =3D ON \r\n at PJL USTATUS JOB =3D ON \
> > they start a thread that read this status and report this information =
> back
> > to cups.
> >=20
> > if i writen a new backend based on the usb backend must i use libusb =
> or the traditionnal method to find the device looking at /dev/usb ?
> >=20
> > The status of the printer is reported in cups only during the print of =
> a job . Is there a possibility to report this in real time.
>
> What you'll need to do is have a background process that sends status =
> updates to your application separately and a new backend that talks to =
> this background process to send print data and report status.
>
> ________________________________________________________________________
> Michael Sweet, Senior Printing System Engineer, PWG Chair
>


i'm using a thread in my backend like hp but cups is only aware of the status
of the printer just when a job is submited and printed because it is the only moment that the backend is called
Hereis the backend it is just a proof of concept i doesnt not print yet i'm just in the main thread performing a sleep of 60s to simulated a print of a job
and the thread read_pjl read the status received by the printer.
I have another problem i received the out of tray error but when i put it back
the printer don't send me the printer ready status grrrr lexmark

#include <cups/backend.h>
#include <cups/cups.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <cups/string.h>
#include <cups/i18n.h>
#include <signal.h>
#include <pthread.h>



#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <syslog.h>

struct pjl_attributes
     {
        int current_status;
        int eoj_pages;        /* end-of-job pages */
       int abort;             /* 0=no, 1=yes */
       int done;              /* 0=no, 1=yes */
       int usb_fd;
       pthread_t tid;
       pthread_mutex_t mutex;
       pthread_cond_t done_cond;
      };

static const char pjl_ustatus_cmd[] = "\e%-12345X at PJL USTATUS DEVICE = ON \r\n at PJL USTATUS JOB = ON \r\n at PJL JOB \r\n\e%-12345X";
static const char pjl_job_end_cmd[] = "\e%-12345X at PJL EOJ \r\n\e%-12345X";
static const char pjl_ustatus_off_cmd[] = "\e%-12345X at PJL USTATUSOFF \r\n\e%-12345X";


/*
 * Local functions...
 */

void	list_devices(void);
int	print_device(const char *uri, const char *hostname,
	             const char *resource, char *options,
		     int print_fd, int copies, int argc, char *argv[],
                     struct pjl_attributes pa);

int parse_pjl_job_end(char *buf, int *pages)
{
   char *p, *tail;
   int stat=0;

   if (buf[0] == 0)
     goto bugout;

    if ((p = strcasestr(buf, "ustatus job")) != NULL)
      {
        if (strncasecmp(p+13, "end", 3) == 0)
          {
             stat = 1;
             if ((p = strcasestr(p+13+5, "pages=")) != NULL)
               *pages = strtol(p+6, &tail, 10);
          }
       }

    bugout:
    return stat;
}

int parse_pjl_device_status(char *buf, int *status)
{
  char *p, *tail;
  int stat=0;

  if (buf[0] == 0)
    goto bugout;

  if ((p = strcasestr(buf, "code=")) != NULL)
    {
      *status = strtol(p+5, &tail, 10);
      syslog(LOG_INFO,"status = %d",*status);
      stat = 1;
   }

   bugout:
   return stat;
}

int get_pjl_input(int usb_fd,char *buf,int buf_size,int *bytes_read)
{
  int stat;
  int len;

  *bytes_read = 0;

  len = read(usb_fd, buf,buf_size);
  *bytes_read = len;
  return 0;

}
static void pjl_read_thread(struct pjl_attributes *pa)
{

  char buf[1024];
  int len,new_status,new_eoj,stat,bytes_read;

  pthread_detach(pthread_self());
  syslog(LOG_INFO,"fmsb backend - starting thread %d\n",(int)pa->tid);
  pa->current_status = 10001;                        /* default is ready */
  pa->eoj_pages = pa->abort = pa->done = 0;

  while( !pa->abort)
  {
     buf[0] = '\0';
     stat = get_pjl_input(pa->usb_fd,buf,sizeof(buf),&bytes_read);
     pthread_mutex_lock(&pa->mutex);
     new_status = parse_pjl_device_status(buf, &pa->current_status);
     new_eoj = parse_pjl_job_end(buf, &pa->eoj_pages);
     pthread_mutex_unlock(&pa->mutex);
     if (new_status)
       syslog(LOG_INFO,"read new pjl status: %d\n", pa->current_status);
     if (new_eoj)
        syslog(LOG_INFO,"read pjl job_end: %d\n", pa->eoj_pages);

     syslog(LOG_INFO,"fmsb backend - pjl input = %s",buf);
  }
  syslog(LOG_INFO,"fmsb backend - exiting thread %d abord = %d stat=%d\n",(int)pa->tid,pa->abort,stat);
  pa->done=1;
  pthread_cond_signal(&pa->done_cond);

  return;
}
void list_devices(void)
{
 int	i;				/* Looping var */
  int	fd;				/* File descriptor */
  char	device[255],			/* Device filename */
	device_id[1024],		/* Device ID string */
	device_uri[1024],		/* Device URI string */
	make_model[1024];		/* Make and model */

 /*
  * Try to open each USB device...
  */

  for (i = 0; i < 16; i ++)
  {
   /*
    * Linux has a long history of changing the standard filenames used
    * for USB printer devices.  We get the honor of trying them all...
    */

    sprintf(device, "/dev/usblp%d", i);

    if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
    {
      if (errno != ENOENT)
	continue;

      sprintf(device, "/dev/usb/lp%d", i);

      if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
      {
	if (errno != ENOENT)
	  continue;

	sprintf(device, "/dev/usb/usblp%d", i);

    	if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
	  continue;
      }
    }

    if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
                            make_model, sizeof(make_model),
			    "fmsb", device_uri, sizeof(device_uri)))
      printf("direct %s \"%s\" \"%s FMSB #%d\" \"%s\"\n", device_uri,
	     make_model, make_model, i + 1, device_id);

    close(fd);
  }
}


/*
 * 'open_device()' - Open a USB device...
 */

static int				/* O - File descriptor or -1 on error */
open_device(const char *uri,		/* I - Device URI */
            int        *use_bc)		/* O - Set to 0 for unidirectional */
{
 int	fd;				/* File descriptor */


 /*
  * The generic implementation just treats the URI as a device filename...
  * Specific operating systems may also support using the device serial
  * number and/or make/model.
  */

  syslog(LOG_INFO,"fmsb backend - Opening device : %s",uri);
  if (!strncmp(uri, "usb:/dev/", 9))
  {
   /*
    * Do not allow direct devices anymore...
    */

    errno = ENODEV;
    return (-1);
  }

  if (!strncmp(uri, "fmsb://", 7))
  {
   /*
    * For Linux, try looking up the device serial number or model...
    */

    int		i;			/* Looping var */
    int		busy;			/* Are any ports busy? */
    char	device[255],		/* Device filename */
		device_id[1024],	/* Device ID string */
		make_model[1024],	/* Make and model */
		device_uri[1024];	/* Device URI string */


   /*
    * Find the correct USB device...
    */

    for (;;)
    {
      for (busy = 0, i = 0; i < 16; i ++)
      {
       /*
	* Linux has a long history of changing the standard filenames used
	* for USB printer devices.  We get the honor of trying them all...
	*/

	sprintf(device, "/dev/usblp%d", i);

	if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT)
	{
	  sprintf(device, "/dev/usb/lp%d", i);

	  if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT)
	  {
	    sprintf(device, "/dev/usb/usblp%d", i);

    	    if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT)
	      continue;
	  }
	}

	if (fd >= 0)
	{
	  backendGetDeviceID(fd, device_id, sizeof(device_id),
                             make_model, sizeof(make_model),
			     "fmsb", device_uri, sizeof(device_uri));
	}
	else
	{
	 /*
	  * If the open failed because it was busy, flag it so we retry
	  * as needed...
	  */

	  if (errno == EBUSY)
	    busy = 1;

	  device_uri[0] = '\0';
        }

        if (!strcmp(uri, device_uri))
	{
	 /*
	  * Yes, return this file descriptor...
	  */

	  fprintf(stderr, "DEBUG: Printer using device file \"%s\"...\n",
		  device);

	  return (fd);
	}

       /*
	* This wasn't the one...
	*/

        if (fd >= 0)
	  close(fd);
      }

     /*
      * If we get here and at least one of the printer ports showed up
      * as "busy", then sleep for a bit and retry...
      */

      if (busy)
	_cupsLangPuts(stderr,
	              _("INFO: Printer busy; will retry in 5 seconds...\n"));

      sleep(5);
    }
  }
  else
  {
    errno = ENODEV;
    return (-1);
  }
}
/*
 * 'print_device()' - Print a file to a USB device.
 */

int					/* O - Exit status */
print_device(const char *uri,		/* I - Device URI */
             const char *hostname,	/* I - Hostname/manufacturer */
             const char *resource,	/* I - Resource/modelname */
	     char       *options,	/* I - Device options/serial number */
	     int        print_fd,	/* I - File descriptor to print */
	     int        copies,		/* I - Copies to print */
	     int	argc,		/* I - Number of command-line arguments (6 or 7) */
	     char	*argv[],        /* I - Command-line arguments */
             struct pjl_attributes pa)  /* I - pjl structure */
{
  int		use_bc;			/* Use backchannel path? */
  int		device_fd;		/* USB device */
  size_t	tbytes;			/* Total number of bytes written */
  int           len;
  struct termios opts;			/* Parallel port options */

  (void)argc;                           /* to disable warning of gcc */
  (void)argv;                           /* to diable  warning of gcc */

/*
  * Open the USB port device...
  */

  fputs("STATE: +connecting-to-device\n", stderr);
  do
  {
    use_bc = 0;
    if ((device_fd = open_device(uri, &use_bc)) == -1)
    {
      if (getenv("CLASS") != NULL)
      {
       /*
        * If the CLASS environment variable is set, the job was submitted
	* to a class and not to a specific queue.  In this case, we want
	* to abort immediately so that the job can be requeued on the next
	* available printer in the class.
	*/

        _cupsLangPuts(stderr,
	              _("INFO: Unable to contact printer, queuing on next "
			"printer in class...\n"));

       /*
        * Sleep 5 seconds to keep the job from requeuing too rapidly...
	*/

	sleep(5);

        return (CUPS_BACKEND_FAILED);
      }

      if (errno == EBUSY)
      {
        _cupsLangPuts(stderr,
	              _("INFO: Printer busy; will retry in 10 seconds...\n"));
	sleep(10);
      }
      else if (errno == ENXIO || errno == EIO || errno == ENOENT ||
               errno == ENODEV)
      {
        _cupsLangPuts(stderr,
	              _("INFO: Printer not connected; will retry in 30 "
		        "seconds...\n"));
	sleep(30);
      }
      else
      {
	_cupsLangPrintf(stderr,
	                _("ERROR: Unable to open device file \"%s\": %s\n"),
			resource, strerror(errno));
	return (CUPS_BACKEND_FAILED);
      }
    }
  } while (device_fd < 0);

/*
     * enable pjl status

*/
  len = write(device_fd,pjl_ustatus_cmd,strlen(pjl_ustatus_cmd));
  pa.usb_fd = device_fd;
  pthread_mutex_init(&pa.mutex,NULL);
  pthread_cond_init(&pa.done_cond,NULL);
  pthread_create(&pa.tid,NULL,(void *(*)(void*))pjl_read_thread,(void *)&pa);
  tbytes = 0;
  while (copies > 0)
  {
    copies--;

   if (print_fd != 0)
     {
         fputs("PAGE: 1 1\n",stderr);
         lseek(print_fd,0,SEEK_SET);
     }
   if (print_fd != 0 && tbytes >= 0)
      _cupsLangPrintf(stderr,
#ifdef HAVE_LONG_LONG
		      _("INFO: Sent print file, %lld bytes...\n"),
#else
		      _("INFO: Sent print file, %ld bytes...\n"),
#endif /* HAVE_LONG_LONG */
		      CUPS_LLCAST tbytes);
    syslog(LOG_INFO,"sleeping 60 s in print thread");
    sleep(60);
  }
  len = write(device_fd,pjl_job_end_cmd,strlen(pjl_job_end_cmd));
  len = write(device_fd,pjl_ustatus_off_cmd,strlen(pjl_ustatus_off_cmd));
  syslog(LOG_INFO,"fmsb backend - stoppped");

   /*
    * Close the USB port and return...
   */
  if( pa.tid)
  {
       pthread_mutex_lock(&pa.mutex);
       pa.abort=1;
       while (!pa.done)
         pthread_cond_wait(&pa.done_cond,&pa.mutex);
       pthread_mutex_unlock(&pa.mutex);
       pthread_cancel(pa.tid);
       pthread_mutex_destroy(&pa.mutex);
       pthread_cond_destroy(&pa.done_cond);
    }
  close(device_fd);
  return CUPS_BACKEND_OK;
}



/*
 * 'main()' - Send a file to the specified USB port.
 *
 * Usage:
 *
 *    printer-uri job-id user title copies options [file]
 */

int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line arguments (6 or 7) */
     char *argv[])			/* I - Command-line arguments */
{
  int		print_fd;		/* Print file */
  int		copies;			/* Number of copies to print */
  int		status;			/* Exit status */
  int		port;			/* Port number (not used) */
  const char	*uri;			/* Device URI */
  char		method[255],		/* Method in URI */
		hostname[1024],		/* Hostname */
		username[255],		/* Username info (not used) */
		resource[1024],		/* Resource info (device and options) */
		*options;		/* Pointer to options */
struct pjl_attributes pa;

pa.tid = 0;



#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
  struct sigaction action;		/* Actions for POSIX signals */
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */


 /*
  * Make sure status messages are not buffered...
  */

  setbuf(stderr, NULL);

 /*
  * Ignore SIGPIPE signals...
  */

#ifdef HAVE_SIGSET
  sigset(SIGPIPE, SIG_IGN);
#elif defined(HAVE_SIGACTION)
  memset(&action, 0, sizeof(action));
  action.sa_handler = SIG_IGN;
  sigaction(SIGPIPE, &action, NULL);
#else
  signal(SIGPIPE, SIG_IGN);
#endif /* HAVE_SIGSET */

 /*
  * Check command-line...
  */

  if (argc == 1)
  {
    list_devices();
    return (CUPS_BACKEND_OK);
  }
  else if (argc < 6 || argc > 7)
  {
    _cupsLangPrintf(stderr,
                    _("Usage: %s job-id user title copies options [file]\n"),
                    argv[0]);
    return (CUPS_BACKEND_FAILED);
  }

 /*
  * Extract the device name and options from the URI...
  */

  uri = cupsBackendDeviceURI(argv);

  if (httpSeparateURI(HTTP_URI_CODING_ALL, uri,
                      method, sizeof(method), username, sizeof(username),
		      hostname, sizeof(hostname), &port,
		      resource, sizeof(resource)) < HTTP_URI_OK)
  {
    _cupsLangPuts(stderr,
                  _("ERROR: No device URI found in argv[0] or in DEVICE_URI "
	            "environment variable!\n"));
    return (1);
  }

 /*
  * See if there are any options...
  */

  if ((options = strchr(resource, '?')) != NULL)
  {
   /*
    * Yup, terminate the device name string and move to the first
    * character of the options...
    */

    *options++ = '\0';
  }

 /*
  * If we have 7 arguments, print the file named on the command-line.
  * Otherwise, send stdin instead...
  */

  if (argc == 6)
  {
    print_fd = 0;
    copies   = 1;
  }
  else
  {
   /*
    * Try to open the print file...
    */

    if ((print_fd = open(argv[6], O_RDONLY)) < 0)
    {
      _cupsLangPrintf(stderr, _("ERROR: Unable to open print file %s - %s\n"),
                      argv[6], strerror(errno));
      return (CUPS_BACKEND_FAILED);
    }

    copies = atoi(argv[4]);
  }

 /*
  * Finally, send the print file...
  */

  status = print_device(uri, hostname, resource, options, print_fd, copies,
                        argc, argv,pa);

 /*
  * Close the input file and return...
  */

  if (print_fd != 0)
    close(print_fd);


  return (status);
}






More information about the cups-devel mailing list