/**
  ******************************************************************************
  * @file    retarget.c
  *
  * @brief   Содержит реализацию функции инициализации UART, а также
  *          переопределенные библиотечные функции, относящиеся к printf.
  *          Также стоить обратить внимание, что для того чтобы все работало,
  *          в компилятор необходимо передаеть ключ -fno-builtin,
  *          а линкеру --specs=nosys.specs
  *
  *          Компилятор: GCC ARM 4.9.3
  *
  * @author  НИИЭТ
  *             - Богдан Колбов (bkolbov), kolbov@niiet.ru
  * @date    02.12.2015
  *
  ******************************************************************************
  * @attention
  *
  * ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО
  * ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ ГАРАНТИИ ТОВАРНОЙ
  * ПРИГОДНОСТИ, СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И ОТСУТСТВИЯ
  * НАРУШЕНИЙ, НО НЕ ОГРАНИЧИВАЯСЬ ИМИ. ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ
  * ПРЕДНАЗНАЧЕНО ДЛЯ ОЗНАКОМИТЕЛЬНЫХ ЦЕЛЕЙ И НАПРАВЛЕНО ТОЛЬКО НА
  * ПРЕДОСТАВЛЕНИЕ ДОПОЛНИТЕЛЬНОЙ ИНФОРМАЦИИ О ПРОДУКТЕ, С ЦЕЛЬЮ СОХРАНИТЬ ВРЕМЯ
  * ПОТРЕБИТЕЛЮ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ НЕСУТ
  * ОТВЕТСТВЕННОСТИ ПО КАКИМ-ЛИБО ИСКАМ, ЗА ПРЯМОЙ ИЛИ КОСВЕННЫЙ УЩЕРБ, ИЛИ
  * ПО ИНЫМ ТРЕБОВАНИЯМ, ВОЗНИКШИМ ИЗ-ЗА ИСПОЛЬЗОВАНИЯ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ
  * ИЛИ ИНЫХ ДЕЙСТВИЙ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ.
  *
  * <h2><center>&copy; 2015 ОАО "НИИЭТ"</center></h2>
  ******************************************************************************
  */

#include "retarget.h"

void retarget_init()
{
    GPIO_Init_TypeDef GPIO_InitStruct;
    GPIO_StructInit(&GPIO_InitStruct);

    // настройка портов и снятие сброса
    if (RETARGET_UART == NT_UART0)
    {
        // хак, необходимый, чтобы была возможность использовать вывоводы со 2 функцией
        GPIO_AltFuncConfig(NT_GPIOD, GPIO_Pin_11, GPIO_AltFunc_3); // uart0 tx
        GPIO_AltFuncConfig(NT_GPIOE, GPIO_Pin_0, GPIO_AltFunc_3); // uart0 rx
        // rx
        GPIO_InitStruct.GPIO_AltFunc = GPIO_AltFunc_2;
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AltFunc;
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
        GPIO_Init(NT_GPIOC, &GPIO_InitStruct);
        // tx
        GPIO_InitStruct.GPIO_Dir = GPIO_Dir_Out;
        GPIO_InitStruct.GPIO_Out = GPIO_Out_En;
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
        GPIO_Init(NT_GPIOC, &GPIO_InitStruct);
        // снятие сброса
        RCC_PeriphRstCmd(RCC_PeriphRst_UART0, ENABLE);
    }
    else if (RETARGET_UART == NT_UART1)
    {
        // rx
        GPIO_InitStruct.GPIO_AltFunc = GPIO_AltFunc_1;
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AltFunc;
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
        GPIO_Init(NT_GPIOA, &GPIO_InitStruct);
        // tx
        GPIO_InitStruct.GPIO_Dir = GPIO_Dir_Out;
        GPIO_InitStruct.GPIO_Out = GPIO_Out_En;
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
        GPIO_Init(NT_GPIOA, &GPIO_InitStruct);
        // снятие сброса
        RCC_PeriphRstCmd(RCC_PeriphRst_UART1, ENABLE);
    }
    else if (RETARGET_UART == NT_UART2)
    {
        // rx
        GPIO_InitStruct.GPIO_AltFunc = GPIO_AltFunc_1;
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AltFunc;
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;
        GPIO_Init(NT_GPIOF, &GPIO_InitStruct);
        // tx
        GPIO_InitStruct.GPIO_Dir = GPIO_Dir_Out;
        GPIO_InitStruct.GPIO_Out = GPIO_Out_En;
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
        GPIO_Init(NT_GPIOF, &GPIO_InitStruct);
        // снятие сброса
        RCC_PeriphRstCmd(RCC_PeriphRst_UART2, ENABLE);
    }
    else if (RETARGET_UART == NT_UART3)
    {
        // хак, необходимый, чтобы была возможность использовать вывоводы со 2 функцией
        GPIO_AltFuncConfig(NT_GPIOF, GPIO_Pin_12 | GPIO_Pin_13, GPIO_AltFunc_3); // uart3 tx rx
        // rx
        GPIO_InitStruct.GPIO_AltFunc = GPIO_AltFunc_2;
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AltFunc;
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
        GPIO_Init(NT_GPIOD, &GPIO_InitStruct);
        // tx
        GPIO_InitStruct.GPIO_Dir = GPIO_Dir_Out;
        GPIO_InitStruct.GPIO_Out = GPIO_Out_En;
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
        GPIO_Init(NT_GPIOD, &GPIO_InitStruct);
        // снятие сброса
        RCC_PeriphRstCmd(RCC_PeriphRst_UART3, ENABLE);
    }

    // включение тактирования UART
    RCC_UARTClkCmd(RETARGET_UART, ENABLE);

    // настройка блоков UART
    UART_Init_TypeDef UART_InitStruct;
    UART_StructInit(&UART_InitStruct);
    UART_InitStruct.UART_BaudRate = RETARGET_BAUDRATE_VAL;
    UART_InitStruct.UART_ClkFreq = RETARGET_CLK_VAL;
    UART_InitStruct.UART_DataWidth = UART_DataWidth_8;

    UART_Init(RETARGET_UART, &UART_InitStruct);
    UART_Cmd(RETARGET_UART, ENABLE);

    // выделяем место под буффер
    setvbuf(stdout, NULL, _IONBF, 0);
}

int _write (int fd, char *ptr, int len)
{
    /* Write "len" of char from "ptr" to file id "fd"
     * Return number of char written.
     * Need implementing with UART here. */
    int i = 0;

    while (ptr[i] && (i < len))
    {  
        while(UART_FlagStatus(RETARGET_UART, UART_Flag_Busy));
        UART_SendData(RETARGET_UART, ptr[i]);
        ITM_SendChar(ptr[i]);
        if (ptr[i] == '\n')
        {
            while(UART_FlagStatus(RETARGET_UART, UART_Flag_Busy));
            UART_SendData(RETARGET_UART, '\r');
            ITM_SendChar('\r');
        }
        i++;
    }

    return len;
}

void _ttywrch(int ch)
{
  /* Write one char "ch" to the default console
   * Need implementing with UART here. */
    while(UART_FlagStatus(RETARGET_UART, UART_Flag_Busy));
    UART_SendData(RETARGET_UART, ch);
}

int _read(int file, char *ptr, int len)
{
    return 0;
}
