UART Asynch API

Hello there,

I am trying to solve the following issue. On the UART I will be receiving a stream of messages. These messages can be each of different lengths. The length of the message is parsed later. So as I am receiving these messages, the first receive buffer is being filled up with data and at some point the buffer will be switched with a second one as per the documentation. As much as I understand this choice I am wondering if there is a way to reset the received data offset, other than disabling and re-enabling the UART.  

struct uart_event_rx {
	/** @brief Pointer to current buffer. */
	uint8_t *buf;
	/** @brief Currently received data offset in bytes. */
	size_t offset;
	/** @brief Number of new bytes received. */
	size_t len;
};

Thank you!
  • Hi 

    I will handle this ticket, since I have more experience with the UART async library. 

    Essentially it is true that the safe way to handle asynchronous messages of unknown length is to either include a packet header, or use SOF/EOF markers.

    A good example of a protocol using the SOF/EOF method is the SLIP protocol. SLIP only uses EOF, not SOF, which means you just have to wait for the EOF byte in your stream to know when the current packet is completed.
    In order to handle the case where your data is identical to the EOF marker a special escape sequence is used, requiring you to modify the data payload whenever the EOF or escape value is found in the data.

    To use slip as an example, you have to make one of the following conversions if either 0xC0 or 0xDB shows up in your data payload:
    0xC0 -> 0xDB, 0xDC
    0xDB -> 0xDB, 0xDD

    Then on the receiving side you need to do the opposite conversion before processing the data. 

    If you know that there will be a relatively long delay in time between each message you might be able to avoid this, by simply processing the data you have received after a certain time has passed. 

    You still need to handle the case where the buffers fill up, which I guess is at the heart of this query. 

    Can't you just maintain a separate buffer for the message and do a memcpy in the callback? 
    Then the value of the offset register should not matter. 
    If you get a callback with offset > 0 and (offset + length) == RX buffer size, then it is a strong indication that the buffers have filled up and that you will have to wait for the rest of the message to arrive later on. 

    Still, you need to implement some kind of timeout to handle the case where the message will fit exactly in the remaining bytes of the buffer, since in this case you will not get any more callbacks until a new message is sent. 

    To summarize I would recommend implementing some kind of packetization, like the SLIP protocol mentioned earlier. If this is not possible for whatever reason you could try to implement something using the timeout principle I described at the end. 

    Best regards
    Torbjørn

  • Hei Torbjørn,

    Thank you for the detailed answer. I think this will help other developers with the best way to use the UART Asynch API. 

    Unfortunately this is not solving it for us as we are using already a protocol which contains a SOF, but not an EOF. 

    In our case the way we have solved this issue is to: 

    1. uart_rx_disable() - disable the receiver - in case of a  UART_RX_RDY event.
    2. folllowed by a uart_rx_enable() - enable the receiver - in the UART_RX_DISABLED event, which is generated following point 1 above.  
    Still it is somewhat puzzling why the UART_RX_RDY event is used in so many instances. The presence of a new enumerator could bring further clarity. 
  • Hi

    Without an EOF I guess you are forced to either wait for the start of the next message, or use a timeout to indicate that the current message is complete. 

    For the timeout mechanism to work it is important that you never get breaks in a message that are longer than the timeout value, or you might inadvertently assume a message is complete when it is still ongoing. 

    Best regards
    Torbjørn

Related