problem in creating serial port application using threads
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
problem in creating serial port application using threads
Hi guys i have searched all the forums but did not get any support. I am creating a serial port application in which i will
1. Open and configure the port
2. I will create two threads WRITER THREAD and READER THREAD, writer thread will write the data to serial port and reader thread will read data from serial port.
I have written the code too.. want to share it
Code:
#include<stdio.h> // Standard Input/output definations
#include<unistd.h> // UNIX standard function definations
#include<fcntl.h> // File control definations
#include<termios.h>// POSIX terminal control definations
#include<pthread.h>
#include<errno.h>
int fildes;//file descriptor
void open_port(void)
{
fildes=open("/dev/tty0",O_RDWR | O_NOCTTY);
if(fildes==-1)
printf("\nUnable to open port!\n");
else
{
fcntl(fildes,F_SETFL,0);//Manipulate file descriptor,F_SETFL will return the value of flag
printf("\n**PORT IS OPEN**\n\n");
}
}
int config_port(fildes)
{
struct termios termios_p;
cfsetispeed(&termios_p,B38400);//Setting output baud rate
cfsetospeed(&termios_p,B38400);//Setting input baud rate
tcsetattr(fildes,TCSANOW,&termios_p);
}
void *writedata(void *ptr)
{
int n;
n = write(fildes,"ATZ\r",4);
if (n < 0)
fputs("write() of 4 bytes failed!\n", stderr);
else
printf ("Write succeed n = %d\n", n );
}
void *readdata(void *ptr)
{
int n;
char buf;
fcntl(fildes, F_SETFL, FNDELAY);
n = read(fildes,&buf,1);
if ( n == -1 )
{
printf ( "Error = %d\n", strerror(errno));
}
printf ( "Number of bytes to be read = %s\n",n);
printf ( "Buf = %c\n", buf);
}
int main()
{
open_port();
config_port(fildes);
pthread_t thread_reader,thread_writer;
int iret1,iret2;
char *message1="thread_reader";
char *message2="thread_writer";
iret1=pthread_create(&thread_writer,NULL,writedata,(void *)message2);
iret2=pthread_create(&thread_reader,NULL,readdata,(void *)message1);
pthread_join(thread_writer,NULL);
pthread_join(thread_reader,NULL);
printf("\nwriter_thread returns:%d\n",iret1);
printf("\nreader_thread returns:%d\n\n",iret2);
close (fildes);
}
I will create two threads WRITER THREAD and READER THREAD, writer thread will write the data to serial port and reader thread will read data from serial port.
Yes, that's ok. I'm not absolutely sure, but I think you could open a descriptor separately for each thread, so that you can set the reader to nonblocking mode via O_NONBLOCK, but use blocking mode for the writer.
There are a number of major issues in your code:
You do not initialize termios_p fields to sane values in config_port()
/dev/tty0 is hardcoded (and probably should be /dev/ttyS0 instead)
and some other minor issues, too:
open_port() just prints but continues normally when failure occurs
unnecessary fcntl() in open_port()
non-signal safe read() and write(), better use a loop to ensure all data read/written
misleading iret1 and iret2 variables in main()
I don't have any serial equipment to test this with, but I'd rewrite your code to something like this:
Code:
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <termios.h>
#include <string.h>
#include <pthread.h>
#include <stdio.h>
#include <errno.h>
int port_descriptor = -1;
typedef struct string string_t;
struct string {
size_t size;
char data[];
};
string_t *add(string_t *string, void const *const data, size_t const size)
{
size_t const oldsize = (string) ? string->size : (size_t)0;
string_t *newstr;
newstr = realloc(string, sizeof(string_t) + oldsize + size + 1);
if (!newstr) {
if (string) {
string->size = 0;
free(string);
}
errno = ENOMEM;
return NULL;
}
if (size)
memcpy(&(newstr->data[oldsize]), data, size);
newstr->data[oldsize + size] = 0;
newstr->size = oldsize + size;
return newstr;
}
static inline char const *string(string_t const *const s)
{
return (s) ? (char *)&(s->data[0]) : "";
}
/* Open and configure device. Return -1 if an error occurs.
*/
int init_port(char const *const device)
{
int descriptor, result;
struct termios settings;
if (!device || !*device) {
errno = EINVAL;
return -1;
}
do {
descriptor = open(device, O_RDWR | O_NOCTTY);
} while (descriptor == -1 && errno == EINTR);
if (descriptor == -1)
return -1;
do {
result = fcntl(descriptor, F_SETFL, O_NONBLOCK);
} while (result == -1 && errno == EINTR);
if (result == -1) {
int const error = errno;
do {
result = close(descriptor);
} while (result == -1 && errno == EINTR);
errno = error;
return -1;
}
do {
result = tcgetattr(descriptor, &settings);
} while (result == -1 && errno == EINTR);
if (result == -1) {
int const error = errno;
do {
result = close(descriptor);
} while (result == -1 && errno == EINTR);
errno = error;
return -1;
}
/* Clear modes */
settings.c_iflag = 0;
settings.c_oflag = 0;
settings.c_lflag &= ~(tcflag_t)( ISIG | ICANON | TOSTOP | IEXTEN |
ECHO | ECHOE | ECHOK | ECHONL );
cfsetispeed(&settings, B38400);
cfsetospeed(&settings, B38400);
do {
result = tcsetattr(descriptor, TCSANOW, &settings);
} while (result == -1 && errno == EINTR);
if (result == -1) {
int const error = errno;
do {
result = close(descriptor);
} while (result == -1 && errno == EINTR);
errno = error;
return -1;
}
/* Note: the above call may succeed even if only some of
* the flags were supported. We could tcgetattr()
* into a temporary struct, and compare fields
* (masked by the significant modes) to make sure.
*/
return descriptor;
}
int write_port(void const *const data, size_t const size)
{
char const *p = (char const *)data;
char const *const q = (char const *)data + size;
ssize_t n;
while (p < q) {
do {
n = write(port_descriptor, p, (size_t)(q - p));
} while (n == (ssize_t)-1 && errno == EINTR);
if (n == (ssize_t)-1 && errno == EWOULDBLOCK) {
/* Sleep for a millisecond, then retry. */
usleep(1000);
continue;
}
if (n == (ssize_t)-1)
return errno;
else
if (n < (ssize_t)1)
return EIO;
p += (size_t)n;
}
if (p != q)
return EIO;
return 0;
}
/* Return number of bytes actually read.
* If 0, errno will contain the reason.
*/
size_t read_port(void *const data, size_t const size)
{
ssize_t r;
do {
r = read(port_descriptor, data, size);
} while (r == (ssize_t)-1 && errno == EINTR);
if (r > (ssize_t)0)
return (size_t)r;
if (r == (ssize_t)-1)
return (size_t)0;
if (r == (ssize_t)0) {
errno = 0;
return (size_t)0;
}
/* r < -1, should never happen. */
errno = EIO;
return (size_t)0;
}
void *reader(void *unused)
{
char buffer[512];
size_t result;
while (1) {
result = read_port(buffer, sizeof(buffer));
if (result)
return (void *)add(NULL, buffer, result);
if (errno == EINTR || errno == EWOULDBLOCK) {
/* Sleep for a millisec, then retry */
usleep(1000);
continue;
}
/* Failure. */
return NULL;
}
/* Never reached. */
return NULL;
}
void *writer(void *string_to_write)
{
string_t *s = (string_t *)string_to_write;
int result;
if (!s || !s->size)
return (void *)((long)ENOENT);
result = write_port(s->data, s->size);
return (void *)((long)result);
}
int main(int argc, char *argv[])
{
pthread_t thread_reader, thread_writer;
void *result_reader, *result_writer;
char *message = "ATZ\n";
int result;
if (argc < 2 || argc > 3) {
fprintf(stderr, "Usage: %s /dev/ttyS0 [ message ]\n", argv[0]);
return 1;
}
port_descriptor = init_port(argv[1]);
if (port_descriptor == -1) {
char const *const error = strerror(errno);
fprintf(stderr, "%s: %s.\n", argv[1], error);
return 1;
}
if (argc > 2)
message = argv[2];
result = pthread_create(&thread_reader, NULL, reader, NULL);
if (result) {
fprintf(stderr, "Cannot create reader thread: %s.\n", strerror(result));
exit(1);
}
result = pthread_create(&thread_writer, NULL, writer, add(NULL, message, strlen(message)));
if (result) {
fprintf(stderr, "Cannot create writer thread: %s.\n", strerror(result));
exit(1);
}
fprintf(stderr, "Waiting for completion..\n");
fflush(stderr);
result = pthread_join(thread_writer, &result_writer);
if (result) {
fprintf(stderr, "Writer thread error: %s\n", strerror(result));
exit(1);
}
result = pthread_join(thread_reader, &result_reader);
if (result) {
fprintf(stderr, "Reader threadd error: %s\n", strerror(result));
exit(1);
}
fprintf(stderr, "Both threads have completed.\n");
fflush(stderr);
printf("Writer returned status %ld (%s).\n",
(long)result_writer, (result_writer == (void *)0L) ? "Success" : "Error");
if (result_reader)
printf("Reader returned string '%s' (%d characters).\n",
string((string_t *)result_reader), (int)(((string_t *)result_reader)->size));
else
printf("Reader returned an error (or failure).\n");
if (result_reader)
free(result_reader);
return 0;
}
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.