/** @file dma_mbuf.h
 * Module handling Direct Memory Access controller's multibuffer system
 *
 * The module provides a convenient tool to send data to a peripheral in a
 * buffered, low-latency, low-cpu usage, non-blocking way
 */

#ifndef _DMA_MBUF_H_
#define _DMA_MBUF_H_

//--includes--------------------------------------------------------------------

#include "../drv/dma.h"


//--type definitions------------------------------------------------------------

/**
 * Struct used by the multibuffer system. This system allows bufferized writes
 * to a peripheral with controlled latency, minimal cpu usage and customisable
 * buffer size
 */
struct DmaMultiBuffer {
	uint8_t* raw_buffer;     //the buffer to use as a multi-buffer

	uint16_t buffer_size;    //the size of the buffer

	uint8_t byte_index;      //index of the next byte to be written
	uint8_t buffer_index;    //index of the buffer being written to
	enum DmaPeriph dma;      //DMA peripheral used for transfers
	enum DmaChannel channel; //DMA channel used for transfers

	bool dma_running;        //whether the dam is currently running or not
};


//--functions-------------------------------------------------------------------

/**
 * Configure a DMA multibuffer for a single DMA channel. The given buffer is
 * divided into 2 to allow one part to be written to while the other is being
 * transfered by the DMA to a peripheral.
 * The peripheral's specific configuration must be handled separately.
 * Each peripheral's driver is responsible for providing the DMA configuration
 * for said peripheral, though it can be manually given too. Please note that
 * multiple peripherals may share the same DMA channel, which will cause issue
 * when used with this buffer.
 *
 * This buffer can be written to at any given time using dma_mbuf_write_byte(),
 * but its content are only written to the corresponding peripheral when
 * dma_mbuf_switch() is called.
 */
void dma_mbuf_configure(volatile struct DmaMultiBuffer* buffer,
		const struct DmaParam* param, enum DmaConfig priority,
		void* raw_buffer, uint16_t buffer_size);

/**
 * Write the given byte to the given buffer. Returns 0 if the write operation
 * was successfull, 1 otherwise. The function is non-blocking.
 *
 * Note: calling this function will not trigger a DMA transfer, see
 * dma_mbuf_switch() to do that
 */
uint32_t dma_mbuf_write_byte(volatile struct DmaMultiBuffer* buffer,
		uint8_t byte);

/**
 * Switch the buffers, triggering a DMA transfer while allowing writes to
 * continue. This function may fail if a DMA transfer is already running,
 * returning 1
 */
uint32_t dma_mbuf_switch(volatile struct DmaMultiBuffer* buffer);


#endif //_DMA_MBUF_H_

