/*  Revisions 4/28/89    */

#include <stdio.h>
#include "fcntl.h"
#include "ctype.h"
#include "devices/serial.h"
#include "exec/io.h"
#include "exec/nodes.h"
#include "exec/lists.h"
#include "exec/devices.h"
#include "exec/ports.h"

   /* DEFINED VALUES */
#define NULL 0
#define TRUE 1
#define FALSE 0
#define CR 0x0d
#define SERBUFSIZE 4096

   /* DEVICES DEFINED */
#define MODEM 1

/*-------------------------------------------*/
/*   Required I/O Structures and Functions   */
/*-------------------------------------------*/
extern struct MsgPort *CreatePort();
extern struct IORequest *CreateExtIO();

struct IOExtSer *io_read;
struct IOExtSer *io_write;

struct MsgPort *readport;
struct MsgPort *writeport;

FILE *fopen(), *f1;

void *calloc();
/*-------------------------------------------*/

   /* port status variable */

long ser_open;

   /* I/O buffers */
unsigned char inbuffer[200];
unsigned char outbuffer[200];

   /* miscellaneous flags */
int device;             /* boolean type variable holds device type */

int trys;               /* attempts to open the serial port */

/*-------------------------------------------*/
   /* command line parameter variables */
/*-------------------------------------------*/
char   direction[4];
char   return_file[80];

unsigned char putvalue[80];
unsigned char getvalue[80];
/*-------------------------------------------*/



/*-----------------------------------------------*/
/*             << CLOSE_SER >>                   */
/*-----------------------------------------------*/
/*
    Delete messages from the read & write ports.
    Delete the read and write ports.
    Close the serial device.
                                                 */
close_ser()
{

   DeleteExtIO(io_read);
   DeleteExtIO(io_write);

   DeletePort(readport);
   DeletePort(writeport);

   CloseDevice(io_read);
   CloseDevice(io_write);

   if (f1!=0) fclose(f1);
}
/*----------------------------------------------------------*/
/*                   <<  DETERMINE >>                       */
/*----------------------------------------------------------*/
/*               Report Possible I/O errors                 */
Determine(error)
int error;
{
   switch(error)
   {
      case 1:{ printf("\nDevice Busy\n"); break;              }
      case 2:{ printf("\nBaud Mismatch\n"); break;            }
      case 3:{ printf("\nInvalid Baud\n"); break;             }
      case 4:{ printf("\nBuffer Error\n"); break;             }
      case 5:{ printf("\nInvalid Parameters\n"); break;       }
      case 6:{ printf("\nLine Error\n"); break;               }
      case 7:{ printf("\nSerial Device not open\n"); break;   }
      case 8:{ printf("\nPort Reset\n"); break;               }
      case 9:{ printf("\nParity Error\n"); break;             }
      case 10:{ printf("\nInit. Error\n"); break;             }
      case 11:{ printf("\nTimer Error\n"); break;             }
      case 12:{ printf("\nBuffer Overflow\n"); break;         }
      case 13:{ printf("\nNo DSR\n"); break;                  }
      case 14:{ printf("\nNo CTS\n"); break;                  }
      case 15:{ printf("\nBreak Detected\n"); break;          }
   }
}



/*-----------------------------------------------------------------*/
/*                     <<  READSER  >>                             */
/*-----------------------------------------------------------------*/
/* Asynchronous read of n characters of inbuffer from serial port  */
/*-----------------------------------------------------------------*/

int ReadSer(io)
struct IOExtSer *io;
{
   long error;
   error = 0L;

   if (f1==0) (f1=fopen("outfile","a+"));

      /* check to see if port has been opened correctly */

   if(ser_open == 0)
   {
         /* serial port has not been opened correctly */
      printf("\n Read attempt on closed serial port.\n");
      return(0);
   }

   io->IOSer.io_Length = 1;
   io->IOSer.io_Command = CMD_READ;
   io->IOSer.io_Data = &inbuffer;

   SendIO(io);
      /* write the n characters from the read to a transfer file */
   if (fwrite(*(io->IOSer.io_Data),1,1,f1) > 0);

   return(io->IOSer.io_Actual);
}




/*-------------------------------------------------------------------*/
/*                     <<  WRITESER  >>                              */
/*-------------------------------------------------------------------*/
/* Asynchronous write of len characters of outbuffer to serial port  */
/*-------------------------------------------------------------------*/
int WriteSer(io,outbuffer,len)
struct IOExtSer *io;
unsigned char *outbuffer;
int len;
{
   int error=0;
   int i=0;

      /* return if there's nothing to write or if write port hasn't
         been opened correctly                                       */
   if ((len==0) || (ser_open == 0)) return(0);

   if(io != NULL)
   {
      io->IOSer.io_Command = CMD_WRITE;
      io->IOSer.io_Length = 1;

      /* write the value character by character to the serial port */
      for (i = 0; i<len; i++)
      {
         io->IOSer.io_Data = &(*(outbuffer + i));
         SendIO(io);
      }
   }
   outbuffer = NULL;
   return();
}


/*-----------------------------------------------*/
/*             <<  INIT_SER  >>                  */
/*-----------------------------------------------*/
/*
    Open and Initialize the serial port with
    supplied parameters or use a default set
                                                 */
int init_ser(baud,parity,bits,stopbits)
int baud;
char parity[2];
int bits;
int stopbits;
{

   int error;       /* holds possible open or
                       initilization error    */

   while ((!ser_open) && (trys < 2))
   {
printf("\nInitializing the serial port with parameters : %d, %s, %d, \
%d \n",baud,parity,bits,stopbits);

        /* create read & write request blocks */

      io_read = (struct IOExtSer *)calloc(1,sizeof(struct IOExtSer));
      io_write = (struct IOExtSer *)calloc(1,sizeof(struct IOExtSer));
printf("\n Request blocks created .\n");

        /* create message ports for reading and writing    */

      readport = CreatePort(SERIALNAME,0);
      writeport = CreatePort(SERIALNAME,0);
printf("\n IO ports created .\n");


        /* check to see that message ports have been opened */
      if (readport == NULL) return(0);
      if (writeport == NULL) return(0);


        /* delete message ports if memory for read or write request
           blocks cannot be allocated.                      */
      if ((io_read == NULL) || (io_write == NULL))
      {
          DeletePort(readport);
          DeletePort(writeport);
          return(0);
      }
      else {
               if (device == MODEM)
               {
                  /* open read & write for 7 wire transfer */
                 io_read->io_SerFlags = SERF_XDISABLED|SERF_SHARED|SERF_7WIRE;
                 io_write->io_SerFlags = SERF_XDISABLED|SERF_SHARED|SERF_7WIRE;
               }
               else
               {
                  /* open read & write for direct communication with device */
                 io_read->io_SerFlags = SERF_XDISABLED|SERF_SHARED;
                 io_write->io_SerFlags = SERF_XDISABLED|SERF_SHARED;
printf("\n device opened for a NONmodem device .\n");
               }

               io_read->IOSer.io_Message.mn_ReplyPort = readport;
               io_write->IOSer.io_Message.mn_ReplyPort = writeport;
printf("\n reply ports created.\n");

/*
               Initialize with Parameters or Defaults

                                                                           */
         /* set parity *//* ---------------------------------------------- */

               if ((parity=='N') || (parity=='n'))
               {
printf("\n No Parity selected .\n");
                    /* Select NO Parity */

                  io_read->io_SerFlags &= ~SERF_PARTY_ON;        /* NO parity */
               }
               else

               if(strcmp(parity,"O")==0)
               {
printf("\n Odd parity selected .\n");

                    /* Select ODD Parity */

                  io_read->io_SerFlags |= SERF_PARTY_ODD | SERF_PARTY_ON;
               }
               else

               if(strcmp(parity,"E")==0)
               {
printf("\n Even Parity selected .\n");
                  /* Select EVEN Parity */

                  io_read->io_SerFlags |= SERF_PARTY_ON;
                  io_read->io_SerFlags &= ~SERF_PARTY_ODD;
               }
               else
               {
printf("\n No Parity (default) selected .\n");
                   /* DEFAULT to NO parity */

                  io_read->io_SerFlags &= ~SERF_PARTY_ON;        /* NO parity */

               }

/* OPEN Serial Device  *//* ---------------------------------------------- */
               if((error=OpenDevice(SERIALNAME,NULL,io_read,NULL))!= 0)
               {
                    /* report failure to open device for reading */

printf("\nSerial device didn't open with read request. error = %ld",error);

                  Determine(error);
                  DeleteExtIO(io_read,sizeof(struct IOExtSer));
                  DeletePort(readport);
                  return(0);
               }
               else
               if((error = OpenDevice(SERIALNAME,NULL,io_write,NULL))!= 0)
               {

                  /* report failure to open device for writing */

printf("\nSerial device didn't open with write request. error = %ld",error);

                  Determine(error);
                  DeleteExtIO(io_write,sizeof(struct IOExtSer));
                  DeletePort(writeport);
                  return(0);
               }
               else{
printf ("\n         /* serial device has been successfully opened          \
                        for both the read and write functions      */    ");

                       /* set break time */

                       io_write->io_BrkTime = io_read->io_BrkTime= 750000;
printf("\n break time set to %ld \n",io_read->io_BrkTime);
printf("\n break time set to %ld (write)\n",io_write->io_BrkTime);

         /* set baud *//* ------------------------------------------------ */
                      if((baud >= 110) && (baud <= 9600))
                         io_read->io_Baud = baud;
                      else io_read->io_Baud = 1200;

                      io_write->io_Baud = io_read->io_Baud;

printf("\n baud set to %d \n",io_read->io_Baud);
printf("\n baud set to %d (write)\n",io_write->io_Baud);

         /* set bits *//* ------------------------------------------------ */
                      if (bits == 7)
                         io_read->io_WriteLen = io_read->io_ReadLen = 7;
                      else
                      if (bits == 8)
                          io_read->io_WriteLen = io_read->io_ReadLen = 8;
                      else
                          io_read->io_WriteLen = io_read->io_ReadLen = 7;

                      io_write->io_WriteLen = io_read->io_WriteLen;
printf("\n bits set to %d \n",io_read->io_WriteLen);
printf("\n bits set to %d (write)\n",io_write->io_WriteLen);


                      io_write->io_RBufLen = io_read->io_RBufLen = SERBUFSIZE;
printf("\n buffer length set to %d \n",io_read->io_RBufLen);
printf("\n buffer length set to %d (write)\n",io_write->io_RBufLen);

         /* set stop bits *//* ------------------------------------------- */
                      if (stopbits==0)
                         io_read->io_StopBits = io_write->io_StopBits = 0;
                      else
                      if (stopbits==1)
                         io_read->io_StopBits = io_write->io_StopBits = 1;
                      else
                      if (stopbits==2)
                      {
                         if (io_read->io_ReadLen == 8) return(0);
                         else
                         io_read->io_StopBits = io_write->io_StopBits = 2;
                      }
printf("\n stop bits set to %d \n",io_read->io_StopBits);
printf("\n stop bits set to %d (write)\n",io_write->io_StopBits);

                      io_read->IOSer.io_Data = (char *)&inbuffer;
                      io_read->IOSer.io_Length = 1;

                      io_write->IOSer.io_Data = (char *)&outbuffer;
                      io_write->IOSer.io_Length = 1;

                      if ((io_read->IOSer.io_Command == SDCMD_SETPARAMS) &&
                         (trys == 1))
                      {
                         io_read->IOSer.io_Command =
                           io_write->IOSer.io_Command = CMD_RESET;
                         trys--;
                      }
                      else
                      {
                         io_read->IOSer.io_Command =
                            io_write->IOSer.io_Command = SDCMD_SETPARAMS;
                      }

                        /* Initialize the serial port */

                      if( ((error=DoIO(io_read))!=0) ||
                        ((error=DoIO(io_write)==0)) )
                      {
                         Determine(error); return(0);
                      }
                      else {
printf("\n                 /* serial device opened and parameters        \
                              accepted                              */  ");

                              io_read->IOSer.io_Command = CMD_READ;
                              io_write->IOSer.io_Command = CMD_WRITE;
                              ser_open = TRUE;

                            }
                      trys++;
                   }
           }


   }
   return(1);
}
/*=====================================================*/
main(argc,argv)
int argc;
char *argv[];
{
        /*=====================================================*/
/* <SERIO> <outfile> <R | W> <putvalue> <baud> <parity> <bits> <stopbits> */
        /*=====================================================*/
   char pr[2];

   int error;              /* error variable */
   int i,j,n;              /* loop controlling variables */
   int bd,bt,st;           /* baud,bits,stopbits */
   int actual, defaults;   /*                            */
   int status;             /* holds the result of port initialization */

   unsigned char sum;
   unsigned char result;

/*---------------------------------------------------*/
         /* initialize variables */

   error = 0; device = 0;
   ser_open = FALSE;
   bd = bt = 0;
   st = 1;
   defaults = 0;
   sum = 0;
   status = 0;
   trys = 0;

   for (i=0;i<80;i++)
   {
      return_file[i] = 0;
      putvalue[i] = 0;
   }
   for (i=0;i<4;i++) direction[i] = 0;

   result = 0;
/*---------------------------------------------------*/

   strcpy(return_file,argv[1]);                 /* where to put the result */
     if (return_file[0] !=0) f1 = fopen(return_file,"w+");

      /* transfer file parameter passed from Magellan */
   strcpy(direction,argv[2]);             /* either "R"(read) or"W"(write) */
printf("\n direction = %s\n",direction);

      /* value to write to serial device */
   if ((strcmp(direction,"W")==0))

     if (argv[3]==0)
     {
        setenv("GETIO","COMPLETED");                  /* status indicator */
        exit();
     }
     setenv("GETIO","PENDING");                       /* status indicator */

   if(argc > 4)
   {
         /* assume there are io parameters included in the
            argument to SERIO                                */

     bd = atoi(argv[4]);
printf("\n baud = %d\n",bd);
     strcpy(pr,argv[5]);
printf("\n parity = %s\n",pr);
     bt = atoi(argv[6]);
printf("\n bt = %d\n",bt);
     st = atoi(argv[7]);
printf("\n stop bits = %d\n",st);

      /* you might want to test for a certain type of device against
         a defined parameter value                                   */

     if(((putvalue[0]=='A')||(putvalue[0]=='a')) &&
        ((putvalue[1]=='T')||(putvalue[1]=='t'))) device = MODEM;
printf("\n device = %d\n",device);

                           /* (int)baud, (str)parity, (int)bits, (int)stop */
     if((status = init_ser(bd,pr,bt,st))==FALSE)
     {
        printf("\n init_ser with given parameters returned 0 \n");
        if ((status = init_ser(defaults))==FALSE);
     }

   }
   else if((status = init_ser(defaults)) == FALSE);

   if (status == TRUE)
   {
      /* you might want to interpret this parameter as a file name
         and open it to read in order to write consecutive commands to
         the serial port                                                  */
      strncpy(putvalue,argv[3]);
printf("\n putvalue = %s\n",putvalue);

        /* should writevalue be converted to hexidecimal ? */
     if((putvalue[0]=='0') && (putvalue[1]=='x'))
     {
        /* convert ascii to hex and send to the serial port */
        /* example of an ascii to hex conversion of the input string
           consistent with the C language interpretation of the
           backslash in a string
                                                                     */
        actual = 0;
        i = 0;   j = 0;
        while (putvalue[i] != '\0')    /* process the entire string */
        {
            /* if character is a backslash */
           if (putvalue[i] == 0x5c)   /* " \ " character */
           {
              i++;
                /* if next character isn't null or backslash */
              if (putvalue[i] != 0x5c)
              {
                 for(j=0; j<2; j++)
                 {
                     /* if character is in range of hex characters A - F */
                    if ((putvalue[i]>='A') && (putvalue[i]<='F'))
                      putvalue[i] -= 'A' - 10;
                    else
                     /* if character in range of digits */
                    if ((putvalue[i]>='0') && (putvalue[i]<='9'))
                      putvalue[i] -= '0';

                    if (j==1)  /* (n)umber of bytes : n==1 represents a test
                                 for the second (low) byte                */
                    {
                        /* second byte */
                       result |= putvalue[i];
                       putvalue[actual] = result;

                       i++; result = 0;
                       actual++;
                       continue;
                    }
                    else      /* j==0 - low byte first   */
                    {
                        /* first byte */
                       result = (putvalue[i] <<= 4);
                       i++;
                    }
                 }
              }
           }
           else
           {
              putvalue[actual] = putvalue[i];
              i++; actual++;
           }
        }
      }

/*------------ Do the READ or WRITE here ----------------------------*/

      if (strcmp(direction,"W")==0)
      {
         if (device == MODEM) putvalue[strlen(putvalue)] = CR;
         actual = strlen(putvalue);

         if(WriteSer(io_write,putvalue,actual)==actual);
      }
      else

      /* READ n bytes from the serial port */
      if (strcmp(direction,"R")==0) ReadSer(io_read);

      setenv("GETIO","COMPLETED");                         /* reset status */
      close_ser();
   }
}
