/*
 * ll_dmadrivenusartcore.cpp
 *
 *  Created on: Nov 4, 2019
 *      Author: abody
 */

#include "f4ll/usartcore.h"

namespace f4ll {

UsartCore::UsartCore(USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t streamRx, uint32_t streamTx)
: m_usart(usart)
, m_rxDma(dma, streamRx)
, m_txDma(dma, streamTx)
{
	LL_DMA_EnableIT_TC(dma, streamRx);
	LL_DMA_EnableIT_TE(dma, streamRx);
	LL_DMA_EnableIT_TC(dma, streamTx);
	LL_DMA_EnableIT_TE(dma, streamTx);
	LL_USART_EnableIT_IDLE(usart);
	LL_USART_EnableIT_ERROR(usart);
}


void UsartCore::UsartIsr()
{
	if(LL_USART_IsActiveFlag_TC(m_usart) && LL_USART_IsEnabledIT_TC(m_usart)) { // transmission complete
		LL_USART_DisableIT_TC(m_usart);
		TransmissionComplete();
	} else if(LL_USART_IsEnabledIT_ERROR(m_usart)) {
		uint32_t status = m_usart->SR;
		volatile uint32_t tmpreg = m_usart->DR; // clearing some of the error/status bits in the HW
		(void) tmpreg;

		if(status & USART_SR_IDLE) {
			ReceiverIdle();
		}
		if(status & USART_SR_FE) {
			FramingError();
		}
		if(status & USART_SR_ORE) {
			Overrun();
		}
	}
}


void UsartCore::RxDmaIsr()
{
	if(*m_rxDma.GetIsReg() & m_rxDma.GetTcMask()) {
		*m_rxDma.GetIfcReg() = m_rxDma.GetTcMask();
		if(m_rxDma.IsEnabledIt_TC())
			RxDmaTransferComplete();
	}
	if(*m_rxDma.GetIsReg() & m_rxDma.GetHtMask()) {
		*m_rxDma.GetIfcReg() = m_rxDma.GetHtMask();
		if(m_rxDma.IsEnabledIt_HT())
			RxDmaHalfTransfer();
	}
	if(*m_rxDma.GetIsReg() & m_rxDma.GetTeMask()) {
		*m_rxDma.GetIfcReg() = m_rxDma.GetTeMask();
		if(m_rxDma.IsEnabledIt_TE())
			RxDmaError(DmaHelper::DmaErrorType::Transfer);
	}
	if(*m_rxDma.GetIsReg() & m_rxDma.GetFeMask()) {
		*m_rxDma.GetIfcReg() = m_rxDma.GetFeMask();
		if(m_rxDma.IsEnabledIt_FE())
			RxDmaError(DmaHelper::DmaErrorType::Fifo);
	}
	if(*m_rxDma.GetIsReg() & m_rxDma.GetDmeMask()) {
		*m_rxDma.GetIfcReg() = m_rxDma.GetDmeMask();
		if(m_rxDma.IsEnabledIt_DME())
			RxDmaError(DmaHelper::DmaErrorType::DirectMode);
	}
}


void UsartCore::TxDmaIsr()
{
	if(*m_txDma.GetIsReg() & m_txDma.GetTcMask()) {	// DMA transfer complete
		*m_txDma.GetIfcReg() = m_txDma.GetTcMask();
		if(m_txDma.IsEnabledIt_TC())
			TxDmaTransferComplete();
	}
	if(*m_txDma.GetIsReg() & m_txDma.GetHtMask()) {
		*m_txDma.GetIfcReg() = m_txDma.GetHtMask();
		if(m_txDma.IsEnabledIt_HT())
			TxDmaHalfTransfer();
	}
	if(*m_txDma.GetIsReg() & m_txDma.GetTeMask()) {
		*m_txDma.GetIfcReg() = m_txDma.GetTeMask();
		if(m_txDma.IsEnabledIt_TE())
			TxDmaError(DmaHelper::DmaErrorType::Transfer);
	}
	if(*m_txDma.GetIsReg() & m_txDma.GetFeMask()) {
		*m_txDma.GetIfcReg() = m_txDma.GetFeMask();
		if(m_txDma.IsEnabledIt_FE())
			TxDmaError(DmaHelper::DmaErrorType::Fifo);
	}
	if(*m_txDma.GetIsReg() & m_txDma.GetDmeMask()) {
		*m_txDma.GetIfcReg() = m_txDma.GetDmeMask();
		if(m_txDma.IsEnabledIt_DME())
			TxDmaError(DmaHelper::DmaErrorType::DirectMode);
	}
}


void UsartCore::SetupTransmit(void const *buffer, uint16_t length)
{
	LL_DMA_ConfigAddresses(m_txDma.GetDma(), m_txDma.GetStream(), reinterpret_cast<uint32_t>(buffer),
			LL_USART_DMA_GetRegAddr(m_usart), LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
	LL_DMA_SetDataLength(m_txDma.GetDma(), m_txDma.GetStream(), length);
	LL_USART_EnableDMAReq_TX(m_usart);
	LL_DMA_EnableStream(m_txDma.GetDma(), m_txDma.GetStream());
}


void UsartCore::SetupReceive(void *buffer, uint16_t length)
{
	LL_DMA_ConfigAddresses(m_rxDma.GetDma(), m_rxDma.GetStream(), LL_USART_DMA_GetRegAddr(m_usart),
			reinterpret_cast<uint32_t>(buffer), LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
	LL_DMA_SetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream(), length);
	LL_USART_EnableDMAReq_RX(m_usart);
	LL_USART_ClearFlag_ORE(m_usart);
	LL_DMA_EnableStream(m_rxDma.GetDma(), m_rxDma.GetStream());
}

} /* namespace f4ll */
