I have connected an HC-05 bluetooth module to microZed board and trying to send and receive data via uart in Linux, Now the the send code is working when I send data from my board to the app it works perfectly given below is my code for sending
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <pthread.h> /* for threads */
#include <termios.h> /* uart */
#include <fcntl.h> /* uart */
#include <unistd.h> /* uart */
#define MODEMDEVICE "/dev/ttyPS1"
int main()
{
printf("Opening %s\n", MODEMDEVICE);
int portfd = open(MODEMDEVICE, O_RDWR | O_NOCTTY);
if (portfd < 0) {
printf("ERROR coultn't open %s\n", MODEMDEVICE);
return -1;
}
/* set terminal settings */
struct termios tty;
tcgetattr(portfd, &tty);
cfsetospeed(&tty, (speed_t)B9600);
cfsetispeed(&tty, (speed_t)B9600);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
tty.c_iflag = IGNBRK;
tty.c_lflag = ICANON;
tty.c_oflag = 0;
tty.c_cflag |= CLOCAL | CREAD;
tty.c_cc[VTIME] = 0;
tty.c_cc[VMIN] = 1;
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
tty.c_cflag &= ~(PARENB | PARODD);
tty.c_cflag |= PARENB;
tty.c_cflag &= ~CSTOPB;
tcsetattr(portfd, TCSANOW, &tty);
/* sleep a bit */
usleep(200000);
/* flush possible characters in the input buffer */
tcflush(portfd, TCIOFLUSH);
char buf;
int i;
while(1) {
buf++;
write(portfd, &buf, 1);
write(portfd, "\r\n", 2);
usleep(200000);
}
return 0;
}
Now the problem arises when I try send data from the app to the Bluetooth module , sometimes the program stops and says "random nonblocking pool initialized" or it gets stuck at i = read(portfd, buf, 20); in the code given below
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <pthread.h> /* for threads */
#include <termios.h> /* uart */
#include <fcntl.h> /* uart */
#include <unistd.h> /* uart */
#define MODEMDEVICE "/dev/ttyPS1"
int main()
{
printf("Opening %s\n", MODEMDEVICE);
int portfd = open(MODEMDEVICE, O_RDWR | O_NOCTTY);
if (portfd < 0) {
printf("ERROR coultn't open %s\n", MODEMDEVICE);
return -1;
}
printf("hello1\n\r");
/* set terminal settings */
struct termios tty;
tcgetattr(portfd, &tty);
cfsetospeed(&tty, (speed_t)B9600);
cfsetispeed(&tty, (speed_t)B9600);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
tty.c_iflag = IGNBRK;
tty.c_lflag = ICANON;
tty.c_oflag = 0;
tty.c_cflag |= CLOCAL | CREAD;
tty.c_cc[VTIME] = 0;
tty.c_cc[VMIN] = 1;
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
tty.c_cflag &= ~(PARENB | PARODD);
tty.c_cflag |= PARENB;
tty.c_cflag &= ~CSTOPB;
tcsetattr(portfd, TCSANOW, &tty);
/* sleep a bit */
printf("hello2\n\r");
usleep(200000);
/* flush possible characters in the input buffer */
tcflush(portfd, TCIOFLUSH);
char buf[20];
printf("hello3\n\r");
int i;
while(1) {
i = read(portfd, buf, 20);
printf("hello\n\r");
buf[i] = 0;
printf("%s", buf);
printf("\n\r");
}
return 0;
}
Any suggestions how can I fix this ?
I found the solution , first mistake was pointed out by this post .
I should have set time to wait for character read to greater than 0 and minimum number of characters to read to zero
tty.c_cc[VTIME] = 5;
tty.c_cc[VMIN] = 0;
and I needed to set the tty.c_lflag flag to 0 to enable raw input instead of canonical, now the code is reading the data constantly
Related
I have a simple test program which waits for a set of 3 characters to be sent to the USB port (0x10, 0x04 and 0x02) and then should respond with "Hello World". For some reason, the first character is missed off the response so I only see "ello World".
I am using the USB-OTG port with modprobe g_serial for communication if that makes any difference.
What am I missing?
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <sys/poll.h>
#include <sys/ioctl.h>
#include <linux/usb/g_printer.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#define ODROID_SERIAL_GADGET "/dev/ttyGS0"
#define BUF_SIZE 1024
int main()
{
struct pollfd fd[0];
struct termios tty;
int timeover=1000;
static char buf[BUF_SIZE];
char obuff[] = ".";
int ox10Found, ox04SeqeunceFound, i;
int bytes_read, retval;
int max_read_time = 2; /* units of 250ms after which incoming data times out - 1 causes larger files to be split */
fd[0].fd = open(ODROID_SERIAL_GADGET, O_RDWR);
if (fd[0].fd < 0) {
printf("Error %d opening %s\n", fd[0].fd, ODROID_SERIAL_GADGET);
close(fd[0].fd);
return(-1);
}
tcgetattr(fd[0].fd,&tty); /* save current serial port settings */
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); // Enable canonical input - we need to read contorol characters
tty.c_oflag = 0; // no output processing
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= 0;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
tcsetattr(fd[0].fd,TCSANOW,&tty);
fd[0].events = POLLIN | POLLRDNORM;
ox10Found=0;
ox04SeqeunceFound=0;
while (1) {
/* Wait for up to 1/4 second for data. */
retval = poll(fd, 1, 250);
timeover++;
if (timeover>1000) {
timeover=max_read_time+1;
}
if (retval) {
bytes_read = read(fd[0].fd, buf, BUF_SIZE);
if (bytes_read < 0) {
/* Open device file for serial gadget. */
printf("Error %d reading from %s\n",fd[0].fd, ODROID_SERIAL_GADGET);
close(fd[0].fd);
return(-1);
}
for (i = 0; i < bytes_read; i++) {
if (buf[i]==0x10 && !ox10Found && !ox04SeqeunceFound) {
ox10Found=1;
continue;
} else if (buf[i]==0x04 && ox10Found) {
ox04SeqeunceFound=1;
continue;
} else {
ox10Found=0;
}
if (buf[i]==0x02 && ox04SeqeunceFound) {
write(fd[0].fd, "Hello World", 11);
tcdrain(fd[0].fd); // Wait for output
}
}
}
}
}
I am trying to listen to a serial port with a C program utilizing CRTSCTS (to prevent an independently powered Arduino from rebooting after the computer it is connected to restarts).
I started with the code from here: Canonical Mode Linux Serial Port
After some adaptations it looks like this:
#define SERIALTERMINAL "/dev/ttyUSB0"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
int set_interface_attribs(int fd, int speed)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
printf("Error from tcgetattr: %s\n", strerror(errno));
return -1;
}
cfsetospeed(&tty, (speed_t)speed);
cfsetispeed(&tty, (speed_t)speed);
tty.c_cflag |= CLOCAL | CREAD;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; /* 8-bit characters */
tty.c_cflag &= ~PARENB; /* no parity bit */
tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
//tty.c_cflag &= ~CRTSCTS;
tty.c_cflag |= ~CRTSCTS; //trying to turn on CRTSCTS
tty.c_cflag &= ~HUPCL; //trying turning off HUPCL - it works!
tty.c_lflag |= ICANON | ISIG; /* canonical input */
tty.c_lflag &= ~(ECHO | ECHOE | ECHONL | IEXTEN);
tty.c_iflag &= ~IGNCR; /* preserve carriage return */
tty.c_iflag &= ~INPCK;
tty.c_iflag &= ~(INLCR | ICRNL | IUCLC | IMAXBEL);
tty.c_iflag &= ~(IXON | IXOFF | IXANY); /* no SW flowcontrol */
//tty.c_iflag |= ~IXON; //try ixon
tty.c_oflag &= ~OPOST;
tty.c_cc[VEOL] = 0;
tty.c_cc[VEOL2] = 0;
tty.c_cc[VEOF] = 0x04;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("Error from tcsetattr: %s\n", strerror(errno));
return -1;
}
return 0;
}
int main()
{
char *portname = SERIALTERMINAL;
int fd;
int wlen;
//fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC); original version
fd = open(portname, O_RDONLY | O_NOCTTY);
if (fd < 0) {
printf("Error opening %s: %s\n", portname, strerror(errno));
return -1;
}
/*baudrate 115200, 8 bits, no parity, 1 stop bit */
set_interface_attribs(fd, B115200);
/* simple canonical input */
do {
unsigned char buf[700];
unsigned char *p;
int rdlen;
rdlen = read(fd, buf, sizeof(buf) - 1);
if (rdlen > 0) {
buf[rdlen] = 0;
printf("%s", buf);
} else if (rdlen < 0) {
printf("Error from read: %d: %s\n", rdlen, strerror(errno));
} else { /* rdlen == 0 */
printf("Nothing read. EOF?\n");
}
/* repeat read */
} while (1);
}
When the program is run it doesn't show any output.
Going back out of CRTSCTS mode by swapping:
tty.c_cflag |= ~CRTSCTS;
with
tty.c_cflag &= ~CRTSCTS;
the program will show output but it is then not in the CRTSCTS mode which I need in order to prevent sending a DTR signal which results in an Arduino reset.
I have tried quite a few different options after reading through the Termios documentation: http://man7.org/linux/man-pages/man3/termios.3.html but to no avail.
So the question is what combination of options will allow reading from the serial port without sending a DTR signal?
I am trying to read some data from serial port using usb/rs232 converter. I am sending data from atmega and it is received properly in minicom. But trying to read sth in my program ends up with an error "Resource temporarily unavailable". I know that this is caused by O_NDELAY, but removing that gives me plenty of empty messages which also isn't good.
Actually, what I want to achieve is a program, which every second will transmit some char to atmega and wait for a response. Depending on a response it will do different actions. Also after few unanswered transmissions program will indicate an error with communication.
But for now I'd like to at least receive something properly.
Here is my code:
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
int fd; //file descriptor
int bytes; // bytes to read
int PortOpen(void)
{
fd = open("/dev/ttyUSB1", O_RDWR | O_NOCTTY | O_NDELAY);
if(fd < 0)
{
//opening error
printf("Port opening error\r\n");
}
else
{
printf("Port opened\r\n");
//port config
struct termios options;
tcgetattr(fd, &options);
cfsetispeed(&options, B9600);
cfsetospeed(&options, B9600);
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cflag |= CLOCAL;
options.c_cflag |= CREAD;
options.c_cflag &= ~CRTSCTS;
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 5;
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
//Modifying c_iflag by bitwise OR and AND
options.c_iflag &= ~(ICRNL | INLCR | IGNCR | IUCLC);
options.c_iflag &= ~(IXON | IXOFF | IXANY);
//Modifying c_oflag by bitwise OR and AND
options.c_oflag &= ~OPOST;
tcflush(fd, TCIFLUSH);
//Setting the new settings for the port immediately
tcsetattr(fd, TCSANOW, &options);
}
return 1;
}
int PortRead(void)
{
int n = 0, spot = 0;
char buf = '\0';
/* Whole response*/
char response[1024];
memset(response, '\0', sizeof response);
do {
n = read( fd, &buf, 1 );
sprintf( &response[spot], "%c", buf );
spot += n;
} while( buf != '\r' && n > 0);
if (n < 0)
{
printf("Error reading: %s\r\n",strerror(errno));
}
else if (n == 0)
{
printf("Read nothing!\r\n");
}
else
{
printf("Response: %s", response);
}
return 1;
}
int main(void)
{
PortOpen();
int j;
for(j=0; j<100; j++) //just testing
{
PortRead();
}
return 0;
}
I am using fgets in a small C program - running under Ubuntu - to read data coming from Arduino via its FTDI USB/Serial converter.
I am using low level I/O function from GNU libc (since I want - in the future - be able to control baud rate etc) and then promoting from descriptor to stream in order to use higher leve I/O functions.
The observed behaviour of my program suggests that the fgets function does not block until the line terminator is acquired (as in my opinion it should do).
Any explanation?
The codes of my programs are here
-> PC side:
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#define bufLen 81
int main(void) {
int fd; /* File descriptor for the port */
FILE * f; /* port will be identified also as stream 'f'*/
char buf[bufLen];
fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY);
if (fd == -1) {perror(""); return errno;}
else {
f = fdopen(fd, "r+t");
while (1) {
if (fgets(buf,bufLen,f)) {
printf("{%s}\n",buf);
sleep(1);
} else {
{perror("ahhhh! ");}
}
}
}
return 0;
}
-> Arduino side:
char ar[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ ";
int k1 = 0, k2 = 0;
void setup() {
// initialize serial:
Serial.begin(9600);
}
void loop() {
Serial.print(ar[k1]);
k1 = (++k1) % 26;
k2 = (++k2) % 5;
if (k2==0) {Serial.println();}
delay(300);
}
And the result of run..
xxx#RevoR3600:~/CProg$ ./SerialPort
ahhhh! : Success
ahhhh! : Success
ahhhh! : Success
...
... (many identical lines...)
...
ahhhh! : Success
ahhhh! : Success
{AP}
{A}
{BCD}
{E
}
{FGHIJ
}
^C
xxx#RevoR3600:~/CProg$
After sleeping one night on it and two more hours of digging this site (and testing) I finally came across a solution right here; sorry I was not able to find it before posting (I can't figure out why); now it is matter for me to study exactly why the found solution is working (and why there is still a minor problem: some strange characters acquired on starting).
Thanks (and apology) to everybody has read my post.
Here is the working (test) code:
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<unistd.h>
#include<fcntl.h>
#include<termios.h>
#define bufLen 81
int main() {
char buf[bufLen];
struct termios tty;
FILE * f;
int fd=open("/dev/ttyACM0",O_RDWR | O_NOCTTY);
if(fd == -1) {
perror("Unable to open /dev/ttyACM1\n");
return -1;
} else {
if(tcgetattr(fd, &tty)!=0) {perror("tcgetatt() error"); return -1;}
else {
cfsetospeed(&tty, B9600);
cfsetispeed(&tty, B9600);
tty.c_cflag &= ~PARENB;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8;
tty.c_cflag &= ~CRTSCTS;
tty.c_cflag |= CLOCAL | CREAD;
tty.c_iflag |= IGNPAR | IGNCR;
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
tty.c_lflag |= ICANON;
tty.c_oflag &= ~OPOST;
tcsetattr(fd, TCSANOW, &tty);
if (!(f = fdopen(fd, "r+t"))) {perror("fdopen() error"); return -1;}
while (1) {
fgets(buf,bufLen,f);
printf("%s--\n",buf);
}
}
}
close(fd);
return 0;
}
So I searched around, and couldn't exactly find what I needed. I need help reading and writing binary data over a serial port, and would appreciate any advice you may have. Please note, I asked a question similar to this earlier when I was at a different stage of this project.
Below are programs. The first program opens a file "test.jpg", reads it in binary mode and stores the result in a buffer. It then closes the file, and is supposed to send that file over a serial port.
The second program creates a file called "testout.jpg", and is supposed to read in the data sent from the previous program.
I have a hunch that the problem in my code lies in the second program. Perhaps I need to use fread for that too? I tried, but I cannot figure out how to implement it for a serial port as I am relatively new to programming.
Many thanks for your time.
Serial write:
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include <stdlib.h>
int main()
{
//writing
int writeport = open_port("/dev/ttyUSB0");
//open file
FILE *file;
char *buffer;
int fileLen;
file = fopen("test.jpg", "rb");
//get file size
fseek(file, 0, SEEK_END);
fileLen = ftell(file);
fseek(file, 0, SEEK_SET);
buffer = (char *)malloc(fileLen + 1);
//read file contents
fread(buffer, fileLen, 1, file);
fclose(file);
int n = write(writeport, buffer, fileLen + 1);
if (n < 0)
fputs("write() of bytes failed!\n", stderr);
//closing ports
close(writeport);
}
int open_port(char str[])
{
int fd = open(str, O_RDWR | O_NOCTTY | O_NONBLOCK); // ?? NDELAY or NONBLOCK?
if (fd == -1)
{
perror("open_port: Unable to open /dev/ttyS0 - ");
}
else
fcntl(fd, F_SETFL, 0);
struct termios options;
tcgetattr(fd, &options); //this gets the current options set for the port
// setting the options
cfsetispeed(&options, B9600); //input baudrate
cfsetospeed(&options, B9600); // output baudrate
options.c_cflag |= (CLOCAL | CREAD); // ?? enable receicer and set local mode
//options.c_cflag &= ~CSIZE; /* mask the character size bits */
options.c_cflag |= CS8; /* select 8 data bits */
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // choosing raw input
options.c_iflag &= ~INPCK; // disable parity check
options.c_iflag &= ~(IXON | IXOFF | IXANY); // disable software flow control
options.c_oflag |= OPOST; // ?? choosing processed output
options.c_cc[VMIN] = 0; // Wait until x bytes read (blocks!)
options.c_cc[VTIME] = 0; // Wait x * 0.1s for input (unblocks!)
// settings for no parity bit
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
tcsetattr(fd, TCSANOW, &options); //set the new options ... TCSANOW specifies all option changes to occur immediately
return (fd);
}
Serial read:
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
int main()
{
//reading
int readport = open_port("/dev/ttyUSB1");
//open resultant file
FILE *file;
//system("rm testout.jpg");
file = fopen("testout.jpg", "wb");
//trying to read one character at a time
char buff;
int n = 1;
while (n > 0)
{
n = read(readport, &buff, 1);
//printf("%c", buff, buff);
**//I tried these three methods, with little success**
//fprintf(file, "%c", buff);
//fwrite(&buff, 1, 1, file);
//write(file, &buff, 1);
}
//closing ports
close(readport);
fclose(file);
}
int open_port(char str[])
{
int fd = open(str, O_RDWR | O_NOCTTY | O_NONBLOCK); // ?? NDELAY or NONBLOCK?
if (fd == -1)
{
perror("open_port: Unable to open /dev/ttyS0 - ");
}
else
fcntl(fd, F_SETFL, 0);
struct termios options;
tcgetattr(fd, &options); //this gets the current options set for the port
// setting the options
cfsetispeed(&options, B9600); //input baudrate
cfsetospeed(&options, B9600); // output baudrate
options.c_cflag |= (CLOCAL | CREAD); // ?? enable receicer and set local mode
//options.c_cflag &= ~CSIZE; /* mask the character size bits */
options.c_cflag |= CS8; /* select 8 data bits */
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // choosing raw input
options.c_iflag &= ~INPCK; // disable parity check
options.c_iflag &= ~(IXON | IXOFF | IXANY); // disable software flow control
options.c_oflag |= OPOST; // ?? choosing processed output
options.c_cc[VMIN] = 0; // Wait until x bytes read (blocks!)
options.c_cc[VTIME] = 0; // Wait x * 0.1s for input (unblocks!)
// settings for no parity bit
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
tcsetattr(fd, TCSANOW, &options); //set the new options ... TCSANOW specifies all option changes to occur immediately
return (fd);
}
file = fopen( "zname.jpg", "wb" );
while (1) {
n = read(readport, &buff, 1);
if (n == -1) switch(errno) {
case EAGAIN: /* sleep() */
continue;
...
default: goto quit;
}
if (n ==0) break;
fputc(buff, file);
}
quit:
fclose (file);
...
Even better than sleep() and loop, would be to use select/poll. (You'd still have to check for EAGAIN)