?
Solved

Problem in serial programming in linux

Posted on 2004-04-16
1
Medium Priority
?
607 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
[X]
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
1 Comment
 
LVL 10

Accepted Solution

by:
Mercantilum earned 500 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

Prepare for your VMware VCP6-DCV exam.

Josh Coen and Jason Langer have prepared the latest edition of VCP study guide. Both authors have been working in the IT field for more than a decade, and both hold VMware certifications. This 163-page guide covers all 10 of the exam blueprint sections.

Question has a verified solution.

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

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…
Monitoring a network: how to monitor network services and why? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the philosophy behind service monitoring and why a handshake validation is critical in network monitoring. Software utilized …
Add bar graphs to Access queries using Unicode block characters. Graphs appear on every record in the color you want. Give life to numbers. Hopes this gives you ideas on visualizing your data in new ways ~ Create a calculated field in a query: …
Suggested Courses

777 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