#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */

#include <sys/ioctl.h>
#include <linux/serial.h>

#define FALSE 0
#define TRUE 1
#define TIMEOUT 10000
#define BUFFER_SIZE 512
volatile int STOP = FALSE;
double count = 0;

double Timeout = TIMEOUT;
int fd;
int i;
int res;
char buf[BUFFER_SIZE];

#define ALTERNATE_BAUD_RATE 250000

/*
 *this function initializes the bus communication
 */
int initport( int fd )
{
   struct termios options;
   // Get the current options for the port...
   tcgetattr(fd, &options);
   /* Set controlflags */
   options.c_cflag |= ( CLOCAL | CREAD ); /* characters may be read , ignore modem state, local connection */
   options.c_cflag |= CS8; /* 8 bits pro byte */
   options.c_cflag |= B38400; /*Set the baud rates to 38400; signals to use alt_speed*/
   options.c_cflag &= ~PARENB;
   options.c_cflag &= ~CSTOPB;
   options.c_cflag &= ~CSIZE;

   /* Set input flags */
   options.c_iflag = IGNBRK /* Ignore BREAKS on Input */
   | IGNPAR /* No Parity */
   | ICRNL; /* map CR to NL (otherwise a CR input on the other computer will not terminate input)*/

   /* Set flow control */
   options.c_iflag |= IXON /* enable XON/XOFF flow control on output*/
   | IXOFF /* enable XON/XOFF flow control on intput*/
   | IXANY;
   options.c_cc[VEOF] = 4; /* Ctrl-d */
   options.c_cc[VMIN] = 0; /* blocking read until 1 character arrives */
   options.c_cc[VINTR] = 1; /* Ctrl-c */
   /*Raw output.*/
   options.c_oflag = 0;
   options.c_lflag = ICANON; /* enable canonical input
    disable all echo functionality, and don't send signals to calling program*/
   // Set the new options for the port...
   tcsetattr(fd, TCSANOW, &options);

#if 0
   /* 3. You can also set baud rate by setting custom divisor as follows
   *    - set tty->termios->c_cflag speed to B38400
   *    - call TIOCSSERIAL ioctl with (struct serial_struct) set as
   *      follows:
   *      o flags & ASYNC_SPD_MASK == ASYNC_SPD_CUST
   *      o custom_divisor set to baud_base / your_new_baudrate
   */
   /* create struct serial*/
   struct serial_struct serial;
   /* retrieve current settings */
   ioctl(fd, TIOCGSERIAL, &serial);
   /* set ASYNC_SPD_CUST*/
   serial.flags &= ~ASYNC_SPD_MASK;
   serial.flags |= ASYNC_SPD_CUST;
   serial.custom_divisor = (int) (serial.baud_base / ALTERNATE_BAUD_RATE);
   printf("baud_base: %i \n",serial.baud_base);
   printf("divisor  : %i \n",serial.custom_divisor);
   printf("baud_rate: %i \n",ALTERNATE_BAUD_RATE);
   ioctl(fd, TIOCSSERIAL, &serial);
#endif
   return 1;
}

/*
 * The logic involved in setting the baudrate can be cleanly split into
 * 3 steps.
 * 1. Standard baud rates are set in tty->termios->c_cflag
 * 2. If these are not enough, you can set any speed using alt_speed as
 * follows:
 *    - set tty->termios->c_cflag speed to B38400
 *    - set your real speed in tty->alt_speed; it gets ignored when
 *      alt_speed==0, (or)
 *    - call TIOCSSERIAL ioctl with (struct serial_struct) set as
 *      follows:
 *      flags & ASYNC_SPD_MASK == ASYNC_SPD_[HI, VHI, SHI, WARP],
 *      this just sets alt_speed to (HI: 57600, VHI: 115200,
 *      SHI: 230400, WARP: 460800)
 * ** Steps 1, 2 are done courtesy of tty_get_baud_rate
 * 3. You can also set baud rate by setting custom divisor as follows
 *    - set tty->termios->c_cflag speed to B38400
 *    - call TIOCSSERIAL ioctl with (struct serial_struct) set as
 *      follows:
 *      o flags & ASYNC_SPD_MASK == ASYNC_SPD_CUST
 *      o custom_divisor set to baud_base / your_new_baudrate
 * ** Step 3 is done courtesy of code borrowed from serial.c
 *    I should really spend some time and separate + move this common
 *    code to serial.c, it is replicated in nearly every serial driver
 *    you see.
 */

/*
 *this function will write a string of data, will print it on the screen
 */
int writeport( int fd, char *chars )
{
   int len = strlen(chars);
   chars[len] = 0x0A; // stick a <LF> after the command
   chars[len + 1] = 0x00; // terminate the string properly
   int n = write(fd, chars, strlen(chars));
   printf("lenght:0x%x\n", len);
   if ( n < 0 )
   {
      fputs("write failed!\n", stderr);
      return 0;
   }
   return 1;
}

/*
 *this function will read a string of data, will print it on the screen
 */
int PrintReceivedData( void )
{

   while ( STOP == FALSE )
   { /* loop until we have a terminating condition */
      /* read blocks program execution until a line terminating character is
       input, even if more than BUFFER_SIZE chars are input. If the number
       of characters read is smaller than the number of chars available,
       subsequent reads will return the remaining chars. res will be set
       to the actual number of characters actually read */
      //printf("receive\n");
      res = read(fd, buf, BUFFER_SIZE);
      buf[res] = '\0'; /* set end of string, so we can printf */
      //printf("%s (%i)\n", buf, res);
      printf("%s\n", buf);
      //if (buf[0]=='\0') STOP=TRUE;
      if ( buf[0] == '\n' && ( --Timeout > 0 ) )
      {
      }
      //if (buf[0]=='\n' && (Timeout<=1)) {
      if ( Timeout <= 1 )
      {
         printf(" count %f\n", Timeout);
         STOP = TRUE;
      }

   }
   return 1;
}

/*
 *this is the main function
 */
int main( int argc, char *argv[] )
{

   fd = open("/dev/ttyUSB1", O_RDWR | O_NOCTTY | O_NDELAY);

   if ( fd == -1 )
   {
      perror("open_port: Unable to open /dev/ttyS1 - ");
      return 1;
   }
   else
   {
      fcntl(fd, F_SETFL, 0);
   }

   initport(fd);
   char sCmd[254];

   for ( i = 1; i < argc ; i++ )
   {

      strcpy(sCmd, argv[i]);
      printf("%s\n", sCmd);
      if ( !writeport(fd, sCmd) )
      {
         printf("write failed\n");
         close(fd);
         return 1;
      }
      printf("written:%s\n", sCmd);

   }

   PrintReceivedData();

   return 0;

}

