/*
 * interrupt.h
 *
 *  Created on: Aug 29, 2019
 *      Author: abody
 */

#ifndef CRC_HANDLER_H_
#define CRC_HANDLER_H_

#include <inttypes.h>

#ifdef HAVE_CONFIG
#include "config.h"
#endif	//	HAVE_CONFIG

#include <platform/crc_ll.h>
#include <f4ll_cpp/dmahelper.h>

namespace f4ll_cpp
{

class CrcScheduler {
public:
	struct ICrcCallback {
		virtual void CrcCalculationCompleted(void*, uint32_t, uint8_t) = 0;
	};

	struct crctask_t {
		void * volatile address;
		uint16_t wordCount;
		ICrcCallback* callback;
		void *callbackParam;
	};

	struct crcslot_t {
		uint16_t count;
		struct crcslot_t *next;
		struct crctask_t *tasks;
	};

	CrcScheduler(CRC_TypeDef *crcUnit, DMA_TypeDef *dma, uint32_t stream);

	uint8_t GetActiveTask(struct crcslot_t **slot_out);
	bool IsTaskQueued(struct crcslot_t *slot, uint8_t task);
	bool IsTaskBusy(struct crcslot_t *slot, uint8_t task);

	void WaitResults(struct crcslot_t *slot, uint8_t task);

	void AttachTasks(struct crcslot_t *slot, struct crctask_t *tasks, uint8_t taskCount);

	uint8_t Enqueue(struct crcslot_t *slot, uint8_t task, void *address, uint16_t len,
			ICrcCallback* callback, void* callbackParam);
	uint32_t Compute(struct crcslot_t *slot, uint8_t task, void *address, uint16_t len);
	static void HandleDmaIrq(void *param) { reinterpret_cast<CrcScheduler*>(param)->_HandleDmaIrq(); }
	void _HandleDmaIrq();

private:
	void StartNextTask();

	CRC_TypeDef *m_crcUnit;
	DmaHelper m_dma;

	volatile crcslot_t *m_activeSlot;
	volatile uint8_t m_activeTask;

	crcslot_t *m_firstSlot;
};

}	//	f4ll_cpp

#endif /* CRC_HANDLER_H_ */
