/*
 * usart_handler.h
 *
 *  Created on: Sep 16, 2019
 *      Author: abody
 */

#ifndef USART_HANDLER_H_
#define USART_HANDLER_H_
#include <inttypes.h>
#include <platform/usart_ll.h>
#include "f4ll_c/dmahelper.h"
#include <f4ll_c/crcscheduler.h>

#ifdef __cplusplus
extern "C" {
#endif

struct usart_buffer_t;
struct usartstatus_t;
struct usartpacket_t;

typedef void (*pku_packetreceivedcallback_t)(void *userParam, struct usart_buffer_t *buffer);

void Pu_Init(
	struct usartstatus_t *st, USART_TypeDef *usart, DMA_TypeDef *dma,
	uint32_t stream_rx, uint32_t stream_tx,
	struct crcstatus_t *crcStatus,
	pku_packetreceivedcallback_t packetReceivedCallback, void * packetReceivedCallbackParam);

uint8_t* Pu_GetTxBuffer(struct usartstatus_t *status);

uint8_t Pu_Post(struct usartstatus_t *status, uint8_t const *payload, uint8_t length, uint8_t waitForCrcQueue);
void Pu_SetupReceive(struct usartstatus_t *status);
void Pu_SetupTransmit(USART_TypeDef *usart, DMA_TypeDef* dma, uint32_t stream, void *buffer, uint32_t length);
void Pu_ConsumePacket(struct usartstatus_t *status, uint8_t packetIndex);

void Pu_HandleRxDmaIrq(struct usartstatus_t *status);
void Pu_HandleTxDmaIrq(struct usartstatus_t *status);
void Pu_HandleUsartIrq(struct usartstatus_t *status);

// !!!Private!!! exposed only to make unit testing possible
void Pu_RxCrcComputedCallback(void *callbackParm, uint32_t calculatedCrc, uint8_t success);
uint8_t Pu_CheckHeader(struct usartpacket_t *packet);

DECLARE_MOCK(Pu_Init);
DECLARE_MOCK(Pu_GetTxBuffer);
DECLARE_MOCK(Pu_Post);
DECLARE_MOCK(Pu_SetupReceive);
DECLARE_MOCK(Pu_SetupTransmit);
DECLARE_MOCK(Pu_ConsumePacket);
DECLARE_MOCK(Pu_ConsumePacket);
DECLARE_MOCK(Pu_HandleRxDmaIrq);
DECLARE_MOCK(Pu_HandleTxDmaIrq);
DECLARE_MOCK(Pu_HandleUsartIrq);
DECLARE_MOCK(Pu_RxCrcComputedCallback);
DECLARE_MOCK(Pu_CheckHeader);

/******************************************************************************************
 * 
 * 
 * 
 */
 
struct usart_stats {
	uint32_t overrun;
	uint32_t hdrError;
	uint32_t lastErrHdr;
	uint32_t payloadErrror;
	uint32_t pep1, pep2;
	uint32_t dmaError;
	uint32_t rcvd;
	uint32_t premature_hdr;
	uint32_t premature_payload;
	uint32_t sent;
	uint32_t skiped;
};

struct usartpacketheader_t {
	uint8_t startByte;
	uint8_t serial;
	uint8_t payloadLength;
	uint8_t hash;
};

struct usartpacket_t {
	struct usartpacketheader_t header;
	//!!! should start on word offset !!!
	uint8_t	payload[256+sizeof(uint32_t)];	// extra room for crc32
} __attribute__((aligned));

struct usart_buffer_t {
	struct usartpacket_t packet;
	//transfer area ends here
	volatile uint8_t busy;
	volatile uint8_t error;
	uint16_t requestedLength;
	uint32_t errorInfo;
	struct usartstatus_t *usartStatus;
};

struct usartstatus_t {
	USART_TypeDef *usart;
	struct dmainfo_t rxDmaInfo;
	struct dmainfo_t txDmaInfo;
	struct crcstatus_t *crcStatus;
	struct crcslot_t crcSlot;
	struct crctask_t crcTasks[2];

	uint8_t rxSerial;
	uint8_t txSerial;
	struct usart_stats stats;
	uint8_t activeRxBuf;
	pku_packetreceivedcallback_t packetReceivedCallback;
	void *packetReceivedCallbackParam;
	struct usart_buffer_t txBuffer;
	struct usart_buffer_t rxBuffers[2];
};


#ifdef __cplusplus
}
#endif

#endif /* UART_HANDLER_H_ */
