/*
 * ll_crchandler.h
 *
 *  Created on: Oct 26, 2019
 *      Author: compi
 */

#ifndef LL_CRCHANDLER_H_
#define LL_CRCHANDLER_H_
#include <inttypes.h>
#include <platform/dma_ll.h>
#include "f4ll/ll_dmahelper.h"
#include "singleton.h"

extern "C" void _HandleCrcDmaIrq(void);

namespace f4ll {

class LL_CrcHandler : public Singleton<LL_CrcHandler>
{
	friend class Singleton<LL_CrcHandler>;

public:
	struct ICallback
	{
		virtual void CrcSucceeded(uintptr_t callbackParam, uint32_t crc, uint8_t task) = 0;
		virtual void CrcFailed(uintptr_t callbackParam, uint32_t crc, uint8_t task) = 0;
	};

	class SlotBase
	{
		friend class LL_CrcHandler;
	public:
		struct CrcTask {
			void const * volatile     m_address;			// changed to nullptr when execution starts
			uint16_t volatile         m_wordCount;
			LL_CrcHandler::ICallback *m_callback;
			uintptr_t                 m_callbackParam;
		};

	private:
		SlotBase *m_next = nullptr;
		uint8_t   m_taskCount;

		virtual CrcTask& operator[](int index) = 0;

	protected:
		SlotBase(unsigned int taskCount) : m_taskCount(taskCount) {}
		SlotBase() = delete;
		SlotBase(SlotBase const &other) = delete;
	};

	template <uint8_t n> class Slot : public SlotBase
	{
	public:
		Slot() : SlotBase(n) {}
		virtual CrcTask& operator[](int index) { return m_tasks[index]; }

	private:
		Slot::CrcTask m_tasks[n];
	};

	void     AttachSlot(SlotBase &slot);
	bool     Enqueue(SlotBase &slot, uint8_t task, void const *address, uint16_t len, ICallback *cb, uintptr_t cbParam);
	uint32_t Compute(SlotBase &slot, uint8_t task, void const *address, uint16_t len);

	bool     IsActive(SlotBase &slot, uint8_t task) const;
	bool     IsQueued(SlotBase &slot, uint8_t task) const;
	bool     IsRunning(SlotBase &slot, uint8_t task) const;

	void DmaTransferCompleted(void);

private:
	LL_CrcHandler(DMA_TypeDef *dma, uint32_t stream);

	friend void ::_HandleCrcDmaIrq(void);
	void StartNextTask(void);
	void WaitResults(SlotBase &slot, uint8_t task) const;

	LL_DmaHelper            m_dma;
	SlotBase * volatile     m_firstSlot = nullptr;
	SlotBase * volatile     m_activeSlot = nullptr;
	int	volatile            m_activeTask;
};


}	//	namespace f4ll

#endif /* LL_CRCHANDLER_H_ */
