2

I'm working on a small Linux server (Ubuntu Server 13.04 running on a Beagleboard xM ARM computer) that will be communicating between a laptop wirelessly and an Arduino. The issue I seem to be having is regarding the communication between the Arduino and the Beagleboard. The program will run just fine for a certain amount of time, ~30 seconds or so, then it will halt. The program will stay running but the port apparently freezes.

The program I'm running is currently just a test program that will sweep a servo over a certain range. The code for the functions used to set up the ports was found here.

My program code is as follows, with exception of the code found in the separate thread:

    #include <errno.h>
    #include <termios.h>
    #include <stdio.h>
    #include <string.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <iostream>

    using namespace std;

   ...

   int main (int argc, const char* argv[]) {
        cout << "TestIO running...\n";
        char* portname = "/dev/ttyACM0";
        // Open serial port
        int fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);

        // Return error if port cannot be opened
        if (fd < 0)
        {
                cout << "error " << errno << " opening " <<  portname << ": " << strerror (errno) << "\n";
                return -1;
        }

        set_interface_attribs (fd, B9600, 0);   // set speed to 9600 bps, 8n1 (no parity)
        set_blocking (fd, 0);                   // set no blocking

        // Read from serial port
        //char inputBuffer[64];
        //int inputLength = read(fd, inputBuffer, sizeof inputBuffer);

        double output = 575;
        char outputString[255];
        char outputLength;
        int incrimentor = 1;
        char inChar;
        for(;;) {
                if (output >= 675 )
                        incrimentor = -1;
                else if (output <= 375)
                        incrimentor = 1;
                output += incrimentor;

                // Sweep wheels on car, set drive motor to 0
                outputLength = sprintf(outputString, "%0.2f", output);
                write(fd, outputString, outputLength);
                write(fd, ",", 1);
                write(fd, "0", 1);
                write(fd, "\n", 1);

                cout << outputString << "\n";

                // Sleep thread for 5000 uS (5 ms)
                usleep(5000);
        }
        close(fd);
        return 0;
}

On a slightly different note, when the program freezes I must force it to quit the code to close the port is never reached and thus I cannot run the program again to test it. I'm curious if anyone might know how to close a serial port through a Linux command run in the terminal.

Thanks!

Community
  • 1
  • 1
SuperUser320
  • 248
  • 1
  • 2
  • 10
  • It takes ~1ms to output 1 char at 9600 baud. You are sleeping for 5ms. How many characters are you outputting every 5ms? What flow control are you using? – Martin James Sep 30 '13 at 12:33
  • That's a good point, currently I'm sending six every loop, in the future I will be sending eight plus. However I tried delaying 10ms between loops, and this still ended in the same result. I didn't actually time it, but I think it may have run a little longer. This led me to believe there was a datatype being overflowed, but I looked and couldn't find one. As for flow control I'm not currently using any, the line is asynchronous. – SuperUser320 Oct 01 '13 at 11:59

1 Answers1

0

Referring your second issues on how to quit the hanging program:

Adding tests for the return value to all system calls is a good idea in general!

Be aware that read()/write() do not necessarily read in/write out as much data as the were told to.

Also read()/write() return if the process received a signal.

Here in particular add testing the result to the calls that might block (write()):

ssize_t writen(int fd, char * buffer, size_t size)
{
  ssize_t written_total = 0;
  ssize_t written = 0;

  while  (outputLength > written_total)
  {
    written = write(fd, buffer + written_total, size - written_total);
    if (-1 == written)
    {
      if (EINTR == errno)
      {
        /* interupted by signal -> break and leave */
        break;
      }
      elseif ((EAGAIN == errno) || (EWOULDBLOCK == errno))
      {
        continue; /* try again */
      }

      /* another error occured -> log, break and leave */

      break;
    }

    written_total += written;
  }

  if (outputLength > written_total)
  {
    if (-1 = written)
    {
      /* handle error */
    }
    else
    {
      /* notify of interruption */
    }
  }
  else
  {
    /* log succesfully transmission of all data */
  }

  return written_total;
}

int main()
{
  ...

  do
  {
    if (outputLength != writen(fd, outputString, outputLength))
    {
      fprintf(stderr, "writen(fd, outputString, outputLength) failed");
      break;
    }

    if (1 != writen(fd, ",", 1))
    {
      fprintf(stderr, "writen(fd, ",", 1)) failed");
      break;
    }

    if (1 != writen(fd, "0", 1))
    {
      fprintf(stderr, "writen(fd, "0", 1)) failed");
      break;
    }

    if (1 != writen(fd, "\n", 1))
    {
      fprintf(stderr, "writen(fd, "\n", 1)) failed");
      break;
    }
  } while (0);

  if (-1 == close(fd))
  {
    perror("close() failed");
  }

  ...
}

Note that the program also needs to have a signal handler registered (for SIGUSR1 for example) that does nothing, but "eating" the signal.

Then from the command line you could easily un-block the program by doing:

$ kill <program-pid> -SIGUSR1
alk
  • 69,737
  • 10
  • 105
  • 255
  • Thanks a ton! Seems to be working well, I'd upvote your answer but I don't have enough rep, so thanks! This will save me a ton of time now. – SuperUser320 Oct 01 '13 at 12:06