Click here to Skip to main content
15,074,181 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
My Linux C application cannot receive bytes from Arduino

Hi all, I intend to use Arduino Mega 2560 as a programmer for AT89S52 (a family of 8051 microprocessor). The Arduino board connects to PC via USB Serial cable.

At first I need to write a program in my Ubuntu to communicate with Arduino board. My program can open connection and write bytes to Arduino properly (I tested by turning led on/off), but the problem is that the Linux program cannot receive data from Arduino.
I already searched through many tutorials and forums but still cannot resolve the problem, so I post question here and hope that someone can help me.

- Below is my functon used to open connection to device
C++
AT89S_EID
usbserial_open ( char* dev_name,
                 UsbSerialDevice* dev_ptr,
                 int baudrate,
                 int config )
{
    speed_t io_baudrate = B9600;

    if (dev_name == NULL || dev_ptr == NULL)
    {
        return AT89S_EID_ARG_NULL;
    }

    if (baudrate != US_BAUDRATE_9600
        || baudrate != US_BAUDRATE_19200
        || baudrate != US_BAUDRATE_115200)
    {
        return AT89S_EID_SERIAL_BAUDRATE_INVALID;
    }

    if (config != US_CONFIG_8N1
        || config != US_CONFIG_7E1
        || config != US_CONFIG_7O1)
    {
        return AT89S_EID_SERIAL_CONFIG_INVALID;
    }

    // store device name
    strcpy(dev_ptr->name, dev_name);

    // open device
    dev_ptr->fd = open (dev_ptr->name,
                        O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
    if (dev_ptr->fd < 0)
    {
        return AT89S_EID_SERIAL_OPEN;
    }

    // get current termios settings
    if (tcgetattr(dev_ptr->fd, &dev_ptr->tios) < 0)
    {
        return AT89S_EID_SERIAL_GET_ATTR;
    }

    // set input/output baudrdate
    if (baudrate == US_BAUDRATE_9600)
        io_baudrate = B9600;
    else if (baudrate == US_BAUDRATE_19200)
        io_baudrate = B19200;
    else if (baudrate == US_BAUDRATE_115200)
        io_baudrate = B115200;

    if (cfsetispeed(&dev_ptr->tios, io_baudrate) != 0
        || cfsetospeed(&dev_ptr->tios, io_baudrate) != 0)
    {
        return AT89S_EID_SERIAL_SET_IOSPEED;
    }

    // enable receiver, ignore status line
    dev_ptr->tios.c_cflag |= (CREAD | CLOCAL);
    // set config
    if (config == US_CONFIG_8N1)
    {
        dev_ptr->tios.c_cflag &= ~PARENB;
        dev_ptr->tios.c_cflag &= ~CSTOPB;
        dev_ptr->tios.c_cflag &= ~CSIZE;
        dev_ptr->tios.c_cflag |= CS8;
    }
    else if (config == US_CONFIG_7E1)
    {
        dev_ptr->tios.c_cflag |= PARENB;
        dev_ptr->tios.c_cflag &= ~PARODD;
        dev_ptr->tios.c_cflag &= ~CSTOPB;
        dev_ptr->tios.c_cflag &= ~CSIZE;
        dev_ptr->tios.c_cflag |= CS7;
    }
    else if (config == US_CONFIG_7O1)
    {
        dev_ptr->tios.c_cflag |= PARENB;
        dev_ptr->tios.c_cflag |= PARODD;
        dev_ptr->tios.c_cflag &= ~CSTOPB;
        dev_ptr->tios.c_cflag &= ~CSIZE;
        dev_ptr->tios.c_cflag |= CS7;
    }

    // no HW flow control
    dev_ptr->tios.c_cflag &= ~CRTSCTS;

    // no input processing (raw input)
    dev_ptr->tios.c_iflag &= ~(IXON | IXOFF | IXANY);
    // other input settings
    dev_ptr->tios.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);

    // no output processing (raw output)
    dev_ptr->tios.c_oflag &= ~OPOST;

    // control character settings
    dev_ptr->tios.c_cc[VMIN]  = 1; // wait for 1 minimum chacacter received
    dev_ptr->tios.c_cc[VTIME] = 0; // no timeout when waiting for charater

    // commit new settings
    if (tcsetattr(dev_ptr->fd, TCSANOW, &dev_ptr->tios) < 0)
    {
        return AT89S_EID_SERIAL_SET_ATTR;
    }

    // wait for device reset & sync up
    usleep(1500 * 1000);

    return AT89S_EID_OK;
} /* usbserial_open */


- And this is the receiving function:
C++
AT89S_EID
usbserial_recv ( UsbSerialDevice* dev_ptr,
                 unsigned char* data_ptr,
                 int data_len )
{
    int read_byte = 0;
    char b[1];

    if (dev_ptr == NULL
        || data_ptr == NULL)
    {
        return AT89S_EID_ARG_NULL;
    }

    // block reading
    fcntl(dev_ptr->fd, F_SETFL, 0);

    // start receiving data
    while (read_byte < data_len)
    {
        if (read(dev_ptr->fd, b, 1) > 0)
        {
            data_ptr[read_byte++] = *b;
        }
        else
        {
            if (errno == EAGAIN)
                continue;
            else if (errno == ETIMEDOUT)
                break;
            else
                return AT89S_EID_SERIAL_RECV;
        }
    }

    return AT89S_EID_OK;
} /* usbserial_recv */


So sorry for posting a long code :)

What I have tried:

I already searched through many tutorials and forums but still cannot resolve the problem. I believe that the Arduino code is working fine because I used some other tools to test it (e.g.: minicom)
Posted
Updated 5-Mar-16 18:10pm
v5
Comments
[no name] 4-Mar-16 1:21am
   
Have you used another program (eg PuTTY http://www.putty.org/) to confirm the Arduino is actually sending bytes?
William Dang 4-Mar-16 1:35am
   
yes, I already used minicom to test the Arduino code. So I think the problem is only in my code :)
Richard MacCutchan 4-Mar-16 4:18am
   
So what exactly is the problem? Have you stepped through the code with your debugger to see where it is failing?
William Dang 5-Mar-16 11:34am
   
I did not use any debugger :). Can you suggest me some of debuggers for Atmega under linux, please?
Jochen Arndt 4-Mar-16 7:01am
   
At first a maybe stupid question:
Is the Arduino sending something when not writing before?
Or do you write something before?

When there is nothing received the read() call should block forever. Is that the case or is the loop left due to an error?

Is the receive function called from another thread? If not, the blocking should lockup your whole program.

Your read error checking seems not to match cases that can occur:
- EAGAIN would only occur when the fd is set to non-blocking and the call would block.
- ETIMEDOUT should never occur with VTIME == 0 (indefinite wait)
William Dang 5-Mar-16 11:37am
   
I successfully sent 256 bytes to Arduino. Then Arduino responded back to linux program 256 bytes, but the linux program only received 1 byte.
Yes, the receive function is called from another thread.

1 solution

I resolved my problem. Just add flush function when open the connection to device, everything can be working fine.
C++
tcflush(fd, TCIOFLUSH);
   

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900