/* File rw.c
 *
 * Due to some problems with the 2.6 kernels, I had to find a way in
 * order to make reading and writing from/to the device file /dev/lp0 and
 * /dev/usb/lp0 working in the same way.
 * With the 2.6 kernel, the read() call will no more be interrupted by
 * an alarm timer. Read on /dev/lp0 is a blocking call, read on 
 * /dev/usb/lp0 will never block.
 * Both device has different behaviour and the kernel people seem not to
 * be able to understood the problem and fix it.
 *
 * Solution: If we open the device file with the O_NDELAY flag set,
 * both interface will return immediatly with the value -1 and errno set
 * to EAGAIN if nothing is to be read. 
 *
 * Writing may be working for now without changes.
 */
 
#ifndef MACOS
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/poll.h>
#include <signal.h>

int inFromFile = 0;

/* the two following functions are for testing. If we got a log
 * from ttink (status or id), we can check what happen and if the
 * results are as expected.
 */
 

/**********************************************
 * Read the next line beginning with Recv:
 *********************************************/
 
ssize_t readLine(int fd, unsigned char *buf, size_t sz)
{
   int i = 0;
   buf[0] = 0;
   while( read(fd, buf+i, 1) > 0 )
   {
      buf[i+1] = 0;

      if ( buf[i] == '\n' )
      {
          buf[i] = 0;
          if ( strncmp(buf, "Recv:",5) == 0 )
          {
             return i;
          }
          else
          {
             i = 0;
             buf[0] = 0;
            continue;
          }
      }
      i++;
      if ( i >= sz )
         break;
   }
   return -1;
}

/**********************************************
 * convert the hex value to binary and copy to
 * the output buffer *buf
 *********************************************/
 
ssize_t convertBuf(unsigned char *buf, int sz, char *buffer)
{
   int i = 0;
   buffer += 5; /* skip Recv: */
   while(*buffer && sz > 1)
   {
      buf[i] = (unsigned char)strtol(buffer, &buffer, 16)&0xff;
      i++;
      sz--;
   }
   buf[i] = '\0';
   return i;
}

/***********************************************
 * Low level read function. The device is in
 * NON_BLOCK mode. 
 **********************************************/

ssize_t devRead(int fd, unsigned char *buf, size_t sz, int to)
{
   int rd = 0;
   to /= 10;
   errno = 0;

   if ( !inFromFile )
   {
      /* Normal way */
      while(to > 0 && rd != -1 )
      {
         /* wait a little bit */
         poll(NULL, 0, 10);
         to--;
         rd = read(fd, buf, sz);
         if ( rd > 0 )
         {
            return rd;
         }
      }
   }
   else
   {
      /* Read from a file (test)
       * read a line, if the line begin with Recv:
       * put the code into the buffer
       */
      char buffer[8092];
      if ( readLine(fd, buffer, sizeof(buffer)) >= 0 )
      {
         rd = convertBuf(buf, sz, buffer);
         return rd;
      }
   }

   /* at this point we are probably interrupted */
   if ( rd == 0 )
   {
      errno = EINTR;
   }
   return -1;
}

/***********************************************
 * Low level write function. The device is in
 * NON_BLOCK mode. 
 **********************************************/

ssize_t devWrite(int fd, unsigned char *buf, size_t sz, int to)
{
   int wr = 0;
   to /= 10;
   errno = 0;

   /* if we are readinf from a file don't write to it
    * leave the function with OK
    */

   if (inFromFile )
   {
      return sz;
   }

   while(to > 0 && wr != -1 )
   {
      /* wait a little bit */
      poll(NULL, 0, 10);
      to--;
      wr = write(fd, buf, sz);
      if ( wr > 0 )
      {
         return wr;
      }
   }

   /* at this point we are probably interrupted */
   if ( wr == 0 )
   {
      errno = EINTR;
   }
   return -1;
}
#endif
