1

I'm trying to connect to an Arduino Mega 2560 unit connected via USB serial port in my Linux based PC.

Using C code, I'm trying to send and receive simple text strings, just I'm able to send and receive on both sides.

On Arduino:

int incomingByte = 0;    // for incoming serial data

void setup() {
    Serial.begin(19200);    // opens serial port, sets data rate to 9600 bps
}

void loop() {
  // send data only when you receive data:
  if (Serial.available() > 0) {

    // read the incoming byte:
    incomingByte = Serial.read();

    // say what you got:
    Serial.print((char)incomingByte);
  }

}

Basically just a loop that checks if there is serial data, and if so reads it and prints it back. there's a (char) conversion so I'll see right away the sent data is what I got back (Linux side)

For the Linux code I use the pretty standard code for opening a port which I found here

I call the Arduino "Table" as it will eventually operate a moving table through USB commands.

C file:

#include "TableFunctions.h"

bool connected=false;
int fd;
char *portname;


int set_interface_attribs (int fd, int speed, int parity)
{
        connected=false;
        struct termios tty;
        struct termios tty_old;
        memset(&tty, 0, sizeof tty);
        if (tcgetattr (fd, &tty) != 0)
        {
                printf("PC: Error %d from tcgetattr  \n", errno);
                return -1;
        }
        tty_old = tty;

        cfsetospeed (&tty, (speed_t)B19200);
        cfsetispeed (&tty, (speed_t)B19200);

        //tty.c_cflag |= B19200;
        tty.c_cflag     &=  ~PARENB;            // Make 8n1
        tty.c_cflag     &=  ~CSTOPB;
        tty.c_cflag     &=  ~CSIZE;
        tty.c_cflag     |=  CS8;

        tty.c_cflag     &=  ~CRTSCTS;           // no flow control
        tty.c_cc[VMIN]   =  1;                  // read doesn't block
        tty.c_cc[VTIME]  =  5;                  // 
        tty.c_cflag     |=  CREAD | CLOCAL;     // turn on READ & ignore ctrl lines
        cfmakeraw(&tty);
        tcflush( fd, TCIFLUSH );

        if (tcsetattr (fd, TCSANOW, &tty) != 0)
        {
                printf("PC: Error %d from tcsetattr  \n", errno);
                return -1;
        }
        return 0;
}

void set_blocking(int fd, int should_block)
{
        struct termios tty;
        memset(&tty, 0, sizeof tty);
        if (tcgetattr (fd, &tty) != 0)
        {
                printf("PC: Error %d from tggetattr  \n", errno);
                return;
        }

        tty.c_cc[VMIN]  = should_block ? 1 : 0;
        tty.c_cc[VTIME] = 10;            // 0.5 seconds read timeout

        if (tcsetattr (fd, TCSANOW, &tty) != 0)
                printf("PC: Error %d setting term attributes  \n", errno);
}


void OpenSerialPort()
{
    char *portname = "/dev/ttyACM0";

    printf("PC: Opening port to table \n");

    int fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);

    usleep(2000000);
    if (fd < 0)
    {
        printf("PC: Error %d opening %s: %s  \n", errno, portname, strerror(errno));
        return;
    }

    set_interface_attribs(fd, B19200, 0);  // set speed to 19,200 bps, 8n1 (no parity)
    set_blocking(fd, 0);                // set no blocking
    printf("PC: Connected\n");
    connected = true;
}
void PrepareWriteCommand(int numberOfCommands, const char *commands[numberOfCommands])
{
    if(connected) //check if arduino still connected
    {
        for(int i = 0; i<numberOfCommands; i++) //go through commands 
        {
            int bufferSize = strlen(commands[i]); //get the buffer size needed for this command
            char charArray[bufferSize]; //helper char array
            memcpy(charArray,commands[i],bufferSize);//copy command to the char array
            charArray[bufferSize]=0; //make sure there is a stop symbok at the end
            WriteSerialPort(charArray); //command is ready to be sent, send it.
        }
    }
}
int WriteSerialPort(const char *buffer)
{
    printf("PC: Now writing: ");
    int n_written = 0; //how many bytes were written

    n_written = write(fd, buffer, strlen(buffer)); //write the command and return how many bytes were written

    printf("\n");

    //check bytes send and return ouput (error, nothing or x bytes sent)
    if(n_written<0)
    {
        printf("PC: Error %d from %s \n",errno, strerror(errno));
    }
    else if(n_written == 0)
    {
        printf("PC: Nothing was written  \n");
    }
    else
    {
        printf("PC: Written %i bytes  \n", n_written);
    }

}

int ReadSerialPort(char *buffer, unsigned int buff_size)
{
    //check if arduino still connected
    if(connected)
    {
        //read the serial data
        if(read(fd,buffer,buff_size))
            return sizeof(buffer); //return how much bytes were read
        else
        {
            //else print nothing received
            printf("PC: Arduino not Connected (ReadSerialPort) \n");
        }
    }
}

In OpenSerialPort I basically open a new fd, and call the functions that set the communication settings.

I use PrepareWriteCommand to make sure commands input from users are with a stop symbol and send them to WriteSerialPort where I use write() and print how many bytes were sent.

H file:

#include <errno.h>
#include <fcntl.h> 
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>


#define MAX_DATA_LENGTH 256

int set_interface_attribs (int fd, int speed, int parity);
void set_blocking(int fd, int should_block);
void OpenSerialPort();
void PrepareWriteCommand(int numberOfCommands, const char *commands[numberOfCommands]);
int WriteSerialPort(const char *buffer);
int ReadSerialPort(char *buffer, unsigned int buff_size);

Main:

    #include "TableFunctions.h"
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
    {
        char output[MAX_DATA_LENGTH]; //char array to hold arduino output
        int received = 0; // check if read() got any bytes
        const char* commands[]={"test"}; //test command

        OpenSerialPort(); // open serial port

        PrepareWriteCommand((sizeof(commands)/sizeof(commands[1])),commands); //prepare command for sending

        usleep(500000); //wait for arduino response

        while(true)
{
    received = ReadSerialPort(output,MAX_DATA_LENGTH);//check serial port for response
    switch(received)
    {
        case -1:
        {
            printf("PC: Error %d from %s \n",errno, strerror(errno));
            break;
        }
        case 0:
        {
            printf("PC: Nothing received\n");
            usleep(500000);
            break;
        }
        default:
        {
             printf("PC: received %i\n",received); //if yes, how many bytes
            printf("PC: %s\n",output); //and what was received
            usleep(500000);
        }
    }
}
return 0; //finish program

I tried tweaking the TTY flags settings with no success. Each time I run the C code I see the Arduino resets (and after opening a new fd I give it some time for bootloading) but no communication is sent between the two.

Output:

PC: Opening port to table 
PC: Connected
testPC: Now writing: 
PC: Written 4 bytes  

PC: received 0
PC: 

Any help with understanding why the C code can't communicate with the Arduino will be highly appreciated!

gre_gor
  • 6,669
  • 9
  • 47
  • 52
  • Your `received` variable is never assigned. Also you are not checking properly the return value of `read()`: it is the number of bytes read or `-1` if error. And `sizeof(buffer)` will return the size of the pointer, not the size of the array or the number of bytes read. – rodrigo Jan 14 '19 at 11:22
  • @rodrigo Thanks, never noticed received not assigned. Now the input to linux is: PC: received 8 PC: So PC gets 8 bytes (yet sends 4, maybe the arduino manages to send the data twice), but prints nothing. Just to make sure, read() puts the read data into the buffer in its parameter, right? About sizeof - I looked and seems there's nothing simple to do about that:https://stackoverflow.com/questions/492384/how-to-find-the-sizeof-a-pointer-pointing-to-an-array – the-friendly-dude Jan 14 '19 at 11:40
  • silly me, 8 bytes are the size of the pointer, isn't it? – the-friendly-dude Jan 14 '19 at 11:57
  • Yes, `sizeof(pointer)` will be 8 in a 64-bit system. `read` puts the data read into the array passed as argument, and returns the number of bytes actually read. The second argument is the size of the buffer, that is the maximum number of bytes read. – rodrigo Jan 14 '19 at 13:24

1 Answers1

0

Problem was in OpenSerialPort(). I set another variable fd which is local, thus given priority. then when OpenSerialPort() is done, it is deleted, and the global fd remain unset. This is why I can't send anything from or to the PC.

Thanks.

mehdi
  • 340
  • 4
  • 17