简体   繁体   中英

linux serial port : read be blocked mode

My goal is to set 2 threads for serial ports: one for read, one for write.

My example is refer to the [one](//refer to how to open, read, and write from serial port in C ) heavily, but I added pthread to my code:

//refer to https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c
    //refer to https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>

    #include <unistd.h>
    #include <fcntl.h>
    #include <termios.h>

    #include <pthread.h>    /* POSIX Threads */

    #define MAX_STR_LEN                         256

    /*
     * The values for speed are 
     * B115200, B230400, B9600, B19200, B38400, B57600, B1200, B2400, B4800, etc
     * 
     *  The values for parity are 0 (meaning no parity), 
     * PARENB|PARODD (enable parity and use odd), 
     * PARENB (enable parity and use even), 
     * PARENB|PARODD|CMSPAR (mark parity), 
     * and PARENB|CMSPAR (space parity).
     * */


    int SetInterfaceAttribs(int fd, int speed, int parity)
    {
            struct termios tty;
            memset (&tty, 0, sizeof tty);
            if (tcgetattr (fd, &tty) != 0) /* save current serial port settings */
            {
                printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
                return -1;
            }

            cfsetospeed (&tty, speed);
            cfsetispeed (&tty, speed);

            tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;     // 8-bit chars
            // disable IGNBRK for mismatched speed tests; otherwise receive break
            // as \000 chars
            tty.c_iflag &= ~IGNBRK;         // disable break processing
            tty.c_lflag = 0;                // no signaling chars, no echo,
                                            // no canonical processing
            tty.c_oflag = 0;                // no remapping, no delays
            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 |= parity;
            tty.c_cflag &= ~CSTOPB;
            tty.c_cflag &= ~CRTSCTS;

            if (tcsetattr (fd, TCSANOW, &tty) != 0)
            {
                    printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
                    return -1;
            }
            return 0;
    }/*set_interface_attribs*/


    void SetBlocking(int fd, int should_block)
    {
            struct termios tty;
            memset (&tty, 0, sizeof tty);
            if (tcgetattr(fd, &tty) != 0)
            {
                    printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
                    return;
            }

            tty.c_cc[VMIN]  = should_block ? 1 : 0;
            tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

            if (tcsetattr (fd, TCSANOW, &tty) != 0)
                     printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
    }/*SetBlocking*/


    void *sendThread(void *parameters)
    {
        char sendBuff[MAX_STR_LEN];

        memset(&sendBuff[0], 0, MAX_STR_LEN);
        snprintf(&sendBuff[0], MAX_STR_LEN, "hello!");

        int fd;

        fd = *((int*)parameters);

        while(1)
        {
            write(fd, &sendBuff[0], strlen(&sendBuff[0]) ); 

            // sleep enough to transmit the length plus receive 25:  
            // approx 100 uS per char transmit
            usleep((strlen(&sendBuff[0]) + 25) * 100);             
        }/*while*/

        pthread_exit(0); 
    }/*sendThread */


    void *readThread(void *parameters)
    {
        char readBuff[MAX_STR_LEN];


        int fd;

        fd = *((int*)parameters);

        while(1)
        {
            ssize_t len;

            memset(&readBuff[0], 0, MAX_STR_LEN);

            len = read(fd, &readBuff[0], MAX_STR_LEN); 

            if (len == -1)
            { 
                switch(errno) 
                {
                    case EAGAIN:
                    printf("__FUNCTION__ = %s, __LINE__ = %d\n", __FUNCTION__, __LINE__);
                    usleep(5*1000); 
                    continue;
                    break;

                    default:
                    printf("__FUNCTION__ = %s, __LINE__ = %d\n", __FUNCTION__, __LINE__);
                        pthread_exit(0); 
                    break;      
                }
            }
            // sleep enough to transmit the length plus receive 25:  
            // approx 100 uS per char transmit
            usleep((len + 25) * 100);
            printf("len = %d\n", (int)len);

            int i;

            for(i = 0; i< len; i++)
                printf("%c(%d %#x)\t", readBuff[i], readBuff[i], readBuff[i]);

            printf("\n");               
        }/*while*/

        pthread_exit(0); 
    }/*readThread */


    int main(int argc, char *argv[])
    {
        int fd, c, res;
        struct termios oldtio,newtio;
        char buf[MAX_STR_LEN];
        int k;
        char deviceName[MAX_STR_LEN];

        memset(&deviceName[0], 0, MAX_STR_LEN);
        snprintf(&deviceName[0], MAX_STR_LEN, "/dev/ttyUSB0");

        k = 1;
        while(argc > k)
        {   
            if(0 == strncmp(argv[k], "-d", MAX_STR_LEN))
            {
                    if(k + 1 < argc)
                    {
                        snprintf(&deviceName[0], MAX_STR_LEN, "%s", argv[k + 1]);
                    }
                    else
                    {
                        printf("error : -d should be follow a device!\n");      
                        return 0;
                    }/*if */
            }
            k++;    
        }/*while k*/

        printf("__FUNCTION__ = %s, __LINE__ = %d\n", __FUNCTION__, __LINE__);


        fd = open(&deviceName[0], O_RDWR | O_NOCTTY |O_NONBLOCK| O_NDELAY); 
        if(0 > fd) 
        {
            perror(&deviceName[0]); 
            exit(-1); 
        }/*if */


        SetInterfaceAttribs(fd, B115200, 0); /* set speed to 115,200 bps, 8n1 (no parity)*/
        SetBlocking(fd, 1); 

        pthread_t readThread_t, sendThread_t;  /* thread variables */

        pthread_create(&sendThread_t, NULL, (void *)sendThread, (void *)&fd);
        pthread_create(&readThread_t, NULL, (void *)readThread, (void *)&fd);

        pthread_join(sendThread_t, NULL);
        pthread_join(readThread_t, NULL);

        close(fd);


        return 0;
    }/*main*/

The send data thread works well.

But the read data thread : I could not set it as blocking, the read function returns immediately, even the read data length is zero.

How should I modify the code to make the read function be blocked?

fd = open(&deviceName[0], O_RDWR | O_NOCTTY |O_NONBLOCK| O_NDELAY);

Try removing O_NONBLOCK and O_NDELAY from your open call. Or is there a particular reason you have that even though you specifically want it to block?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM