io - My C program that works with serial port hangs on read if ran for the second time - Stack Overflow

I am using Cygwin environment to build my program. Also I use the termius library. Essentially, the pro

I am using Cygwin environment to build my program. Also I use the termius library. Essentially, the program opens the serial port:

fuart = open(device, O_RDWR | O_NOCTTY | O_SYNC);

Then its workflow involves writing to the serial port this way:

write(fuart, str, xlen);

As well as reading from it:

ln = read(fuart, buff, n);

And at the end:

tcflush(fuart,TCIOFLUSH);
close(fuart);
sleep(2); //just in case

When I run the program for the first time it works great, however when launched subsequently with same input data and whatnot, it will hang on read. If I disable the COM port in Windows device manager and re-enable it, then everything goes fine on the next run. I thought maybe my program doesn't properly close the port due to compatability issues and it remains locked, however other terminal software such as teraterm could open it, more interestingly, if I try to run my program for the second time and it hangs, I can see the data it wrote to the serial port after I forcibly close it via task manager and open 3rd party terminal software. So seems like my C program cannot properly handle closing of the COM port (or perhaps flushing/releasing the read buffer, since it hangs on the read operation) and this is not an OS or platform issue. Note that during its work my program successfully reads and writes to the port several times (but again only during the first run after which I have to disable-enable the device or open another terminal software).

For reference, the device I communicate with is an USB modem.

I tried searching for the answer but had little luck, other than finding advise to close the port, which I already do.I have seen someone was in the same boat and they used the enable-disable trick, but like I said my research revealed that other terminal programs do not have this bug and they even help to release the COM port. I even found a software that uses Cygwin runtime, namely mobastorm, and it doesn't suffer from this problem.

I am using Cygwin environment to build my program. Also I use the termius library. Essentially, the program opens the serial port:

fuart = open(device, O_RDWR | O_NOCTTY | O_SYNC);

Then its workflow involves writing to the serial port this way:

write(fuart, str, xlen);

As well as reading from it:

ln = read(fuart, buff, n);

And at the end:

tcflush(fuart,TCIOFLUSH);
close(fuart);
sleep(2); //just in case

When I run the program for the first time it works great, however when launched subsequently with same input data and whatnot, it will hang on read. If I disable the COM port in Windows device manager and re-enable it, then everything goes fine on the next run. I thought maybe my program doesn't properly close the port due to compatability issues and it remains locked, however other terminal software such as teraterm could open it, more interestingly, if I try to run my program for the second time and it hangs, I can see the data it wrote to the serial port after I forcibly close it via task manager and open 3rd party terminal software. So seems like my C program cannot properly handle closing of the COM port (or perhaps flushing/releasing the read buffer, since it hangs on the read operation) and this is not an OS or platform issue. Note that during its work my program successfully reads and writes to the port several times (but again only during the first run after which I have to disable-enable the device or open another terminal software).

For reference, the device I communicate with is an USB modem.

I tried searching for the answer but had little luck, other than finding advise to close the port, which I already do.I have seen someone was in the same boat and they used the enable-disable trick, but like I said my research revealed that other terminal programs do not have this bug and they even help to release the COM port. I even found a software that uses Cygwin runtime, namely mobastorm, and it doesn't suffer from this problem.

Share Improve this question asked Nov 17, 2024 at 17:29 Curious UserCurious User 192 bronze badges 5
  • 1 Does your true code check the return values of all the various I/O calls? So far, the small code samples do not. Try that first. Note: best to post a minimal reproducible example. – chux Commented Nov 17, 2024 at 18:26
  • Your fixation on "closing of the COM port" and concern about the "serial port or its buffers aren't released" are misplaced. All the resources that your program acquired will be released by the OS when your program terminates. You can verify that by deleting the close() statement(s) from your program; you can then expect no difference in program (mis)behavior. Different behavior on program startup is more often an indication of improper/incomplete initialization (which you neglect to describe in any detail). – sawdust Commented Nov 18, 2024 at 23:34
  • @blackgreen - Why was the answer by TGDEV deleted? That post offered salient information that the OP seem to be unaware of. IMO that post offered more practical information that the second answer. – sawdust Commented Nov 18, 2024 at 23:41
  • @awdust, improper initialization would likely cause the code to fail on the first run. – Curious User Commented Nov 19, 2024 at 7:09
  • "improper initialization would likely cause the code to fail on the first run." - Maybe. But I'm also referring to an incomplete initialization, which will result in (re-)using the existing termios configuration (left by the previous program). When your program does not perform a complete termios configuration to its requirements, then you leave it to chance. That can cause an unreliable program, just like you seem to have. – sawdust Commented Nov 20, 2024 at 2:02
Add a comment  | 

1 Answer 1

Reset to default 0

To narrow down the issue, because it hangs on read() you could set the file descriptor for the serial port in none-block mode.

You can do this with the flag O_NDELAY or O_NONBLOCK.

fd_uart = open(device, O_RDWR | O_NOCTTY | O_SYNC | O_NONBLOCK);

I suggest before you call read() to check if there are bytes available for reading. You can do this with a I/O control command. If there are no bytes available or lesser bytes which you want to read, read() hangs, if the file descriptor is in block mode.

Sample for POSIX systems:

#include <ioctl.h>

int ret;
int bytes;

ret = ioctl(fd_uart, FIONREAD, &bytes);

Sample for Windows only:

#include <Windows.h>

int ret;
int bytes;
COMSTAT comst;
DWORD dwerr;

ret = ClearCommError(handle_uart, &dwerr, &comst);
bytes = (int) comst.cbInQue;

The number of bytes which are available for reading are stored in the variable bytes.

Another suggestion from me to set the serial port in raw mode:

#include <termios.h>

struct termios options;

/* Set raw input mode */
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
/* Enable receiver and set local mode */
options.c_cflag |= (CLOCAL | CREAD);
/* Set raw output mode */
options.c_oflag &= ~OPOST;
tcsetattr(fd_uart, TCSANOW, &options);

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745629352a4637008.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信