Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

Problem in serial programming in linux

Posted on 2004-04-16
1
603 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
ID: 10848753
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

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

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…
The purpose of this article is to demonstrate how we can upgrade Python from version 2.7.6 to Python 2.7.10 on the Linux Mint operating system. I am using an Oracle Virtual Box where I have installed Linux Mint operating system version 17.2. Once yo…
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…

792 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