BeagleBoard serial port code

Hi,

I am currently having problems with my BeagleBoard when using it to
communicate with the COM port on it.

Here is a code that was written to communicate with the serial port on
the BeagleBoard. We are trying to get the BeagleBoard to communicate
with a NovAtel GPS. The command being sent from the BeagleBoard to the
GPS is log version as seen below in the codes I have included. This
command should give us a output of the version of the GPS and some
other information. But all we get is the following error:

[ 1215.394714] SysRq : HELP : loglevel(0-9) reBoot Crash terminate-all-
tasks(E) memory-full-oom-kill(F) kill-all-tasks(I) thaw-filesystmes(J)
saK show-memory-usage(M) nice-all-RT-tasks(N) powerOFF show-
registers(P) show-all-timers(Q) unRawSync show-task-states(T) Unmount
ETM buffer dump show-blocked-tasks(W) dump-ftrace-buffer(Z)

If you recognize this error message or have any suggestions for us
that would be most appreciated.

Below is all parts of the code being used for communication with the
COM port.

PART 1: main.cc

#include "Serial.hh"
#include "stdio.h"

int main(void)
{
  cout << "Begin" << endl;

  Serial port("/dev/ttyS0", Serial::BAUD_9600, 1);

  port.write("log bestxyz\r\n");

  char buf[200] = "";
  char eol = *"\n";
  int count = 0;
  usleep(1000000);

  for(int i=0; i<10; i++)
  {
    count += read(port.fd, buf, 200);

    if (i % 2 == 0)
    {
       for (int k=0; k<200; k++)
      {

        if(buf[k] == eol)
        {
          k=199;
          printf("\n");
        }

        else
        {
          printf("%c", buf[k]);
        }
      }

    }

  }

  printf("Read %d bytes.\n", count);

  port.close();
}

END PART 1

PART 2: Serial.cc

#include "Serial.hh"

Serial::Serial(const char* port, BaudRate baud, int flags)
{

  fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);

  if(fd == -1)
  {
    perror("Open port: unable to open the specified port");
  }

  if(flags)
  {
  fcntl(fd, F_SETFL, FNDELAY); //set non-blocking read
  }
  else
  {
   fcntl(fd, F_SETFL, 0); //set blocking read
  }

  termios port_settings ;
  if ( tcgetattr( fd, &port_settings ) < 0 )
  {
    cout << "Error getting port" << endl;
  }
  //
  // Set the baud rate for both input and
output.
  //
  if ( ( cfsetispeed( &port_settings, baud ) < 0 )
       >> ( cfsetospeed( &port_settings, baud ) < 0 ) )
  {
    cout << "Error setting baud" << endl;
  }
  //
  // Set the new attributes of the serial
port.
  //
  if ( tcsetattr( fd, TCSANOW, &port_settings ) < 0 )
  {
    cout << "Error applying settings" << endl;
  }
}

int Serial::write(const char* data)
{
  int n = ::write(fd, data, strlen(data));
  usleep(750);
  return n;
}

int Serial::read(char* buffer, int buflen)
{
  return ::read(fd, buffer, buflen);
}

int Serial::close()
{
  termios port_settings ;

     tcgetattr( fd, &port_settings ); // Get current options for the
port...
     cfsetispeed(&port_settings, B9600); // Set the baud rate for
input to 9600...
     cfsetospeed(&port_settings, B9600); // Set the baud rate for
output to 9600
     port_settings.c_cflag &= ~PARENB; // No Parity
     port_settings.c_cflag &= ~CSTOPB; // 1 stop bit
     port_settings.c_cflag &= ~CSIZE; // Mask the character size bits
     port_settings.c_cflag |= CS8; // 8 Data Bits
     port_settings.c_cflag &= ~CRTSCTS; // Hardware control disabled
     port_settings.c_cflag |= (CLOCAL | CREAD); // Enable the receiver
and set loval mode...
     tcsetattr( fd, TCSAFLUSH, &port_settings ); // Set the new
options for the port...

  return ::close(fd);
}

END PART 2

PART 3: Serial.hh

#ifndef SERIAL_H
#define SERIAL_H

#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 <iostream> //cout

using namespace std; //cout

class Serial
{
public:
  enum BaudRate {
    BAUD_50 = B50,
    BAUD_75 = B75,
    BAUD_110 = B110,
    BAUD_134 = B134,
    BAUD_150 = B150,
    BAUD_200 = B200,
    BAUD_300 = B300,
    BAUD_600 = B600,
    BAUD_1200 = B1200,
    BAUD_1800 = B1800,
    BAUD_2400 = B2400,
    BAUD_4800 = B4800,
    BAUD_9600 = B9600,
    BAUD_19200 = B19200,
    BAUD_38400 = B38400,
    BAUD_57600 = B57600,
    BAUD_115200 = B115200,
    BAUD_230400 = B230400,
    BAUD_460800 = B460800,
    BAUD_500000 = B500000,
    BAUD_576000 = B576000,
    BAUD_921600 = B921600,
    BAUD_1000000 = B1000000,
    BAUD_1152000 = B1152000,
    BAUD_1500000 = B1500000,
    BAUD_2000000 = B2000000,
    BAUD_2500000 = B2500000,
    BAUD_3000000 = B3000000,
    BAUD_3500000 = B3500000,
    BAUD_DEFAULT = BAUD_115200,
    BAUD_MAX = BAUD_3500000,
  };

  Serial(const char* port, BaudRate baud, int flags);

  int write(const char* data);
  int read(char* buffer, int buflen);
  int close();
  int fd;

private:
  BaudRate baud;
  int flags; //used for specifying blocking read

};

#endif

END PART 3

Thank you for any help you can offer.

Dear Brent,

It looks as though the GPS is sending a break condition, which is I believe
used to indicate that the magic SysRq key has been pressed.

You could try disabling the SysRq key with:

  sysctl -w kernel.sysrq=0

or

  echo 0 > /proc/sys/kernel/sysrq

(for some more discussion see
http://www.tldp.org/HOWTO/Remote-Serial-Console-HOWTO/security-sysrq.html ).

However, if I understand your setup correctly, you may wish to change the
console= line in the bootloader so that /dev/ttyS2 (or /dev/ttyO2 depending
on kernel version) isn't mentioned at all; otherwise, console output from
the kernel will be pushed down the serial port even if an application is
using it.

Hope that helps,

Dear Laurence,

I disabled the SysRq key as you suggested and I don't get that error
message anymore.

However I still get messages from the GPS saying "ERROR: Invalid
Message ID". I get that multiple times even if I just make one
request. Besides, the number of bytes received is inconsistent each
time I run the program. Therefore I believe that you're right when you
say that the output from the kernel is being pushed down the serial
port. Somehow the BeagleBoard is sending "extra" information to the
GPS. Now, to change the "console=" line in the bootloader, do I have
to reinstall Linux completely? Or can I just access the bootloader
from the minicom? What command should I issue to the bootloader to
change that?

Thank you very much,

Brent Cummings