LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 03-17-2011, 07:24 AM   #1
tejendra
LQ Newbie
 
Registered: Dec 2010
Location: Noida(U.P.) India
Posts: 14

Rep: Reputation: 0
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);
}

Last edited by tejendra; 03-17-2011 at 07:28 AM.
 
Old 03-17-2011, 07:25 AM   #2
tejendra
LQ Newbie
 
Registered: Dec 2010
Location: Noida(U.P.) India
Posts: 14

Original Poster
Rep: Reputation: 0
please help out,please tell me is this approach good and if not then what is the correct way to achieve this objective.
 
Old 03-22-2011, 03:23 AM   #3
tejendra
LQ Newbie
 
Registered: Dec 2010
Location: Noida(U.P.) India
Posts: 14

Original Poster
Rep: Reputation: 0
guys is there no one to help me[]...please help me out i am stuck in it...
 
Old 03-22-2011, 06:26 AM   #4
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 942Reputation: 942Reputation: 942Reputation: 942Reputation: 942Reputation: 942Reputation: 942Reputation: 942
Quote:
Originally Posted by tejendra View Post
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;
}
For starters, I'd recommend looking at Serial Programming Guide for POSIX Operating Systems by Michael R. Sweet (for portable serial programming).
 
  


Reply

Tags
serial port, threading


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Is a USBtty (USB serial port) treated the same as tty (normal serial port) in C? spudgunner Programming 1 11-12-2010 01:19 PM
Creating a bash script with serial port input Elv13 Linux - Hardware 10 06-08-2010 07:01 AM
Problem creating threads in C++ mending73 Linux - Newbie 1 09-30-2009 02:51 AM
how to transfer and receive file using serial port from my application amit_pansuria Programming 5 06-14-2007 05:27 PM
serial port problem bekaar Ubuntu 2 03-24-2007 06:44 PM


All times are GMT -5. The time now is 02:55 AM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration