1

I want to make two Raspberry Pi send message to each other using ZigBee protocol. I have connected XBee S2C (ZigBee) module to Raspberry Pi using USB Explorer (CH430g). I had written a python script which will do the desired work,

import serial ser = serial.Serial('/dev/ttyUSB0', 9600) while True: incoming = ser.readline().strip() print ('%s' %incoming.decode()) string = input("") + '\n' ser.write(string.encode()) 

But I need a C program to do the same, I looked into libserial library for C and C++, found that it's buggy and never compiled for me.

I tried this thread it works pretty well, but at the receiver side I need to keep read(fd, &buffer, sizeof(buffer)); in a while loop to continuously open for listening unlike a C socket program where read() function will halt till it receives the data just like my python script will wait in line incoming = ser.readline().strip() till it receives some message.

Is there any solution for it without using while loop ?

Edit 1:

In aforementioned python code, while loop is used to receive multiple messages. The line incoming = ser.readline().strip() will catch the message, process it and waits for next message since its in a while loop.

In C if my code is something like this:

while(1){ str = read(); //some processing } 

it throws error since read is not halting till it gets the data, it's just returning read fail. Since the read data is NULL the post processing of the data will throw an error. To make it work I have introduce another while loop like this:

 while(1){ while(1){ str = read(); if(str!=NULL) break; } //some processing } 

I want to eliminate this extra loop and make read() to wait for the message. PS: I'm opening serial device like this: uart0_filestream = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);

12
  • Why is this question C++, if you ask specificly for C? Commented Jul 31, 2018 at 9:23
  • The read() in the mentioned thread is blocking, will put the process in sleep waiting for data, so yes, you can use it within a loop (careful with the &buffer, it is the bug, look at the answer too). May I ask why if the python script is working do you need it in C? Commented Jul 31, 2018 at 9:28
  • @hellow I prefer C, but solution is available in C++ the I'm fine with it so. Commented Jul 31, 2018 at 9:40
  • @Alex Actually I don't want to use read() in a while loop since the code is just a part of other vast project. So I'm asking how I can avoid while loop or any library available for C/C++. As I said, its a part of a project, which should be in C/C++ I cant use python script in that. Commented Jul 31, 2018 at 9:41
  • @VinayakaSP I see now, sorry, you can configure the serial as non-blocking, you can use select() to do some other stuff while waiting for data, but I don't see how you can get rid of a loop if you are expecting more data Commented Jul 31, 2018 at 9:44

2 Answers 2

1

If you don't want the connection to be non-blocking, you probably want to remove the O_NDELAY option you've added to your call to open that turns on non-blocking. Just like this...

uart0_filestream = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY); 

Also, read doesn't return a string, it returns the number of bytes read in so your calls to read should look more like

bytecount = read(uart0_filestream, str, 20); if(bytecount>0) { str[bytecount]='\0'; } else { // Something bad happened? } 
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you ! seems this solution has solved my problem !
1

Get some inspiration from this code. This is very generic canonical serial programming using C.

NOTE: Canonical input processing can also handle the erase, delete word, and reprint characters, translate CR to NL, etc..


I suggest you to read this article in order to know more about the serial programming settings, different mode.

HowTo serial programming.

#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> #include <stdio.h> /* baudrate settings are defined in <asm/termbits.h>, which is included by <termios.h> */ #define BAUDRATE B38400 /* change this definition for the correct port */ #define SERIAL_DEVICE "/dev/ttyS1" #define FALSE 0 #define TRUE 1 volatile int STOP=FALSE; int main(void) { int fd,c, res; struct termios oldtio,newtio; char buf[255]; /* Open modem device for reading and writing and not as controlling tty because we don't want to get killed if linenoise sends CTRL-C. */ fd = open(SERIAL_DEVICE, O_RDWR | O_NOCTTY ); if (fd <0) {perror(SERIAL_DEVICE); exit(-1); } tcgetattr(fd,&oldtio); /* save current serial port settings */ memset(&newtio, sizeof(newtio)); /* clear struct for new port settings */ /* BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed. CRTSCTS : output hardware flow control (only used if the cable has all necessary lines. See sect. 7 of Serial-HOWTO) CS8 : 8n1 (8bit,no parity,1 stopbit) CLOCAL : local connection, no modem contol CREAD : enable receiving characters */ newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD; /* IGNPAR : ignore bytes with parity errors ICRNL : map CR to NL (otherwise a CR input on the other computer will not terminate input) otherwise make device raw (no other input processing) */ newtio.c_iflag = IGNPAR | ICRNL; /* Raw output. */ newtio.c_oflag = 0; /* ICANON : enable canonical input disable all echo functionality, and don't send signals to calling program */ newtio.c_lflag = ICANON; /* initialize all control characters default values can be found in /usr/include/termios.h, and are given in the comments, but we don't need them here */ newtio.c_cc[VINTR] = 0; /* Ctrl-c */ newtio.c_cc[VQUIT] = 0; /* Ctrl-\ */ newtio.c_cc[VERASE] = 0; /* del */ newtio.c_cc[VKILL] = 0; /* @ */ newtio.c_cc[VEOF] = 4; /* Ctrl-d */ newtio.c_cc[VTIME] = 0; /* inter-character timer unused */ newtio.c_cc[VMIN] = 1; /* blocking read until 1 character arrives */ newtio.c_cc[VSWTC] = 0; /* '\0' */ newtio.c_cc[VSTART] = 0; /* Ctrl-q */ newtio.c_cc[VSTOP] = 0; /* Ctrl-s */ newtio.c_cc[VSUSP] = 0; /* Ctrl-z */ newtio.c_cc[VEOL] = 0; /* '\0' */ newtio.c_cc[VREPRINT] = 0; /* Ctrl-r */ newtio.c_cc[VDISCARD] = 0; /* Ctrl-u */ newtio.c_cc[VWERASE] = 0; /* Ctrl-w */ newtio.c_cc[VLNEXT] = 0; /* Ctrl-v */ newtio.c_cc[VEOL2] = 0; /* '\0' */ /* now clean the modem line and activate the settings for the port */ tcflush(fd, TCIFLUSH); tcsetattr(fd,TCSANOW,&newtio); /* terminal settings done, now handle input In this example, inputting a 'z' at the beginning of a line will exit the program. */ while (STOP==FALSE) { /* loop until we have a terminating condition */ /* read blocks program execution until a line terminating character is input, even if more than 255 chars are input. If the number of characters read is smaller than the number of chars available, subsequent reads will return the remaining chars. res will be set to the actual number of characters actually read */ res = read(fd,buf,255); buf[res]=0; /* set end of string, so we can printf */ printf(":%s:%d\n", buf, res); if (buf[0]=='z') STOP=TRUE; } /* restore the old port settings */ tcsetattr(fd,TCSANOW,&oldtio); return 0; } 

1 Comment

Thank you for the suggestion, Definitely I'll go through it.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.