/********************************* (C) РОТЕК ***********************************
 * @module  usart
 * @file    usart.c
 * @version 1.0.0
 * @date    XX.XX.XXXX
 * $brief   Template
 *******************************************************************************
 * @history     Version  Author         Comment
 * XX.XX.XXXX   1.0.0    Telenkov D.A.  First release.
 *******************************************************************************
 */

#include "stm32f4xx.h"  
#include "usart.h"
//#include "port_microrl.h"
#include "main.h"
#include "ring_buf.h"
//#include <stdio.h>
#include "FreeRTOS.h"
#include "semphr.h"

#define UPS_RBUF_SIZE 100
rbuf_t ups_rx_rbuf, ups_tx_rbuf;
uint32_t ups_rx_fifo[UPS_RBUF_SIZE];
uint32_t ups_tx_fifo[UPS_RBUF_SIZE];
SemaphoreHandle_t xSem_rx_buf;

USART_InitTypeDef USART_InitStructure;

void uart_hw_init(USART_TypeDef *uart, uint32_t baud, uint16_t wordlen, uint16_t parity, uint16_t stop) {
	uint16_t wordlen_tmp;

	if (wordlen == 8)
		wordlen_tmp = USART_WordLength_8b;
	if (wordlen == 9)
		wordlen_tmp = USART_WordLength_9b;

	USART_InitStructure.USART_BaudRate = baud;
	USART_InitStructure.USART_WordLength = wordlen_tmp;
	USART_InitStructure.USART_StopBits = stop;
	USART_InitStructure.USART_Parity = parity;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

	USART_DeInit(uart);

	if (uart == USART1) {
		RCC->APB2ENR |= RCC_APB2Periph_USART1;
		NVIC_SetPriority(USART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0x05, 0));
		NVIC_EnableIRQ(USART1_IRQn);
		USART_Init(USART1, &USART_InitStructure);
		USART_Cmd(USART1, ENABLE);
		USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
		USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
	}

	if (uart == USART2) {
		RCC->APB1ENR |= RCC_APB1Periph_USART2;
		NVIC_SetPriority(USART2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0x05, 0));
		NVIC_EnableIRQ(USART2_IRQn);
		USART_Init(USART2, &USART_InitStructure);
		USART_Cmd(USART2, ENABLE);
		USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
		USART_ITConfig(USART2, USART_IT_TXE, DISABLE);
	}

    if (uart == USART3) {
        RCC->APB1ENR |= RCC_APB1Periph_USART3;
        NVIC_SetPriority(USART3_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0x05, 0));
        NVIC_EnableIRQ(USART3_IRQn);
        USART_Init(USART3, &USART_InitStructure);
        USART_Cmd(USART3, ENABLE);
    USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
    USART_ITConfig(USART3, USART_IT_TXE, DISABLE);
    }
}

void InitUSART(void) {
	xSem_rx_buf = xSemaphoreCreateCounting( UPS_RBUF_SIZE, 0 );
	rbuf32_init(&ups_tx_rbuf, ups_tx_fifo, UPS_RBUF_SIZE);
	rbuf32_init(&ups_rx_rbuf, ups_rx_fifo, UPS_RBUF_SIZE);
	uart_hw_init(UPS_USART, UPS_USART_BAUD, UPS_USART_WORD_LEN, UPS_USART_PARITY, UPS_USART_STOP_BIT);
}

void ups_putchar(uint16_t byte) {
	UPS_USART->CR1 &= ~USART_CR1_TXEIE;
	if (!rbuf_isfull(&ups_tx_rbuf)) {
		rbuf32_put(&ups_tx_rbuf, (uint32_t)(byte));
	}
	UPS_USART->CR1 |= USART_CR1_TXEIE;
}

int ups_send_block(void *data, uint8_t len) {
	int i = 0;
	uint32_t s_temp = 0;
	UPS_USART->CR1 &= ~USART_CR1_TXEIE;
	//DBG printf("STOP \r\n");
	while (i < len) {
		if (!rbuf_isfull(&ups_tx_rbuf)) {
			s_temp = ((uint8_t *)data)[i++];
			rbuf32_put(&ups_tx_rbuf, s_temp);
		}
		else
			break;
	}
	UPS_USART->CR1 |= USART_CR1_TXEIE;
	return i;
}

int ups_getchar(unsigned int timeout) {
	int res;
	res = xSemaphoreTake( xSem_rx_buf, (TickType_t)timeout );
	if (res == pdFALSE) {
		return -1;
	}
	rbuf32_get(&ups_rx_rbuf, &res);
//	DBG printf("STOP \r\n");
//	DBG printf("wr: %d 0x%x\r\n", rs485_rx_rbuf.read_index,res);
	return res;
}



//inline void rs232_irq_handler(void)
void rs232_irq_handler(void)
{
	uint32_t c = 0;

	static BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	if ((UPS_USART->SR & USART_SR_ORE)) {
		c = (uint32_t)UPS_USART->DR;
		//DBG printf("overrunRS485\r\n");
	}
	if (USART_GetITStatus(UPS_USART, USART_IT_TXE) != RESET) {
		if(rbuf32_get(&ups_tx_rbuf, &c)) {
			UPS_USART->DR = (uint16_t)c;
			//DBG printf("wr: %d 0x%x\r\n", rs485_tx_rbuf.read_index,c);
		}
		else {
			UPS_USART->CR1 &= ~USART_CR1_TXEIE;
			UPS_USART->CR1 |= USART_CR1_RXNEIE;
		}
			USART_ClearITPendingBit(UPS_USART, USART_IT_TXE);
	}
	if(USART_GetITStatus(UPS_USART, USART_IT_RXNE) != RESET)
	{
		c = (uint32_t)UPS_USART->DR;
		//DBG printf("read: %d 0x%x\r\n", rs485_rx_rbuf.write_index,c);
		if (!rbuf_isfull(&ups_rx_rbuf))
			rbuf32_put(&ups_rx_rbuf, c);
		USART_ClearITPendingBit(UPS_USART, USART_IT_RXNE);
		xSemaphoreGiveFromISR(xSem_rx_buf, &xHigherPriorityTaskWoken);
		portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
	}
}


void USART1_IRQHandler(void) {

}

void USART2_IRQHandler(void) {
	rs232_irq_handler();
}

void USART3_IRQHandler(void) {

}


/********************************* (C) РОТЕК **********************************/
