• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 609
  • Last Modified:

Problem in serial programming in linux

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
mhcnet
Asked:
mhcnet
1 Solution
 
MercantilumCommented:
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

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now