C Read From Serial Port

  1. Ansi C Read Serial Port
  2. C Read From Serial Portal
  3. C Read From Serial Port Charlotte
  4. Serial Port Read
  5. Python Read From Serial Port
Active5 years, 2 months ago

Serial Port Reader (Serial Port Monitor) is a powerful and user-friendly serial data recorder that gives you the capacity to begin reading any serial port in a system at any time, even if the port is already in use by another application. Use this method for reading characters from the serial port. If it is necessary to switch between reading text and reading binary data from the stream, select a protocol that carefully defines the boundary between text and binary data, such as manually reading bytes and decoding the data. SerialPort (RS-232 Serial COM Port) in C#.NET This article explains how to use the SerialPort class in.NET to read and write data, determine what serial ports are available on your machine, and how to send files.

$begingroup$

I'm receiving data from a serial port in C, using Serial Programming Guide for POSIX Operating Systems as a guide.

The data I receive should be always 10 bytes in length but I want to be sure that, if there is any error (more or less bytes received), reading will clear buffer before the next data arrive, so that there is always proper data in the buffer to be processed. I'm using select to monitor serial file descriptor and local socket. I figured out that I can clean serial buffer in case there was something left from previous transmission, when device is not sending for some period of time.

Question is: is this the right solution?

main.c:

serial_port.c

Click on Start and type Windows Media Player to bring it up.If you are in Now Playing mode, you should switch to the Library mode by clicking on Switch to Library.Step 2: Navigate to Organize - Layout and ensure that Show menu bar is ticked. Steps to Change Skins on Windows Media PlayerStep 1: Of course, you will need to start the Windows Media Player. Windows media player skins. All skins support the basic functionalities and some of them have additional features too, to my surprise.

Some more info. I'm querying device every 5 seconds for data, and it should always respond with 10 bytes packets: so data should come fairly quickly into serial buffer, and then a few seconds of silence; sometimes however the device can send data on its own, I don't know when, but also as a 10 bytes packets.

I was doing some test with my program and minicom connected on the other side.

Until I was sending data like

program was reading what it supposed to read:

Problem arises when I send on minicom:

Usually what was read was:

so next, when I wrote on minicom proper data:

program was reading

and every next read was bad because of leftovers in buffer from previous read.

When I added clearing buffer after 1 or 2 seconds when nothing is read, then I'm sure any leftovers are cleared before next transmission.

I read about this VMIN settings but decided against because of this leftovers.

Also this data 1234567890 is just an example. In fact 10 bytes consist of:

  • Byte #1 - always some constant to mark begining of transmission like 0xA5
  • Byte #2 through #9 byte - data
  • Byte #10 - control sum from all previous bytes.

So after I have 10 bytes packet received I can verify if it has proper data or is somehow corrupted: so if one transmission fails, I should be ok, especially when I can clear the buffer before next data coming in.

ChrisWC read from serial port linux
12.4k1 gold badge27 silver badges73 bronze badges
user2018761user2018761
$endgroup$

migrated from stackoverflow.comJan 21 '14 at 17:51

This question came from our site for professional and enthusiast programmers.

5 Answers

$begingroup$

The code you posted contains no error-recovery at all. It's a bit off-topic on this site to ask how to implement a new feature (error-recovery); but I'll try.

Ansi C Read Serial Port

It's not clear what your communication protocol looks like. It might be:

  1. A continuous stream of bytes, to be split into packets of 10
  2. 10-byte packets, with a measurable delay between packets, no reply expected
  3. 10-byte packets, after which silence until there is a reply, perhaps with a retry if there no reply

I'll assume it isn't 1. because that has little opportunity for error-recovery: if a byte were ever lost then you wouldn't know where the boundary is between 'packets', if it's a continuous stream of bytes, unless you use 'framing' and 'escape sequences' in the data.

So I'll assume that it's 2. or 3.. In either case, what's important is:

  • There are 10 bytes received (probably received quickly with little or no delay between bytes)
  • There is then a delay (no bytes received) after those 10 bytes.

Setting Read Timeouts looks interesting. It may be your best algorithm: set VMIN to say that you want to receive no more or less than exactly 10 bytes when you read.

However that may have a problem:

However, the timeout only applies to the first character read, so if for some reason the driver misses one character inside the N byte packet then the read call could block forever waiting for additional input characters.

You don't say why you want error-recovery after losing a character: perhaps you sometimes get overruns in the driver, or bit parity errors from the serial port?

'Setting Input Parity Options' talks about handling the parity errors:

  1. Replace/mark the byte with an error byte

    If you do this then you can be more sure that you will get 10 bytes; but you can only do it if the protocol allows you to recognize an illegal byte value.

  2. Or remove the error byte

    If you do this then you must be able to recover from getting 9 bytes sometimes.

The data I receive should be always 10 bytes in length but I want to be sure that, if there is any error (more or less bytes received), reading will clear buffer before the next data arrive, so that there is always proper data in the buffer to be processed.

Reading should empty the buffer, if your sizeof(tmp_buffer) is bigger is the number of bytes queued in the driver. However:

  • It depends on the read mode (e.g. a read may block forever instead of clearing the buffer, if VMIN is set to non-zero)
  • If there are, somehow, very many received bytes enqueued in the driver, then you may have to read repeatedly until the driver is empty.
  • Immediately after you read, there may be more bytes in the driver: for example if the serial port is flow-controlled, reading from the driver allows the device to send again / send more.

Whether you can clear the buffer 'before the next data arrive' is difficult to say: I don't know when the next data is supposed to arrive.

Depending on how you handle parity errors, maybe bytes are never lost. If bytes are sometimes lost then you may want to implement logic like:

Instead of actually setting a timer, above, perhaps loop doing a blocking-read-with-timeout (which either reads the bytes, or expires).

As well as handling too few bytes (above), you could modify the above to check for receiving more than 10 bytes: after you receive 10 bytes, do another blocking-read-with-small-timeout to verify that there are no more bytes to receive. If there are extra bytes, then read them all before returning to the 'waiting-for-next-10-bytes' state (otherwise, these extra bytes will mess up your next 10-byte packet).

I think there's an obvious bug in the code. After you read 16 bytes, you completely clear your serial_buffer by zeroing si_processed, and you then think 'success!' after each next 10 bytes you read.

Instead you should:

  • If you read too much data, don't discard the extra bytes: instead use memmove to move them to the beginning of the buffer (assuming they're the start of the next packet), and then read the subsequent bytes into the vacant space after them.

Something like:

  • After you read any bytes, verify whether the start byte is your 0xA5 value, and discard the bytes if not.

Something like:

ChrisWChrisW
12.4k1 gold badge27 silver badges73 bronze badges
$endgroup$$begingroup$

You shouldn't need to call usleep() to throttle the loop. If you need usleep() prevent the loop from consuming 100% of the CPU, then something is wrong, since select() is supposed to be the gatekeeper that lets the loop continue when input is available to be processed. Perhaps you are failing to drain the socket or serial port completely in your input handlers, so that select() always returns immediately.

Community
200_success200_success
136k21 gold badges175 silver badges447 bronze badges
$endgroup$$begingroup$

C Read From Serial Portal

The final version, in case someone was interested.

main.c

serial_port.h

serial_port.c


$endgroup$$begingroup$

I would modify your serial reading function in a few ways, firstly by changingits name to reflect what it does. I would also move the accumulation bufferinto the function, making it and its position counter static (which meansthey stick around without losing their value between calls) . Also define thedetails of the packet in #defines.

More extensive changes are required to recover from a loss of synchronizationto the data or on failure of the check-sum. If the check-sum fails, I don'tthink it is safe to discard the whole packet unless you can guarantee that thesentinel value (0xA5 or whatever) never occurs within the packet or itscheck-sum. As you don't mention it, I'm assuming we can't guarantee this,although it is clearly possible to arrange the data protocol to provide such aguarantee.

Without the guarantee, we need to check the check-sum within the readingfunction and to re-sync to the next sentinel on error.

I think this might be easier to achieve by making the file descriptornon-blocking and reading one byte at a time. As your data rate is slow, thisis not a great overhead. And as your baud rate is slow (compared to processorspeed) the chances are that your select will unblock after each receivedcharacter.

You should also check for errors in the read call and return an error unlessthe read was interrupted (EINTR) - in which case the fd will still selectavailable and the function will be called again - or no data was available(EAGAIN).

Here is some untested code to do this.

C Read From Serial Port Charlotte

William MorrisWilliam Morris
$endgroup$$begingroup$

You pass &tmp_input to select but then pass &input to the FD_ISSETs. These two fd_set objects are different. The input fd_set is set once, so FD_ISSET may well lie to you and your reads will fail.

Jamal
32k12 gold badges123 silver badges231 bronze badges

Serial Port Read

stuartstuart
$endgroup$

Python Read From Serial Port

Not the answer you're looking for? Browse other questions tagged cstreamerror-handlingtimeoutserial-port or ask your own question.