Solved

Problem in serial programming in linux

Posted on 2004-04-16
1
599 Views
Last Modified: 2008-02-01
I am currently writing a serial module for receiving binary data from a micro-controller board. The micro-controller board uses the setting of 9600baud, 8N1 for transfer. Based on various programming-HOW-TO, i wrote a serial module which can be able to receive data. However, I found that the data received is wrong. The error is that the most significant bit of each byte is always equal to 0. It is ok for transferring ASCII character, but all the binary data are wrong. I tried to debug again and again and i still can't figure out the error. As the deadline of my project comes, i urgently need to fix it.
Thanks a lot in advance. I greatly appreciate any help!

Here are the coding:
#ifndef SERIALDATA_H
#define SERIALDATA_H

#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <errno.h>
#include <qobject.h>
#include <string>
#include <vector>

using namespace std;

class SerialData : public QObject
{
  Q_OBJECT;
 public:
  SerialData(QObject* parent = 0, const char* name = 0, const char* port = 0);
  enum BaudRateEnum { BAUD_50    = B50,
                  BAUD_75    = B75,
                  BAUD_110   = B110,
                  BAUD_134   = B134,
                  BAUD_200   = B200,
                  BAUD_300   = B300,
                  BAUD_600   = B600,
                  BAUD_1200  = B1200,
                  BAUD_2400  = B2400,
                  BAUD_4800  = B4800,
                  BAUD_9600  = B9600,
                  BAUD_19200 = B19200,
                  BAUD_38400 = B38400 };

  enum ParityEnum { PARITY_7E1, PARITY_8N1 };
  enum FlowControlEnum { HARDWARE, SOFTWARE, NONE };
  static const BaudRateEnum DEFAULT_BAUD_RATE;
  static const ParityEnum DEFAULT_PARITY_MODE;
  static const FlowControlEnum DEFAULT_FLOW;
 
 public slots:
  void setBaudRate(const BaudRateEnum baudRate);
  void setParity(const ParityEnum parityMode);
  void setFlowControl(const FlowControlEnum flowCtrl);
  void readOp();
  void writeByte(unsigned char byte);
  unsigned char readByte();

  bool checkHwBuffer(); // check serial port hardware buffer
         

 private:
  void openPort(const char* port, const BaudRateEnum baudRate,
            const ParityEnum parityMode, const FlowControlEnum flowCtrl);
 
  int fd;                   // file descriptor
  int bytes;                // number of bytes available for reading in the port
  struct termios settings;  // serial port settings
   char buffer[256];
};

#endif

#include "serialdata.h"
#include <iostream>

const SerialData::BaudRateEnum SerialData::DEFAULT_BAUD_RATE = BAUD_9600;
const SerialData::ParityEnum SerialData::DEFAULT_PARITY_MODE = PARITY_8N1;
const SerialData::FlowControlEnum SerialData::DEFAULT_FLOW   = NONE;


SerialData::SerialData(QObject* parent, const char* name, const char* port)
  : QObject(parent, name)
{
  bytes = 0;
  openPort(port, DEFAULT_BAUD_RATE, DEFAULT_PARITY_MODE, DEFAULT_FLOW);
}


// set the baud rate
void SerialData::setBaudRate(const BaudRateEnum baudRate)
{
  cfsetispeed(&settings, baudRate);
  cfsetospeed(&settings, baudRate);
}


// set the parity mode (7E1, 8N1)
void SerialData::setParity(const ParityEnum parityMode)
{
  if (parityMode == PARITY_7E1)
    {
      settings.c_cflag |= PARENB;
      settings.c_cflag &= ~PARODD;
      settings.c_cflag &= ~CSTOPB;
      settings.c_cflag &= ~CSIZE;
      settings.c_cflag |= CS7;
    }
  else if (parityMode == PARITY_8N1)
    {
      settings.c_cflag &= ~PARENB;
      settings.c_cflag &= ~CSTOPB;
      settings.c_cflag &= ~CSIZE;
      settings.c_cflag |= CS8;
    }
  settings.c_iflag |= (INPCK | ISTRIP);
}


// set flow control mode
void SerialData::setFlowControl(const FlowControlEnum flowCtrl)
{
  if (flowCtrl == HARDWARE)
    {
      settings.c_cflag |= CRTSCTS;
      settings.c_cflag &= ~(IXON | IXOFF | IXANY);
    }
  else if (flowCtrl == SOFTWARE)
    {
      settings.c_cflag &= ~CRTSCTS;
      settings.c_cflag |= (IXON | IXOFF | IXANY);
    }
  else if (flowCtrl == NONE)
    {
      settings.c_cflag &= ~CRTSCTS;
      settings.c_cflag &= ~(IXON | IXOFF | IXANY);
    }

}


// check serial port hardware buffer
bool SerialData::checkHwBuffer()
{
  if (ioctl(fd, FIONREAD, &bytes) == -1)
    cerr << "Error in ioctl" << endl;
  return bytes > 0;
}


// read int(bytes) to the buffer and store to the messages
void SerialData::readOp()
{
 
}

void SerialData::writeByte(unsigned char byte)
{
  while (true)
    {
      int byteWrite = write(fd, &byte, 1);
      if (byteWrite == -1)
      cerr << "Error in writing" << endl;
      if (byteWrite == 1)
      break;
    }  
}

unsigned char SerialData::readByte()
{
  unsigned char c;
  while (true)
    {
      int byteRead = 0;
      if (ioctl(fd, FIONREAD, &bytes) == -1)
      cerr << "Error in ioctl" << endl;
      if (bytes > 0)
      byteRead = read(fd, &c, 1);
      if (byteRead == -1)
      cerr << "Error in reading" << endl;
      if (byteRead == 1)
      break;
    }
  //cout << c << endl;
  return c;
}

// open the serial port with inputting port name
void SerialData::openPort(const char* port, const BaudRateEnum baudRate,
                    const ParityEnum parityMode, const FlowControlEnum flowCtrl)
{
  fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);
  if (fd == -1)
    perror("Error in opening the port");
  else
    fcntl(fd, F_SETFL, 0);
  tcgetattr(fd, &settings);
  settings.c_cflag |= CLOCAL | CREAD;
  setBaudRate(baudRate);
  setParity(parityMode);
  setFlowControl(flowCtrl);
  settings.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // set raw data mode
  tcsetattr(fd, TCSANOW, &settings);
}
0
Comment
Question by:mhcnet
1 Comment
 
LVL 10

Accepted Solution

by:
Mercantilum earned 125 total points
Comment Utility
One bit is probably taken by parity, handled by the driver if you chose 7E1 or 7O1 in setParity.
In this case after checking parity the MSb is probably set to 0.
1. Try to change your parity settings.

If using 8N1 parity you still get 7 data bits, encode for writing using Base64 or base128.
The algorithm is easy to implement if you don't have one available.
0

Featured Post

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

Have you ever been frustrated by having to click seven times in order to retrieve a small bit of information from the web, always the same seven clicks, scrolling down and down until you reach your target? When you know the benefits of the command l…
The purpose of this article is to fix the unknown display problem in Linux Mint operating system. After installing the OS if you see Display monitor is not recognized then we can install "MESA" utilities to fix this problem or we can install additio…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now