1

I'm trying to connect to an arduino Mega At2560 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)
        {
            ReadSerialPort(output,MAX_DATA_LENGTH);//check serial port for response
            if(strlen(output)>0) //if anything received
            {
                printf("PC: received %i\n",received); //if yes, how many bytes
                printf("PC: %s\n",output); //and what was received
                usleep(500000);
            }
            else if(strlen(output)<=0) //else print nothing received
            {
                printf("PC: Nothing received\n");
            }
        }
        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!

13
  • 1
    Yes, but you can't use a parameter to set the size of a parameter. It makes no sense. You should be using const char **commands or const char *commands[] since you are using an array of pointers.
    – Majenko
    Commented Jan 14, 2019 at 12:18
  • 1
    regarding: ReadSerialPort(output,MAX_DATA_LENGTH); I doubt that the function: ReadSerialPort() terminates the input with a NUL byte, so any following calls that are expecting a NUL terminated array of characters will not work. I would expect that function returns a count of the number of characters read, which can be used to insert a NUL byte into the array output[] Commented Jan 15, 2019 at 7:16
  • 1
    regarding: ReadSerialPort(output,MAX_DATA_LENGTH); The posted code does not check the returned value from ReadSerialPort() AND the actual function: ReadSerialPort() fails to return an error status when (for instance) the port is not connected Commented Jan 15, 2019 at 7:22
  • 1
    regarding: printf("PC: Now writing: "); this data will stay in the output stream until something happens (like another call to printf() that (properly) has a '\n' as part of the data (perferably the last character output) forces the data to be passed to the terminal Commented Jan 15, 2019 at 7:26
  • 1
    to call to read() will let the code know if anything is there to read. Waiting some arbitrary time is not a good method. Much better to keep calling ReadSerialPort() until some data is seen Commented Jan 15, 2019 at 7:28

1 Answer 1

1

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.