0

After three weeks I can't get past this problem. I have the code below running on Ubuntu 18.04.3 which sends a string successfully to another device. When the remote device receives the string ... it sends another back ... but the code below (even with 1 sec set) times out on select().

When I comment out the select() and just do the read() ... fails to see any data as well?

It was working three weeks ago ... but recent code changes broke it ... and I cannot see why. How could a write() on a file descriptor go out the serial port ok ... but a select() and read() using the same file descriptor get nothing back. I have a third device (a PC with putty) so I can see everything on the wire. All three are on an RS-485 bus.

Any other issues with the code would be greatly appreciated!

Thanks!

// main.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <term.h>
#include <signal.h>
#include <sys/time.h>

#include "SER.h"

static
struct  sigaction mySigActTerm;

volatile
int     terminate = 0;


void terminateHandler(int signum, siginfo_t *info, void *ptr)
{
  //------------------------------------------------------------
  // set a flag here and get out.
  terminate = 1;
}


int main()
{
  int       rtn;
  pthread_t serialThdID;
  SER*      mySER;

  //------------------------------------------------------------
  // setup terminate signal
  memset(&mySigActTerm, 0, sizeof(mySigActTerm));
  mySigActTerm.sa_sigaction = terminateHandler;
  mySigActTerm.sa_flags = SA_SIGINFO;

  sigaction(SIGTERM, &mySigActTerm, NULL);

  //------------------------------------------------------------
  // initialize the serial port.
  mySER = SERinit("/dev/ttyUSB0", 2);
  if (mySER == NULL)
  {
    fprintf(stderr, "main() - SERinit() returned NULL");
    exit(EXIT_FAILURE);
  }

  //------------------------------------------------------------
  // start the serial thread.
  rtn = pthread_create(&serialThdID, NULL, serialThread, mySER);
  if(rtn  == 0)
    fprintf(stderr, "starting serial thread.\n");
  else
  {
    fprintf(stderr, "main() - pthread_create() returned %d\n%s\n", rtn, strerror(errno));
    free(mySER);
    exit(EXIT_FAILURE);
  }

  //------------------------------------------------------------
  // wait till serialThread() indicates it is running.
  while (mySER->ThreadStatus != threadRuning)
  {
    fprintf(stderr, "waiting for thread running status.\n");
    sleep(1);
  }

  //------------------------------------------------------------
  // main loop here.
  while (terminate == 0)
  {
    // do stuff here.
  }

  //------------------------------------------------------------
  // tell the serial thread to stop.
  mySER->ThreadCtrl = threadCtrlKill;

  //------------------------------------------------------------
  // verify serial thread is dead!
  while (mySER->ThreadStatus != threadStopped)
  {

  }

  //------------------------------------------------------------
  // clean up.
  SERclose(mySER);
  free(mySER);
}


serialThread.c

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <sys/time.h>
#include <term.h>
#include <inttypes.h>

#include "SER.h"



void*  serialThread(void* arg)
{
  char*   rtn;
  SER*  mySER = arg;

  mySER->tid = pthread_self();

  mySER->ThreadStatus = threadRuning;

  //  thread Loop!
  while(mySER->ThreadCtrl != threadCtrlKill)
  {
    rtn = SERwrapperFunc(mySER);
      // code to print the response here
    printf("%.*s\n", 8, rtn);
    sleep(30);
  }

  mySER->ThreadStatus = threadStopped;
  pthread_exit(NULL);
}

SERmaster.c

#define responseSize    4584

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <termios.h>
//#include <linux/serial.h>
//#include <aio.h>
#include <sys/time.h>

#include "SER.h"


// array used to get termios BAUD.
const
int       BAUDarray[9] = {  0,         // not used.
                            B4800,     // 208
                            B9600,     // 104
                            B19200,    //  52
                            B38400,    //  26
                            B57600,    //  17.363636
                            B115200,   //   8.727272
                            B230400,   //   4.363636
                            B460800    //   2.181818
                         };

// delay (in uS) per character transmitted.
//    1 start, Even parity, 7bits, 1 stop.
//    bit time (times 10 bits)
//    Plus one bit time between characters.
const
int       BAUDdelay[9] = {  0,         // not used.
                            2288,
                            1144,
                            572,
                            286,
                            191,
                            96,
                            48,
                            24
                         };

static    
char      response[4584];

static
unsigned  
int       respIndex;

static
struct    termios   newtio, oldtio;

extern
volatile
int       terminate;


static
int sendRecieve(SER* mySER, const char* msgBuffer, int msgCnt, int sendFlag, int receiveFlag)
{
  int       rtn;
  char      myChar;
  fd_set    myfds;

  struct
  timeval   tm_out;

  if (sendFlag == true)
  {
    while (1)
    {
      rtn = write(mySER->sfd, msgBuffer, msgCnt);
      if (rtn == -1)
      {
        if (errno == EINTR)
        {
          fprintf(stderr, "sendRecieve() - write() EINTR !\n");
          if (terminate == 1)
            break;                     // deal with SIGTERM !
          continue;                    // if not SIGTERM then retry.
        }
        else
        {
          fprintf(stderr, "sendRecieve() - write()\n%s\n", strerror(errno));
          return EXIT_FAILURE;
        }
      }
      else
      {
        if (rtn == msgCnt)
          break;
        else
        {
          fprintf(stderr, "sendRecieve() - write() returned less than msgCnt !\n");
          return EXIT_FAILURE;
        }
      }
    }
  }

  if (receiveFlag == true)
  {
    respIndex = 0;

    while (1)
    {
      tm_out.tv_sec  = 1;
      tm_out.tv_usec = mySER->BAUDmult * msgCnt;
      FD_ZERO(&myfds);
      FD_SET(mySER->sfd, &myfds);

      rtn = select(mySER->sfd + 1, &myfds, NULL, NULL, &tm_out);
      if (rtn == 0)
      {
        fprintf(stderr, "sendRecieve() - select() timeout!\n");
        return EXIT_FAILURE;
      }
      if (rtn == -1)
      {
        if (errno == EINTR)
        {
          fprintf(stderr, "sendRecieve() - select() EINTR !\n");
          if (terminate == 1)
            break;
          continue;
        }
        else
        {
          fprintf(stderr, "sendRecieve() - select()\n%s\n", strerror(errno));
          return EXIT_FAILURE;
        }
      }

      while (1)
      {
        rtn = read(mySER->sfd, &myChar, 1);
        if (rtn == -1)
        {
          if (errno == EINTR)
          {
            fprintf(stderr, "sendRecieve() - read() EINTR !\n");
            if (terminate == 1)
              break;
            continue;
          }
          else
          {
            fprintf(stderr, "sendRecieve() - read()\n%s\n", strerror(errno));
            return EXIT_FAILURE;
          }
        }
        else
          break;

        response[respIndex] = myChar;
        if (respIndex < responseSize - 1)
          respIndex++;
        else
          break;

        if (myChar == '\n')
          return EXIT_SUCCESS;
      }
    }
    fprintf(stderr, "sendRecieve() - select/read while loop Dumped (response frame too big)!!\n");
    return EXIT_FAILURE;
  }
  return EXIT_SUCCESS;
}


char* SERwrapperFunc(SER* mySER)
{
  char  myCharArray[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' };
  int   myCharArrayCountToSend = sizeof(myCharArray);

  sendRecieve(mySER, myCharArray, myCharArrayCountToSend, true, true);
  return response;
}


void serPrint()
{
  printf("NCCS = %d            OLD:              NEW:\n", NCCS);
  printf("c_iflag -        %08x          %08x\n", oldtio.c_iflag, newtio.c_iflag);
  printf("c_oflag -        %08x          %08x\n", oldtio.c_oflag, newtio.c_oflag);
  printf("c_cflag -        %08x          %08x\n", oldtio.c_cflag, newtio.c_cflag);
  printf("c_lflag -        %08x          %08x\n", oldtio.c_lflag, newtio.c_lflag);
  printf("c_line -         %08x          %08x\n", oldtio.c_line, newtio.c_line);
  printf("c_ispeed -       %08x          %08x\n", oldtio.c_ispeed, newtio.c_ispeed);
  printf("c_ospeed -       %08x          %08x\n", oldtio.c_ospeed, newtio.c_ospeed);

  printf("\n");

  printf("VINTR -                %02x                %02x\n", oldtio.c_cc[VINTR], newtio.c_cc[VINTR]);
  printf("VQUIT -                %02x                %02x\n", oldtio.c_cc[VQUIT], newtio.c_cc[VQUIT]);
  printf("VERASE -               %02x                %02x\n", oldtio.c_cc[VERASE], newtio.c_cc[VERASE]);
  printf("VKILL -                %02x                %02x\n", oldtio.c_cc[VKILL], newtio.c_cc[VKILL]);
  printf("VEOF -                 %02x                %02x\n", oldtio.c_cc[VEOF], newtio.c_cc[VEOF]);
  printf("VTIME -                %02x                %02x\n", oldtio.c_cc[VTIME], newtio.c_cc[VTIME]);
  printf("VMIN -                 %02x                %02x\n", oldtio.c_cc[VMIN], newtio.c_cc[VMIN]);
  printf("VSWTC -                %02x                %02x\n", oldtio.c_cc[VSWTC], newtio.c_cc[VSWTC]);
  printf("VSTART -               %02x                %02x\n", oldtio.c_cc[VSTART], newtio.c_cc[VSTART]);
  printf("VSTOP -                %02x                %02x\n", oldtio.c_cc[VSTOP], newtio.c_cc[VSTOP]);
  printf("VSUSP -                %02x                %02x\n", oldtio.c_cc[VSUSP], newtio.c_cc[VSUSP]);
  printf("VEOL -                 %02x                %02x\n", oldtio.c_cc[VEOL], newtio.c_cc[VEOL]);
  printf("VREPRINT -             %02x                %02x\n", oldtio.c_cc[VREPRINT], newtio.c_cc[VREPRINT]);
  printf("VDISCARD -             %02x                %02x\n", oldtio.c_cc[VDISCARD], newtio.c_cc[VDISCARD]);
  printf("VWERASE -              %02x                %02x\n", oldtio.c_cc[VWERASE], newtio.c_cc[VWERASE]);
  printf("VLNEXT -               %02x                %02x\n", oldtio.c_cc[VLNEXT], newtio.c_cc[VLNEXT]);
  printf("VEOL2 -                %02x                %02x\n", oldtio.c_cc[VEOL2], newtio.c_cc[VEOL2]);

  printf("\n");
  printf("\n");
}


SER* SERinit(const char* strPort, int myBAUD)
{
  SER* mySER;

  //------------------------------------------------------------
  // create the global SER struct instance.
  if ((mySER = malloc(sizeof(SER))) == NULL)
  {
    fprintf(stderr, "SERinit() - mySER malloc()\n%s\n", strerror(errno));
    return NULL;
  }
  memset(mySER, 0, sizeof(SER));

  //------------------------------------------------------------
  // setup the BAUD.
  mySER->BAUDindex = myBAUD;
  mySER->BAUDvalue = BAUDarray[myBAUD];
  mySER->BAUDmult  = BAUDdelay[myBAUD];

  //------------------------------------------------------------
  // open the serial port.
  mySER->sfd = open(strPort, O_RDWR | O_NOCTTY);
  if (mySER->sfd < 0)
  {
    fprintf(stderr, "SERInit() - open()\n%s\n", strerror(errno));
    free(mySER);
    return NULL;
  }

  //------------------------------------------------------------
  // save old port settings for when we exit.
  tcgetattr(mySER->sfd, &oldtio);

  //------------------------------------------------------------
  // prepare the newtio struct with current settings.
  newtio = oldtio;

  //------------------------------------------------------------
  // set BAUD
  if (cfsetspeed(&newtio, B9600) != 0)//mySER->BAUDvalue
  {
    fprintf(stderr, "SERInit() - cfsetspeed()\n%s\n", strerror(errno));
    free(mySER);
    return NULL;
  }

  //------------------------------------------------------------
  // set for non-canonical (raw).
  cfmakeraw(&newtio);

  newtio.c_cflag |= (CLOCAL | CREAD);
  newtio.c_cflag &= ~(CRTSCTS | CSTOB)

  // read() blocks until one char or until 100 mS timeout.
  newtio.c_cc[VTIME]  = 1;
  newtio.c_cc[VMIN]   = 1;

  // flush the toilet.
  tcflush(mySER->sfd, TCIFLUSH);

  // write new port settings.
  tcsetattr(mySER->sfd, TCSANOW, &newtio);

  serPrint();

  return mySER;
}


void SERclose(SER* mySER)
{
  // restore old port settings.
  tcsetattr(mySER->sfd, TCSANOW, &oldtio);
  close(mySER->sfd);
}

SER.h


#ifndef SER_H_
#define SER_H_

#define threadInit        0x00
#define threadStarting    0x01
#define threadRuning      0x02
#define threadFailed      0x03
#define threadStopped     0x0f

#define threadCtrlRestart 0xFE
#define threadCtrlKill    0xFF

#include <stdint.h>
#include <pthread.h>


typedef struct SER
{
  int         BAUDindex;               // the BAUD rate.

  int         BAUDmult;                // uS per character ... plus one bite time between characters.
                                       //   used as a multiplier used to calculate sleep times after write().
                                       //   (bit time x 10 bits) 71E.

  int         BAUDvalue;               // array used to set termios BAUD and get BAUDmult.
                                       // 4800 = 1       2080 uS
                                       // 9600 = 2       1040
                                       // 19,200 = 3      520
                                       // 38,400 = 4      260
                                       // 76,800 = 5      130
                                       // 115,200 = 6      65
                                       // 230,400 = 7      32.5
                                       // 460,800 = 8      16.25

  pthread_t   tid;                     // Stores thread ID.

  uint8_t     ThreadStatus;            // written only by thread.

  uint8_t     ThreadCtrl;              // written only by main.

  int         sfd;                     // serial port file descriptor.
}SER;


char* SERwrapperFunc(SER* mySER);
SER* SERinit(const char* strPort, int myBAUD);
void SERclose(SER* mySER);
void* serialThread(void* arg);

#endif /* SER_H_ */

  • 1
    *"Preparing"* the termios struct by zeroing it out is simply not robust. That method may work for you (occasionally), but it's not the reliable or portable method. See [Setting Terminal Modes Properly](http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_12.html#SEC237). Use **cfsetspeed()** to set the baudrate instead of direct bit manipulation. Properly configure (e.g. disable?) HW and SW flow control. – sawdust Dec 08 '19 at 22:42
  • *"All three are on an RS-485 bus"* -- Typically RS485 is half duplex. Is yours half duplex? Usually there's some configuration for RS485 mode, e.g. to setup the RTS control line for transmit versus receive modes. – sawdust Dec 08 '19 at 22:54
  • The USB RS-232 / 422 / 485 is in 485 mode so no RTS or CTS on the bus side. Not sure of what the USB driver does. However ... when I run the earlier code ... it works all day and all night. I tried cfsetIspeed() and cfsetOspeed() and it does not work under linux. I'll look into cfsetspeed() ... didnt know about that but I will say many examples on the net do the bits. I onlt do the termios struct for initialization then discard it. THANKS sawdust – keith bradley Dec 08 '19 at 23:36
  • sorry sawdust I did not understand your comment re: existing termios struct. I trimmed my source to create this post and accidentally trimmed the part where I obtained the existing termios setting. That part is in my original source. – keith bradley Dec 10 '19 at 15:12
  • Instead of calling **bzero()** to *"prepare"* the termios struct, the correct method is to call **tcgetattr()** as described in the link I provided. If you *"trimmed"* your source code, then how do we know if you *"accidentally"* removed other salient statements? – sawdust Dec 11 '19 at 07:10
  • The original source does not function as well. Working on it and will update code above. Thanks – keith bradley Dec 11 '19 at 20:31
  • thnx to sawdust I tweaked the code for cleaner serial port termios struct setup. problem still remains. any ideas anyone? I also 'identically' updated the old code and it still works. – keith bradley Dec 13 '19 at 22:02
  • 1
    Your initialization is now certainly *"cleaner"*, too much in fact. Two essential attributes are missing and two more should be cleared; add statements after cfmakeraw() like: `newtio.c_cflag |= (CLOCAL | CREAD);` and `newtio.c_cflag &= ~(CRTSCTS | CSTOPB);` – sawdust Dec 16 '19 at 03:09
  • *"Any other issues with the code would be greatly appreciated!"* -- What is this serial port connected to? The message protocol seems asymmetrical; you expect a newline to terminate the response, but a newline does not terminate the string that is written! Since you are expecting a response terminated by a newline, raw mode is IMO inappropriate, and you could be using canonical mode to read an entire line at a time (instead of inefficiently reading byte by byte). See https://stackoverflow.com/questions/57152937/canonical-mode-linux-serial-port/57155531#57155531 – sawdust Dec 16 '19 at 05:10
  • Thanks sawdust, I had the CLOCAL | CREAD in both the working and non-working and I can certainly put them back in. I also had CRTSCTS but removed that for troubleshooting purposes. These items seem to make no difference. The working version still works ... the newer broken one does not. The serial port is connected to a MCU device which echos the string after new line. I plan to stay in non-canonical mode when the final protocol is completed. I just picked the /n for grunts and giggles. It will not be used eventually. Just trying to get back and forth working again which it was. – keith bradley Dec 16 '19 at 19:41
  • OK ... I added those lines and the new version still does not work, the old does (with identical serial port setup BTW). At this point I have to believe the serial initialization is perfect and not where the problem lies. What else would cause a write() to send ok, but a select() to time out and read() to block forever using the same file descriptor? ... this is the part I can't understand. – keith bradley Dec 18 '19 at 18:58
  • *"I added those lines"* -- Sloppy edits! *"old does (with identical serial port setup BTW)* [work]" -- Which means you may have had a good termios configuration, tried to *"clean"* it, only to break it and waste a week. *"What ... cause ... select() to time out and read() to block forever"* -- That seems to be your hasty & faulty conclusions rather than an accurate description of program behavior. Your program has a bug where data is read but is always discarded. You need to learn how to methodically debug a program that has multiple bugs. – sawdust Dec 19 '19 at 05:40
  • My print function shows identical termios structs on the older (working) ... and newer (non working). I yield to your substantially greater experience in C coding and with termios ... but ... select ... set for one full second ... returns 0 ... which I am led to believe means that the file descriptor set (which has only one) is not ready for reading. The RS-485 driver chip most certainly has its transmit off at some point during that 1000 mS. There is no way it shouldn't see something. – keith bradley Dec 19 '19 at 20:26
  • 1
    Even though you have not posted a *minimal* example (the threading cruft is unnecessary to demonstrate the the salient issues), I did (clean up your sloppy edits and) run your latest version. I used USB-to-RS232 adapters, and found that your code has a bug that discards all data that it reads. So if you think that **select()** is always returning zero, then my comment to you 11 days ago about RS485 configuration is relevant again. – sawdust Dec 19 '19 at 22:19
  • Well then that is very helpful. Thanks Sawdust ... I will look in that area. – keith bradley Dec 19 '19 at 23:34

1 Answers1

0

Thanks to sawdust, I found the issue, and corrected some others!

The original SERmaster.c was select()'ing and read()'ing and discarding with a final select() which of course timed out due to no additional serial data when the message ended.

I had assumed select() only fired once and timed out.

Corrected SERmaster.c

#define responseSize    4584

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <termios.h>
//#include <linux/serial.h>
//#include <aio.h>
#include <sys/time.h>

#include "SER.h"


// array used to get termios BAUD.
const
int       BAUDarray[9] = {  0,         // not used.
                            B4800,     // 208
                            B9600,     // 104
                            B19200,    //  52
                            B38400,    //  26
                            B57600,    //  17.363636
                            B115200,   //   8.727272
                            B230400,   //   4.363636
                            B460800    //   2.181818
                         };

// delay (in uS) per character transmitted.
//    1 start, Even parity, 7bits, 1 stop.
//    bit time (times 10 bits)
//    Plus one bit time between characters.
const
int       BAUDdelay[9] = {  0,         // not used.
                            2288,
                            1144,
                            572,
                            286,
                            191,
                            96,
                            48,
                            24
                         };

static    
char      response[4584];

static
unsigned  
int       respIndex;

static
struct    termios   newtio, oldtio;

extern
volatile
int       terminate;


static
int sendRecieve(SER* mySER, const char* msgBuffer, int msgCnt, int sendFlag, int receiveFlag)
{
  int       rtn;
  char      myChar;
  fd_set    myfds;

  struct
  timeval   tm_out;

  if (sendFlag == true)
  {
    while (1)
    {
      rtn = write(mySER->sfd, msgBuffer, msgCnt);
      if (rtn == -1)
      {
        if (errno == EINTR)
        {
          fprintf(stderr, "sendRecieve() - write() EINTR !\n");
          if (terminate == 1)
            break;                     // deal with SIGTERM !
          continue;                    // if not SIGTERM then retry.
        }
        else
        {
          fprintf(stderr, "sendRecieve() - write()\n%s\n", strerror(errno));
          return EXIT_FAILURE;
        }
      }
      else
      {
        if (rtn == msgCnt)
          break;
        else
        {
          fprintf(stderr, "sendRecieve() - write() returned less than msgCnt !\n");
          return EXIT_FAILURE;
        }
      }
    }
  }

  if (receiveFlag == true)
  {
    for (int i = 0; i < responseSize; i++)
      response[i] = '\0';
    respIndex = 0;

    // set our first select() time out for (x + 2) char times where x is what we sent via write().
    tm_out.tv_sec  = 0;
    tm_out.tv_usec = mySER->BAUDmult * (msgCnt + 2);

    while (1)
    {
      FD_ZERO(&myfds);
      FD_SET(mySER->sfd, &myfds);

      rtn = select(mySER->sfd + 1, &myfds, NULL, NULL, &tm_out);
      if (rtn == 0)
      {
        fprintf(stderr, "sendRecieve() - select() timeout!\n");
        return EXIT_FAILURE;
      }
      if (rtn == -1)
      {
        if (errno == EINTR)
        {
          if (terminate == 1)
          {
            fprintf(stderr, "sendRecieve() - select() EINTR, terminating!\n");
            return EXIT_FAILURE;
          }
          fprintf(stderr, "sendRecieve() - select() EINTR, restarting, tm_out.tv_usec = %d, remaining = %ld\n", mySER->BAUDmult * msgCnt, tm_out.tv_usec);
          continue;
        }
        else
        {
          fprintf(stderr, "sendRecieve() - select()\n%s\n", strerror(errno));
          return EXIT_FAILURE;
        }
      }
      // select() indicates ready for reading !!

      while (1)
      {
        rtn = read(mySER->sfd, &myChar, 1);
        if (rtn == -1)
        {
          if (errno == EINTR)
          {
            fprintf(stderr, "sendRecieve() - read() EINTR !\n");
            if (terminate == 1)
              return EXIT_FAILURE;
            continue;
          }
          else
          {
            fprintf(stderr, "sendRecieve() - read()\n%s\n", strerror(errno));
            return EXIT_FAILURE;
          }
        }
        if (rtn == 0)
        {
          fprintf(stderr, "sendRecieve() - read() returned 0 yet select() reported ready for reading ??? should never see this !\n");
          return EXIT_FAILURE;
        }
        // break from read while() loop to process the char.
        break;
      }// end read() while loop

      // save the new char.
      response[respIndex] = myChar;
      // point to the nest storage location.
      respIndex++;

      if (myChar == '\n')
        return EXIT_SUCCESS;

      // are we pointing beyond max buffer size?
      if (respIndex == responseSize)
      {
        fprintf(stderr, "sendRecieve() - exceeded response buffer size ... before message termination char!!\n");
        return EXIT_FAILURE;
      }

      // set our next select() time out for 2 char times based on baud rate.
      tm_out.tv_sec  = 0;
      tm_out.tv_usec = mySER->BAUDmult * 2;

    }//end select() while loop

    fprintf(stderr, "sendRecieve() - select/read outer while loop Dumped, should not see this ever !!\n");
    return EXIT_FAILURE;

  }// end if (receiveFlag == true)

  return EXIT_SUCCESS;
}


char* SERwrapperFunc(SER* mySER)
{
  char  myCharArray[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' };
  int   myCharArrayCountToSend = sizeof(myCharArray);

  sendRecieve(mySER, myCharArray, myCharArrayCountToSend, true, true);
  return response;
}


void serPrint()
{
  printf("NCCS = %d            OLD:              NEW:\n", NCCS);
  printf("c_iflag -        %08x          %08x\n", oldtio.c_iflag, newtio.c_iflag);
  printf("c_oflag -        %08x          %08x\n", oldtio.c_oflag, newtio.c_oflag);
  printf("c_cflag -        %08x          %08x\n", oldtio.c_cflag, newtio.c_cflag);
  printf("c_lflag -        %08x          %08x\n", oldtio.c_lflag, newtio.c_lflag);
  printf("c_line -         %08x          %08x\n", oldtio.c_line, newtio.c_line);
  printf("c_ispeed -       %08x          %08x\n", oldtio.c_ispeed, newtio.c_ispeed);
  printf("c_ospeed -       %08x          %08x\n", oldtio.c_ospeed, newtio.c_ospeed);

  printf("\n");

  printf("VINTR -                %02x                %02x\n", oldtio.c_cc[VINTR], newtio.c_cc[VINTR]);
  printf("VQUIT -                %02x                %02x\n", oldtio.c_cc[VQUIT], newtio.c_cc[VQUIT]);
  printf("VERASE -               %02x                %02x\n", oldtio.c_cc[VERASE], newtio.c_cc[VERASE]);
  printf("VKILL -                %02x                %02x\n", oldtio.c_cc[VKILL], newtio.c_cc[VKILL]);
  printf("VEOF -                 %02x                %02x\n", oldtio.c_cc[VEOF], newtio.c_cc[VEOF]);
  printf("VTIME -                %02x                %02x\n", oldtio.c_cc[VTIME], newtio.c_cc[VTIME]);
  printf("VMIN -                 %02x                %02x\n", oldtio.c_cc[VMIN], newtio.c_cc[VMIN]);
  printf("VSWTC -                %02x                %02x\n", oldtio.c_cc[VSWTC], newtio.c_cc[VSWTC]);
  printf("VSTART -               %02x                %02x\n", oldtio.c_cc[VSTART], newtio.c_cc[VSTART]);
  printf("VSTOP -                %02x                %02x\n", oldtio.c_cc[VSTOP], newtio.c_cc[VSTOP]);
  printf("VSUSP -                %02x                %02x\n", oldtio.c_cc[VSUSP], newtio.c_cc[VSUSP]);
  printf("VEOL -                 %02x                %02x\n", oldtio.c_cc[VEOL], newtio.c_cc[VEOL]);
  printf("VREPRINT -             %02x                %02x\n", oldtio.c_cc[VREPRINT], newtio.c_cc[VREPRINT]);
  printf("VDISCARD -             %02x                %02x\n", oldtio.c_cc[VDISCARD], newtio.c_cc[VDISCARD]);
  printf("VWERASE -              %02x                %02x\n", oldtio.c_cc[VWERASE], newtio.c_cc[VWERASE]);
  printf("VLNEXT -               %02x                %02x\n", oldtio.c_cc[VLNEXT], newtio.c_cc[VLNEXT]);
  printf("VEOL2 -                %02x                %02x\n", oldtio.c_cc[VEOL2], newtio.c_cc[VEOL2]);

  printf("\n");
  printf("\n");
}


SER* SERinit(const char* strPort, int myBAUD)
{
  SER* mySER;

  //------------------------------------------------------------
  // create the global SER struct instance.
  if ((mySER = malloc(sizeof(SER))) == NULL)
  {
    fprintf(stderr, "SERinit() - mySER malloc()\n%s\n", strerror(errno));
    return NULL;
  }
  memset(mySER, 0, sizeof(SER));

  //------------------------------------------------------------
  // setup the BAUD.
  mySER->BAUDindex = myBAUD;
  mySER->BAUDvalue = BAUDarray[myBAUD];
  mySER->BAUDmult  = BAUDdelay[myBAUD];

  //------------------------------------------------------------
  // open the serial port.
  mySER->sfd = open(strPort, O_RDWR | O_NOCTTY);
  if (mySER->sfd < 0)
  {
    fprintf(stderr, "SERInit() - open()\n%s\n", strerror(errno));
    free(mySER);
    return NULL;
  }

  //------------------------------------------------------------
  // save old port settings for when we exit.
  tcgetattr(mySER->sfd, &oldtio);

  //------------------------------------------------------------
  // prepare the newtio struct with current settings.
  newtio = oldtio;

  //------------------------------------------------------------
  // set BAUD
  if (cfsetspeed(&newtio, B9600) != 0)//mySER->BAUDvalue
  {
    fprintf(stderr, "SERInit() - cfsetspeed()\n%s\n", strerror(errno));
    free(mySER);
    return NULL;
  }

  //------------------------------------------------------------
  // set for non-canonical (raw).
  cfmakeraw(&newtio);

  newtio.c_cflag |= (CLOCAL | CREAD);
  newtio.c_cflag &= ~(CRTSCTS | CSTOPB);

  // read() blocks until one char or until 100 mS timeout.
  newtio.c_cc[VTIME]  = 1;
  newtio.c_cc[VMIN]   = 1;

  // flush the toilet.
  tcflush(mySER->sfd, TCIFLUSH);

  // write new port settings.
  tcsetattr(mySER->sfd, TCSANOW, &newtio);

  serPrint();

  return mySER;
}


void SERclose(SER* mySER)
{
  // restore old port settings.
  tcsetattr(mySER->sfd, TCSANOW, &oldtio);
  close(mySER->sfd);
}