#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <hal/pin.h>
#include <libopencm3/stm32/timer.h>
#include "funkce_spolecne.h"
#include "test_desky.h"

void timer10_inicializace_1s(void)
{
    rcc_periph_clock_enable(RCC_TIM10);
    timer_update_on_overflow(TIM10_BASE);   //URS = 0;
    timer_enable_update_event(TIM10_BASE);  //UDIS = 0;
    timer_set_period(TIM10_BASE,10000);     //pro 168MHz - 1s
    timer_set_prescaler(TIM10_BASE,16800);

    timer_clear_flag(TIM10_BASE,TIM_SR_UIF);
}

void timer10_cekej (void)
{
    timer_enable_counter(TIM10_BASE);   //TIM_CR1(TIM10_BASE) |= TIM_CR1_CEN;

    while (!timer_get_flag(TIM10_BASE,TIM_SR_UIF))
    {
    }
    timer_disable_counter(TIM10_BASE);
    timer_clear_flag(TIM10_BASE,TIM_SR_UIF);
}

void FPGA_propojeni_test(void)
{
    uint32_t FPGA_piny [] = {FPGA1, FPGA2, FPGA3, FPGA4, FPGA5, FPGA6, FPGA7, FPGA8, FPGA9, FPGA10, FPGA11};

    for (uint16_t i = 0; i < sizeof(FPGA_piny) / sizeof(FPGA_piny[0]); i++)
    {
        pin_pull_disable(FPGA_piny[i]);
        pin_output_pushpull(FPGA_piny[i]);
        pin_set(FPGA_piny[i],true);
    }
}

bool PHY_NAND_TREE_TEST (void)
{
    bool test_pin0 = 0;
    bool test_pin = 0;
    uint32_t PHY_NAND_TREE_piny [] = {PHY_MII_MDIO, PHY_MII_MDC,
                            PHY_MII_RXD3, PHY_MII_RXD2, PHY_MII_RXD1, PHY_MII_RXD0, PHY_MII_RXDV, PHY_MII_RXC,
                            PHY_MII_RXER, PHY_INTRP, //PHY_INTRP - #NAND_TREE
                            PHY_MII_TXC, PHY_MII_TXEN, PHY_MII_TXD0, PHY_MII_TXD1, PHY_MII_TXD2, PHY_MII_TXD3,
                            PHY_MII_COL};
                            //LDE0, LED1 - nejsou pripojeny k mikroprocesoru
                            //PHY_MII_CRS - vystup

    pin_pull_disable(PHY_INTRP);
    pin_output_pushpull(PHY_INTRP);
    pin_pull_disable(PHY_RST);
    pin_output_pushpull(PHY_RST);

    pin_pull_disable(PHY_MII_CRS);
    pin_input(PHY_MII_CRS);

    pin_set(PHY_INTRP,false);
    wait_cyklu(0xFFFF);
    pin_set(PHY_RST,false);
    wait_cyklu(0xFFFF);
    pin_set(PHY_RST,true);
    wait_cyklu(0xFFFF);


    for (uint16_t i = 0; i < sizeof(PHY_NAND_TREE_piny) / sizeof(PHY_NAND_TREE_piny[0]); i++)
    {
        pin_pull_disable(PHY_NAND_TREE_piny[i]);
        pin_output_pushpull(PHY_NAND_TREE_piny[i]);
        pin_set(PHY_NAND_TREE_piny[i],true);
    }

    test_pin = pin_get(PHY_MII_CRS);
    pin_set(LED3,test_pin);
    pin_set(LED2,test_pin);

    for (uint16_t i = 0; i < sizeof(PHY_NAND_TREE_piny) / sizeof(PHY_NAND_TREE_piny[0]); i++)
    {
        test_pin0 = pin_get(PHY_MII_CRS);
        pin_set(PHY_NAND_TREE_piny[i],false);
        wait_cyklu(0xFFFF);

        pin_toggle(LED2);
        test_pin = pin_get(PHY_MII_CRS);

        if (test_pin0 == test_pin)
        {
            pin_set(PHY_INTRP,true);    //vypnuti NAND_TREE
            wait_cyklu(0xFFFF);
            pin_set(PHY_RST,false);
            wait_cyklu(0xFFFF);
            pin_set(PHY_RST,true);
            wait_cyklu(0xFFFF);
            pin_input(PHY_INTRP);
            return false;
        }

        pin_set(LED3,test_pin);
        wait_cyklu(0x1FFFFF);
    }
    pin_set(LED2,false);
    pin_set(LED3,false);

/*Vypnuti NAND_TREE modu*/

    pin_set(PHY_INTRP,true);
    wait_cyklu(0xFFFF);
    pin_set(PHY_RST,false);
    wait_cyklu(0xFFFF);
    pin_set(PHY_RST,true);
    wait_cyklu(0xFFFF);
    pin_input(PHY_INTRP);

    return true;
}

void test_desky(void)
{
    uint16_t port_E_piny = 0xFF80; //maska pro vyvedene piny
    bool test_pin = false;

    rcc_clock_setup_hse_3v3(&hse_25mhz_3v3[CLOCK_3V3_168MHZ]);  /* nastaveni systemovych hodin 168 MHz
                                                                  apb1 = 42 MHz
                                                                  apb2 = 84 MHz
                                                                */
    MCO2_inicializace();
    povoleni_hodin_GPIO_vsechny();

    LED_a_TL_inicializace();
    pin_set(LED1,true);

    timer10_inicializace_1s();

/*Testovani PHY pomoci NAND_TREE*/
    test_pin = PHY_NAND_TREE_TEST();
    pin_set(LED2, test_pin);
    timer10_cekej();
    timer10_cekej();
/*Testovani PHY pomoci NAND_TREE konec*/

/*Test propojeni STM a FPGA*/
    FPGA_propojeni_test();
/*Test propojeni STM a FPGA konec*/

/*Nasteveni vsech pinu vyvedenych z mikroprocesoru na pinove listy na hodnotu 1 */
    gpio_mode_setup(GPIOE,GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, port_E_piny);
    gpio_set(GPIOE, port_E_piny );

    gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, 0x1F00); // 0x1F00 == GPIO8 | GPIO9 | GPIO10 | GPIO11 | GPIO12
    gpio_set(GPIOA, 0x1F00);
/*Nasteveni vsech pinu vyvedenych z mikroprocesoru na pinove listy na hodnotu 1 konec*/

    while (true)
    {
       timer10_cekej();
       pin_toggle(LED1);
       pin_set(LED2,!pin_get(TL1));
       pin_set(LED3,!pin_get(TL2));
    }
}
