SharedRingBuffer #135

Closed
opened 2020-07-09 15:21:22 +02:00 by muellerr · 0 comments
Owner

I discussed a smart way to read data via a serial bus today with Uli without putting too much pressure on the CPU.

The elegant solution would require a circular buffer, and uses the DLE encoder. A ring buffer is cotinuously checked by a task for packets, using the DLE decoder function (packets are preceded by a STX char and an ETX char).

Unfortunately, an additional copy operation is required when using system/driver calls: I can not get a pointer to the ring buffer (like getFreeElement for the LocalPool), because the write operation performed might not be contiguous.

So an additional copy operation is required. My concern was what happens if the serial data is coming in at a very high rate and the memcpy operation with the 10 bytes (another value could be chosen as well) takes too long?

I considered writing a getFreeElement() function for the ring buffer, but that would require each call to the ring buffer to be cleanly dividable by the total size (so, for example, 1000 byte ring buffer and each read and write operation writes and reads 10 bytes), so that is not really ideal and I think it also defeats the purpose of a ring buffer. But then I could pass that pointer to my DMA function directly. What do you think about that?

Polling the data would be performed by a polling task while another reading task (or the TMTC bridge, possibly even the generic one) handles analysing and reading the ring buffer.
So, the ring buffer is shared by two tasks, and thread-safety becomes an issue.
I wrote a shared ring buffer, which wraps a lock around some important ring buffer calls (similar to the PoolManager), and registers itself as a system object.

UPDATE: Another idea I just had: How about implementing and using the getFreeElement function while passing or constructing the underlying buffer larger than required to accomodate for the exceeding bytes. If getFreeElement is called and the number of bytes requested is larger thant the size till wrap, the number of exceeding bytes is stored inside a member variable. Then there would be an additional function like wrapSurplusBytes which checks whether that number is larger than 0 and copies the exceeding bytes to the start of the buffer. The resposibility to call wrapSurplusBytes would go to the TC analyser task (which has more breathing room anyway) and the polling DMA task can write to the ring buffer directly.

I discussed a smart way to read data via a serial bus today with Uli without putting too much pressure on the CPU. The elegant solution would require a circular buffer, and uses the DLE encoder. A ring buffer is cotinuously checked by a task for packets, using the DLE decoder function (packets are preceded by a STX char and an ETX char). Unfortunately, an additional copy operation is required when using system/driver calls: I can not get a pointer to the ring buffer (like getFreeElement for the LocalPool), because the write operation performed might not be contiguous. So an additional copy operation is required. My concern was what happens if the serial data is coming in at a very high rate and the memcpy operation with the 10 bytes (another value could be chosen as well) takes too long? I considered writing a getFreeElement() function for the ring buffer, but that would require each call to the ring buffer to be cleanly dividable by the total size (so, for example, 1000 byte ring buffer and each read and write operation writes and reads 10 bytes), so that is not really ideal and I think it also defeats the purpose of a ring buffer. But then I could pass that pointer to my DMA function directly. What do you think about that? Polling the data would be performed by a polling task while another reading task (or the TMTC bridge, possibly even the generic one) handles analysing and reading the ring buffer. So, the ring buffer is shared by two tasks, and thread-safety becomes an issue. I wrote a shared ring buffer, which wraps a lock around some important ring buffer calls (similar to the PoolManager), and registers itself as a system object. UPDATE: Another idea I just had: How about implementing and using the getFreeElement function while passing or constructing the underlying buffer larger than required to accomodate for the exceeding bytes. If getFreeElement is called and the number of bytes requested is larger thant the size till wrap, the number of exceeding bytes is stored inside a member variable. Then there would be an additional function like wrapSurplusBytes which checks whether that number is larger than 0 and copies the exceeding bytes to the start of the buffer. The resposibility to call wrapSurplusBytes would go to the TC analyser task (which has more breathing room anyway) and the polling DMA task can write to the ring buffer directly.
muellerr added the
feature
question
labels 2020-07-09 15:21:22 +02:00
Sign in to join this conversation.
No Milestone
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: fsfw/fsfw#135
No description provided.