Blocking and non-blocking (locating the cause of the serial port self-loop test failure)

Locating the cause of serial port self-loop test failure

INT32 serial_test()
{
    INT32 fd;
    INT32 i;
    char rbuf[1];
    char wrbuf[1];
    INT32 count = 0;
    INT32 cnt = 0;
    rbuf[0] = 0;
    int ret;
 //VCS_Ctrl_LedConf(SC1_LED,RED,FAST_BLINK);  //SC4红灯灭
// printf("serial_test::11111\n");
 
    printflag = 1;
    fd = open( "/dev/ttyS0", O_RDWR| O_NOCTTY  | O_NONBLOCK);
    if (fd < 0)
    {
        DPRINTF(PRINT_FLAG_ERR,"can't open ttyS0\n");
        close(fd);
    }
    else
     {
        DPRINTF(PRINT_FLAG_ERR,"open OK...\n");
    }
// printf("serial_test::22222\n");  
 tcflush(fd,TCIOFLUSH);
 for(i=0;i<10000;i++)
 {
    rbuf[0] = 0;
    read(fd,rbuf,1);
 }
//printf("serial_test::3333\n");
// VCS_Ctrl_LedConf(SC3_LED,RED,FAST_BLINK);  //SC4红灯灭
 if(0 == tty_raw(fd))
 DPRINTF(PRINT_FLAG_ERR,"tty raw set OK \n");
// VCS_Ctrl_LedConf(SC3_LED,GREEN,FAST_BLINK);  //SC4红灯灭
 
 #if 0   
 {
       
   INT32 timeOut = 0;
        /* hope to read 10 byte from serial com0*/
        while(1)
        {
            ret = read(fd, rbuf, 1000);
            if(ret <= 0)
            {
                timeOut ++;
                if (timeOut > 10)
                    break;
            }
        }
    }
 #endif
    while(1)
    {
        tcflush(fd,TCIOFLUSH);
       
        wrbuf[0] = 'u';
        rbuf[0] = 0;

        ret=write(fd,wrbuf,1);
        if(ret== -1)
        {
            printf("write error!\n");
            perror("wirte failed");
        }
        if(ret==1)
            printf("write success!");
        usleep(1000);  //lixia add 2010-06-13
        
        ret = 0;
    cnt = 0;
        while(ret != 1)

 {             cnt++;  ret=read(fd,rbuf,1);             if(ret== -1)             {                  printf("read error! 0x%x\n",errno); Here we find frequent read errors, and the returned errno is 0xb,                  perror("read failed");             }             if(ret==1)                 printf("read success! cnt=%d\n",cnt);              usleep(1000);             if(cnt>2000)                 break;   }

          











        printf("w:%c %d r:%c %d \n",wrbuf[0],wrbuf[0],rbuf[0],rbuf[0]);
        if(wrbuf[0] == rbuf[0])
        {
            Beep_Warning_On();
            sleep(1);
            Beep_Warning_Off();
            sleep(1);
           if (0 == tty_reset(fd))
                DPRINTF(PRINT_FLAG_ERR,"tty set RESET ok\n");
          // sleep(2);
            close(fd);
            printflag = 0;
          //   VCS_Ctrl_LedConf(SC1_LED,GREEN,FAST_BLINK);  //SC4红灯灭
            return 0;
        }
        else
        {
           count ++;
           if(count > 1000)
           {
              if (0 == tty_reset(fd))
              {
                  DPRINTF(PRINT_FLAG_ERR,"tty set RESET ok\n");
              }
                close(fd);
                printflag = 0;
                 VCS_Ctrl_LedConf(SC1_LED,GREEN,FAST_BLINK);  //SC4红灯灭
                return -1;
           }
        }
    }    
}

Found that the "read function marked in red" often read errors, and the returned errno is 0xb,

0xb corresponds to EAGAIN.

Because the open function uses O_NONBLOCK, which is non-blocking, the reason is located. Because it is in non-blocking mode, read will directly return to failure if there is no data, resulting in writing not equal to the data read. If more than 1000 times, the serial port is judged The self-loop test failed. The optimized code is shown in the above figure.

Knowledge point: be sure to judge the return value of the function! ! !

--------------------------------------------------------------------------------------------------------------------------------------

Non-blocking (O_NONBLOCK)

Non-blocking I/O makes our operation either succeed or return an error immediately without being blocked.
For a given descriptor, there are two ways to specify non-blocking I/O:
(1) Call open to get the descriptor, and specify the O_NONBLOCK flag
(2) For the opened file descriptor, call fcntl to open the O_NONBLOCK file status Sign.

flags = fcntl( s, F_GETFL, 0 ) )
fcntl( s, F_SETFL, flags | O_NONBLOCK )

--------------------------------------------------------------------------------------------------------------------------------------

Linux: The difference between non-blocking O_NONBLOCK and O_NDELAY

The result of O_NONBLOCK and O_NDELAY is to make I/O into non-blocking mode (non-blocking). When no data is read or the write buffer is full, it will return immediately without blocking waiting.

The difference between them is: in the read operation, if the data cannot be read, O_NDELAY will make the I/O function return 0 immediately, but this creates a problem because the end of the file (EOF) is also 0 when it is read, so It is impossible to distinguish which situation is. Therefore, O_NONBLOCK is generated, it will return -1 when the data cannot be read, and set errno to EAGAIN .

O_NDELAY was introduced in the early version of System V. When encoding, O_NONBLOCK specified by POSIX is recommended. O_NONBLOCK can be set in open and fcntl .

--------------------------------------------------------------------------------------------------------------------------------------

Linux device driver --- blocking character device driver --- O_NONBLOCK --- non-blocking flag

block:

          When designing a simple character driver, there is an important issue to pay attention to.

          What should be done when a device cannot immediately satisfy the user's read and write request?

          For example: there is no data to read when calling read, but there may be later;

          Or a process tries to write data to the device, but the device is not ready to receive data temporarily.

          The application usually doesn't care about this problem, the application just calls read or write and gets the return value.

         Drivers should (by default) block the process , it goes to sleep , until the request can be met .

Blocking operation:

          It means that when performing device operations, if resources cannot be obtained , the process will be suspended until the operable conditions are met.

          The suspended process enters the sleep state and is removed from the run queue of the scheduler until the waiting conditions are met.

Non-blocking operation:

          When the process can not operate the device does not hang , he or give up , or keep the query until you can perform the operation so far.

 

Blocking mode-read- implementation:

          In the blocking driver, read is implemented as follows:

          If the process calls read, but the device has no data or insufficient data, the process is blocked .

          When new data arrives , wake up the blocked process .

 

Blocking mode -write- implementation:

          In the blocking driver, write is implemented as follows:

          If the process is called write, but the device does not have enough space for write data, the process of blocking .

          When the data is read device left, the buffer empty part of the space , the wake-up process .

 

Read and write operations in non-blocking mode:

          Blocking mode is a file read and write operations by default , but can be obtained by the application programmer using O_NONBLOCK flag artificially

          The set read and write operations to a non-blocking manner . (This flag is defined, when opening the file specified in <linux / fcntl.h> in).

 

          If the O_NONBLOCK flag is set , read and write behavior is different, if the process does not have the data ready when you call a read,

          Or call the write buffer when there is no space, the system just simply return -EAGAIN , but will not block the process .

 

Example --- the realization of read blocking:

          

          

 

We use while because other signals may wake up sleep. We have to use while to re-check whether there is data....

 

 

          

 

 

Example --- Button-driven blocking realization:

1. Check whether it is blocking or non-blocking in the open function:

         The file structure contains the f_flags flag bit, depending on whether it is blocking or non-blocking:

          O_NONBLOCK is non-blocking mode ;

	if (file->f_flags & O_NONBLOCK)  /* 非 阻塞操作 */
	{
		if (down_trylock(&button_lock))   /* 无法获取信号量,down_trylock 立马返回 一个 非零值 */
			return -EBUSY;
	}
	else                             /* 阻塞操作 */
	{
		/* 获取信号量 */
		down(&button_lock);   /* 获取不到  睡眠 */
	}

 

2. View the same in the read function:

	if (file->f_flags & O_NONBLOCK)       /* 非 阻塞操作 */
	{
		if (!ev_press)                 /* ev_press 为 1 表示有按键按下,为 0 if 成立 ,没有按键按下, */
			return -EAGAIN;        /* 返回 -EAGAIN 让再次来执行 */
	}
	else                                   /* 阻塞操作 */
	{
		/* 如果没有按键动作, 休眠 */
		wait_event_interruptible(button_waitq, ev_press);
	}
<table><tr><td bgcolor=#7FFFD4>这里的背景色是:Aquamarine,  十六进制颜色值:#7FFFD4, rgb(127, 255, 212)</td></tr></table>

3. In the application:

1. Run in blocking mode:

Execute the application in the background, the process is in sleep state, press the button, immediately print the button number;

int main(int argc, char **argv)
{
	unsigned char key_val;
	int Oflags;
                                                   
	fd = open("/dev/buttons", O_RDWR );
	if (fd < 0)
	{
		printf("can't open!\n");
		return -1;
	}
 
	while (1)
	{
		read(fd, &key_val, 1);
		printf("key_val: 0x%x\n", key_val);
	}
	
	return 0;
}

 

 


 

2. Run in non-blocking mode:

When opening the driver, pass the flag O_NONBLOCK non-blocking;

Execute the application in the background:

int main(int argc, char **argv)
{
	unsigned char key_val;
	int ret;
	int Oflags;
 
	fd = open("/dev/buttons", O_RDWR | O_NONBLOCK);
	if (fd < 0)
	{
		printf("can't open!\n");
		return -1;
	}
 
	while (1)
	{
		ret = read(fd, &key_val, 1);
		printf("key_val: 0x%x, ret = %d\n", key_val, ret);
		sleep(5);
	}
	
	return 0;
}

 

 

Non-blocking mode, no key value is pressed, the program returns immediately;
read return value is -1;

https://blog.csdn.net/yikai2009/article/details/8653697#t7

 

Guess you like

Origin blog.csdn.net/u014426028/article/details/112789104