One solution could be to implement your own sprintf
which is able to work with ring buffers. Unfortunately this won't help you out regarding a more basic problem: What would you do if your ringbuffer is full and you invoke sprintf
?
If your memory situation can afford it, I'd suggest another solution for this problem:
The idea is based on two linked lists of buffers (one list for the free buffers, one list as transmit queue). The buffers are equally sized so they can store a worst case length string. The buffers build a simple heap where allocation/deallocation is only dequeuing/enqueuing an element either from the free or from the transmission list.
Having equally sized buffers guarantees you don't suffer from outer fragmentation effects like "checkerboarding" while allocating memory dynamically. Building your own heap for this job would also give you full control over the total buffer size available for transmission tasks.
I could imagine this running as follows:
- You allocate a buffer from the free list to render the data into.
- Use your render functions (suchas sprintf) to render the data in the buffer
- Append the data to be sent to the transmission queue (and trigger a transmission if necessary)
For the DMA transfer you handle the transfer end IRQ. There you move the buffer just transferred to the "free list" and setup the transfer for next buffer in the queue.
This solution won't be the memory efficientiest but the runtime efficiency is good as you only write to the memory once and the allocation/deallocation is only fetching/storing a pointer somewhere. Of course you'll have to make sure that you don't get race conditions between your application and the IRQ for allocation/deallocation.
Maybe this idea gives you an inspiration to solve your requirements.