Thread: the sleep function in C and serial programming

  1. #1
    Registered User
    Join Date
    Jan 2014
    Posts
    62

    the sleep function in C and serial programming

    Below I mocked up a basic C serial program for linux. My requirement is to toggle the RTS port to high on a rs-232 serial port, wait 5 milliseconds, send a hart frame (which consists of 11 bytes), wait 5 milliseconds, and then toggle the RTS port to low. Now the requirement seems simple. But I am wondering if the sleep function is exactly the same thing as "waiting". The sleep function suspends the current thread for n seconds. If the thread is suspended, does that also suspend the influence on the RTS port? If it won't have any affect on the RTS signal, I still would like to know if there is a better way to wait a few milliseconds when communicating across an rs-232 serial port. Thanks.

    Code:
    #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 <unistd.h> /* Sleep Function */
    
    
    
    
    #define BUFFER_SIZE        1000
    
    
    
    
    unsigned char Buffer[BUFFER_SIZE];
    
    
    
    
    struct termios options;
    
    
    
    
    
    
    
    
    int open_port()
    {
        int fd; /* File descriptor for the port */
    
    
    
    
        fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
    
    
    
    
        if (fd == -1)
        {
            perror("open_port: Unable to open /dev/ttyS0 - ");
    
    
    
    
        } else {
          fcntl(fd, F_SETFL, 0);
    
    
    
    
          return (fd);
        }
    }
    
    
    
    
    void configure_port(int fd)
    {
    
    
    
    
        tcgetattr(fd, &options);
    
    
    
    
        cfsetispeed(&options, B1200);
    
    
    
    
        cfsetospeed(&options, B1200);
    
    
    
    
    
    
    
    
        options.c_cflag |= (CLOCAL | CREAD);
    
    
    
    
    
    
    
    
        options.c_cflag &= ~PARENB
    
    
    
    
        options.c_cflag |= PARODD
    
    
    
    
        options.c_cflag &= ~CSTOPB
    
    
    
    
    
    
    
    
        options.c_cflag &= ~CSIZE; 
    
    
    
    
        options.c_cflag |= CS8; 
    
    
    
    
    
    
    
    
        options.c_cflag &= ~CNEW_RTSCTS;
    
    
    
    
    
    
    
    
        options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    
    
    
    
    
    
    
    
        options.c_oflag     &= ~OPOST;
    
    
    
    
    
    
    
    
        options.c_cc[VMIN]  = 0;
    
    
    
    
        options.c_cc[VTIME] = 10;
    
    
    
    
    
    
    
    
    
    
    
    
        tcsetattr(fd, TCSANOW, &options);
    
    
    
    
    }
    
    
    
    
    
    
    
    
    void raise_rts_signal(int fd)
    
    
    
    
    {
        int status;
    
    
    
    
        ioctl(fd, TIOCMGET, &status);
    
    
    
    
        status &= TIOCM_RTS;
    
    
    
    
        ioctl(fd, TIOCMSET, status);
    }
    
    
    
    
    void drop_rts_signal(int fd)
    
    
    
    
    {
    
    
    
    
        int status;
    
    
    
    
        ioctl(fd, TIOCMGET, &status);
    
    
    
    
        status &= ~TIOCM_RTS;
    
    
    
    
        ioctl(fd, TIOCMSET, status);
    
    
    
    
    }
    
    
    
    
    
    
    
    
    int send_hart_frame(int fd)
    
    
    
    
    {
    
    
    
    
        int bytes;
    
    
    
    
        unsigned char hart_buff[11] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x0, 0x0, 0x0, 0x2 };
    
    
    
    
        bytes = write(fd, hart_buff, 11);
    
    
    
    
        if (bytes != 11)
    
    
    
    
            return -1;
    
    
    
    
        else
    
    
    
    
            return 0;
    
    
    
    
    }
    
    
    
    
    
    
    
    
    
    
    
    
    int get_bytes_available(int fd, unsigned char *Buf)
    
    
    
    
    {
    
    
    
    
        int bytes;
    
    
    
    
        ioctl(fd, FIONREAD, &bytes);
    
    
    
    
        if (bytes >= 1)
    
    
    
    
        {
    
    
    
    
            bytes = read(fd, Buf, BUFFER_SIZE);
    
    
    
    
            if (bytes < 0)
    
    
    
    
                return -1;
    
    
    
    
            printf("Received Bytes from Hart: %s", Buf);
    
    
    
    
            return 0;
    
    
    
    
        }
    
    
    
    
        else
    
    
    
    
            printf("No data available.");
    
    
    
    
            return -1;
    
    
    
    
    }
    
    
    
    
    
    
    
    
    int main(void)
    
    
    
    
    {
    
    
    
    
        int fd = open_port();
    
    
    
    
        configure_port(fd);
    
    
    
    
    
    
    
    
           while(1)
    
    
    
    
           {
    
    
    
    
               raise_rts_signal(fd);
    
    
    
    
               // sleep 5 milliseconds
    
    
    
    
               sleep(0.005);
    
    
    
    
               send_hart_frame(fd);
    
    
    
    
               // sleep 5 milliseconds
    
    
    
    
               sleep(0.005);
    
    
    
    
               drop_rts_signal(fd);
    
    
    
    
               // now poll for bytes available in serial buffer
    
    
    
    
               get_bytes_available(fd, Buffer);
    
    
    
    
    
    
    
    
    
    
    
    
               // try again in 30 seconds
    
    
    
    
               sleep(30);
    
    
    
    
           }
    
    
    
    
    
    
    
    
        close(fd);
    
    
    
    
    
    
    
    
        return 0;
    }

  2. #2
    Registered User
    Join Date
    Apr 2013
    Posts
    1,656
    It would help if you didn't have 5 to 7 blank lines between each line of code. You'd probably be better off using some sort of timer driven function call back or event setter for the timing. I don't know what these functions are for linux.

  3. #3
    Registered User
    Join Date
    Jan 2014
    Posts
    62
    I noticed all the spaces after I posted. Sorry, I don't see an option to edit the post. Can you elaborate on timer driven function?

  4. #4
    Registered User
    Join Date
    Apr 2013
    Posts
    1,656
    Quote Originally Posted by johnmerlino View Post
    Sorry, I don't see an option to edit the post. Can you elaborate on timer driven function?
    I don't know what it is for linux. For Windows, you would use the multimedia timer functions.

  5. #5
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    You would use the HPET timer, for Windows or Linux, for the best timer resolution.

    The following operating systems are known not to be able to use HPET: Windows XP,[note 2] Windows Server 2003, and earlier Windows versions, Linux kernels prior to 2.6.[note 3]

    The following operating systems are known to be able to use HPET: Windows XP SP3,[note 4] Windows Server 2008, Windows Server 2008 R2, Windows Vista, Windows 7, x86 based versions of Mac OS X, Linux operating systems using the 2.6 kernel (or later), FreeBSD[clarification needed][citation needed] and OpenSolaris.[citation needed]
    If you Google it for your distro, you should find what you need to implement it.

  6. #6
    Registered User
    Join Date
    Apr 2013
    Posts
    1,656
    In the case of Windows, I'm not sure what functions are available to access the HPET. Currently programs (mostly games like racing games, and some multi-media programs) that need a very accurate fixed frequency use QueryPerformanceCounter(), which returns a 64 bit counter that runs at cpu clock speed on some PC's. There's no interrupt with this timer, so it has to be polled in a tight delay loop. CPU overhead in the delay loop can be reduced by checking to see if 1 ms (Win 7, maybe Vista) or 2 ms (Win XP) or more is remaining for the current delay cycle and if so, perform a Sleep(1). This requires a call to timerBeginPeriod(1) to set the timer to about 1 ms (1000 hz on Win 7, 1024 hz on Win XP, but Sleep(1) on XP results in almost 2 ms Sleep). Any drift over time can be prevented by basing the delays on fixed delay counts added to a counter based on a single initial read of the high frequency counter (as opposed to using the previous cycle's counter value).

    Microsoft article about HPET:

    Guidelines For Providing Multimedia Timer Support
    Last edited by rcgldr; 02-12-2014 at 02:36 AM.

  7. #7
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Currently, Windows (and the South Bridge chipsets), will continue to support legacy timers of several types, so software that uses them will continue to function.

    Going forward, MS states that Windows support for it's multimedia timer, will cease. Only the HPET for it's high resolution timing, will be supported.

    It's confusing because MS had it's own "Multimedia Timer" based on software, which didn't work that well, and will not be supported in the future. Instead MS will support, the (Intel) HPET timer.

    Example code is here:
    How to: Use the High-Resolution Timer
    Last edited by Adak; 02-12-2014 at 06:34 AM.

  8. #8
    Registered User
    Join Date
    Apr 2013
    Posts
    1,656
    Quote Originally Posted by Adak View Post
    Currently, Windows (and the South Bridge chipsets), will continue to support legacy timers of several types, so software that uses them will continue to function. Going forward, MS states that Windows support for it's multimedia timer, will cease. Only the HPET for it's high resolution timing, will be supported. It's confusing because MS had it's own "Multimedia Timer" based on software, which didn't work that well, and will not be supported in the future. Instead MS will support, the (Intel) HPET timer.

    Example code is here:
    How to: Use the High-Resolution Timer
    The example code is for Windows CE, and for C#. The mentioned functions, QueryPerformanceFrequency(), and QueryPerformanceCounter(), will use one of 3 timers, depending on the version of Windows and the hardware. Note that these are polling functions and not functions that can set events or perform call back. The regular timer functions are still needed to do that and are limited to about 1 millisecond cycle time (1000hz Win 7, 1024hz Win XP). WinXP callback and event functions are problematic, in that they emulate 1000hz clock with 1024hz clock by occasionally "delaying" an extra tick about once every 41.6 ticks, using a repeating pattern of (42, 42, 41) for when to include the extra ticks. Win XP Sleep(1) always waits 2/1024 = 1/512 second, without including the extra ticks. If a thread priority is set high enough, then Sleep(1) is safe to use for Win XP. Win 7 and probably Vista, timers run at 1000hz without the extra tick issue, and Sleep(1) always waits 1 / 1000 second.

    On my system, Intel DP67G motherboard, Intel 2600K 3.4ghz cpu, Windows XP QueryPerformanceFrequency() returns 3,392,380,000 (cpu frequency clock), while Win7 QueryPerformanceFrequency() returns 3,312,832 (apparently the power management timer). I don't get the HPET frequency range of 10mhz to < 1ghz with either version of windows on my system.

    Scroll down to note 4 at the bottom of this wiki article:

    High Precision Event Timer - Wikipedia, the free encyclopedia

    Links to Microsoft descriptions:

    QueryPerformanceFrequency function (Windows)

    QueryPerformanceCounter function (Windows)
    Last edited by rcgldr; 02-12-2014 at 12:10 PM.

  9. #9
    Registered User
    Join Date
    Nov 2012
    Posts
    1,393
    For serial programming have you tried the following document for ideas:

    Serial Programming HOWTO


    The examples there make use of usleep and select for timeouts. I suppose select will also work in Windows if used properly:


    select function (Windows)

  10. #10
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Not all boards are using chipsets that support the HPET fully, yet. MS is providing some software support for them, and for legacy users of it's older Multimedia timer as well, but it has become quite a mess because of the variety of timers, chipsets, etc.

    I thought the notations in the program I linked to were helpful.

    Looks like C99tutorial has a great link for it.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. sleep function
    By pollypocket4eva in forum C Programming
    Replies: 11
    Last Post: 02-16-2009, 04:28 AM
  2. Using the sleep function
    By HyperHelix in forum C++ Programming
    Replies: 3
    Last Post: 04-30-2005, 09:18 AM
  3. The sleep function...
    By Finchie_88 in forum C++ Programming
    Replies: 6
    Last Post: 09-07-2004, 03:19 PM
  4. sleep function
    By subflood in forum C Programming
    Replies: 1
    Last Post: 08-29-2004, 03:11 PM
  5. How often do you lose sleep due to programming
    By Thantos in forum A Brief History of Cprogramming.com
    Replies: 21
    Last Post: 08-26-2003, 12:10 AM