#include "stm32f4xx.h"

typedef uint8_t BYTE;
typedef uint16_t WORD;
typedef uint32_t DWORD;
typedef uint64_t QWORD;
typedef int8_t INT8;
typedef int16_t INT16;
typedef int32_t INT32;
typedef int64_t INT64;

// dekokotizace (prevedeni masky z kokoti knihovny na bitovy offset)
#define dekkt(k)(k&0x00000001 ? 0  : k&0x00000002 ? 1  : k&0x00000004 ? 2  : k&0x00000008 ? 3  : k&0x00000010 ? 4  : k&0x00000020 ? 5:  k&0x00000040 ? 6:  k&0x00000080 ? 7:  \
                 k&0x00000100 ? 8  : k&0x00000200 ? 9  : k&0x00000400 ? 10 : k&0x00000800 ? 11 : k&0x00001000 ? 12 : k&0x00002000 ? 13: k&0x00004000 ? 14: k&0x00008000 ? 15: \
                 k&0x00010000 ? 16 : k&0x00020000 ? 17 : k&0x00040000 ? 18 : k&0x00080000 ? 19 : k&0x00100000 ? 20 : k&0x00200000 ? 21: k&0x00400000 ? 22: k&0x00800000 ? 23: \
                 k&0x01000000 ? 24 : k&0x02000000 ? 25 : k&0x04000000 ? 26 : k&0x08000000 ? 27 : k&0x10000000 ? 28 : k&0x20000000 ? 29: k&0x40000000 ? 30: k&0x80000000 ? 31: 0xFF)
//  PORT C
#define DACSTBY     (1 << 0)
#define DACCLKA     (1 << 2)  // zpozdovaci linka z hradel
#define DACCLKB     (1 << 3)  // zpozdovaci linka z hradel
#define DACOFFS     6
//  PORT E
#define HEADDOFFS   0       // DDR data pro tiskovou hlavu, 3b + 1 rezerva
#define HEADSCK     (1 << 4)  // hodiny, prez zpozdovaci linku z hradel
#define HEADLAT     (1 << 5)  // ulozi data do bufferu, resetuje pocitadlo pulsu
#define HEADCHA     (1 << 6)  // prepne dekoder na dalsi puls, liche hlavy
#define HEADCHB     (1 << 7)  // prepne dekoder na dalsi puls, sude hlavy
#define HEADNCHG    (1 << 8)  // odpali vsechny trysky


volatile WORD strobe[8];
volatile WORD lut[2];

volatile WORD prnthd[4096];          // kapacita na 4 framy
volatile WORD dacwav[2048];          // signal pro vykonovy DAC (A i B kanal prokladane)
volatile WORD spistart[2];

inline void LED0(){GPIOA->BSRRH = 1 << 0;}
inline void LED1(){GPIOA->BSRRL = 1 << 0;}
inline void PHYRES0(){GPIOB->BSRRH = 1 << 10;}
inline void PHYRES1(){GPIOB->BSRRL = 1 << 10;}

void zelenina()
{
    volatile DWORD z;
    while(1)
    {
        z = 2000000;
        while(z --);
        LED1();
        z = 500000;
        while(z --);
        LED0();
    }
}

#include "wav.h"
#include "M-L_eth.h"

void SystemInit()
{
    volatile DWORD z = 100000;
    while(z --);
//       ____     ____
// X +--+ XO |   | /  |    ____     ____
//  ### |25M +---+PLLM+---+    |   | /  |
//   +--+____|   |____|   |VCO +-+-+PLLP+-+-sysclk
//                      +-+____| | |____| |
//                      |  ____  |  ____  |
//                      | | *  | | | /  | |
//                      +-+PLLN+-+-+PLLQ+-)-gpioclk
//                        |____|   |____| |  ____
//                                        | |/MCO|
//                                        +-+1PRE+---MCO1
//                                          |____|

//        25   /16  1,5625      300  /2     150  << sysclk
//                         *192      /6     50   << gpioclk
//                                            /3     50   << MCO1
    RCC->CR |= RCC_CR_HSEON;                // spustit XO
    while(!(RCC->CR & RCC_CR_HSERDY));      // pockat na stabilizaci HSE
    FLASH->ACR = 4 << dekkt(FLASH_ACR_LATENCY) | FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN; // FLASH delicka
    RCC->CFGR = 5 << dekkt(RCC_CFGR_MCO1PRE) | 3 << dekkt(RCC_CFGR_MCO1)   // delicky pro periferie a MCO (50 M)
              | 5 << dekkt(RCC_CFGR_PPRE1) | 4 << dekkt(RCC_CFGR_PPRE2);   // 37,5 a 75 M
    RCC->PLLCFGR = 0x20000000 | 6 << dekkt(RCC_PLLCFGR_PLLQ) | RCC_PLLCFGR_PLLSRC   //PLL
                 | 0 << dekkt(RCC_PLLCFGR_PLLP) | 192 << dekkt(RCC_PLLCFGR_PLLN) | 16 << dekkt(RCC_PLLCFGR_PLLM);
    RCC->CR |= RCC_CR_PLLON;                // spustit PLL
    while(!(RCC->CR & RCC_CR_PLLRDY));      // pockat nez se stabilizuje PLL
    RCC->CFGR |= 2 << dekkt(RCC_CFGR_SW);   // prepnout SYSCLK na PLL
    z = 100;
    while(z --);
    RCC->APB2ENR |= RCC_APB2ENR_TIM1EN | RCC_APB2ENR_TIM8EN | RCC_APB2ENR_SYSCFGEN;
	RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN | RCC_AHB1ENR_GPIODEN | RCC_AHB1ENR_GPIOEEN;
    z = 100;
    while(z --);
    GPIOA->AFR[0] = 0xB0000BB0;     // 1=REFCLK; 2=MDIO; 3=INT#(neni AF); 7=CRS; 8=MCO(selektor je 0)
    GPIOB->AFR[1] = 0x00BBB000;     // 11=txEN; 12=txD0; 13=txD1
    GPIOC->AFR[0] = 0x00BB00B0;     // 1=MDC; 4=rxD0; 5=rxD1
	GPIOA->MODER = 0xA8028029;
	GPIOB->MODER = 0x0A900280;
	GPIOC->MODER = 0x55555A59;
	GPIOE->MODER = 0x00015555;
	GPIOA->OSPEEDR = 0xFFFFFFFF;                //Nastaveni slew rate (max)
	GPIOB->OSPEEDR = 0xFFFFFFFF;
	GPIOC->OSPEEDR = 0xFFFFFFFF;
	GPIOD->OSPEEDR = 0xFFFFFFFF;
	GPIOE->OSPEEDR = 0xFFFFFFFF;
	PHYRES0();
    z = 1000;
    while(z --);
    RCC->AHB1RSTR = RCC_AHB1RSTR_ETHMACRST;
    SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL;             //RMII
	RCC->AHB1ENR |= RCC_AHB1ENR_ETHMACEN | RCC_AHB1ENR_ETHMACTXEN | RCC_AHB1ENR_ETHMACRXEN | RCC_AHB1ENR_ETHMACPTPEN
	             | RCC_AHB1ENR_CCMDATARAMEN | RCC_AHB1ENR_BKPSRAMEN | RCC_AHB1ENR_DMA2EN;
	RCC->AHB1RSTR = 0;
	PHYRES1();
    return;
}



int main(void)
{
    if(!ml_eth_init()) zelenina();
    WORD k;
    while(1)
    {
        while(rxdesc[rxindex][0] & DMA_RX_OWN);
        k = (rxdesc[rxindex][0] & DMA_RX_FL) >> dekkt(DMA_RX_FL) >> 1; // delka ve wordech
        switch(premrdat(rx[rxindex][6]))
        {
        case 0x0806:           // arp
            if(k >= 21
            && rx[rxindex][10] == premrdat(0x0001)
            && rx[rxindex][19] == ip_r >> 16
            && rx[rxindex][20] == (ip_r & 0xFFFF))
            {
                clientmach_r = rx[rxindex][11];
                clientmacl_r = rx[rxindex][12] << 16 | rx[rxindex][13];
                clientip_r =   rx[rxindex][14] << 16 | rx[rxindex][15];
                while(txdesc[0] & DMA_TX_OWN);
                k = 0;
                tx[k ++] = clientmach_r;    // target MAC
                tx[k ++] = clientmacl_r >> 16;
                tx[k ++] = clientmacl_r;
                tx[k ++] = mach_r;          // source MAC
                tx[k ++] = macl_r >> 16;
                tx[k ++] = macl_r;
                tx[k ++] = premrdat(0x0806);

                tx[k ++] = rx[rxindex][k];
                tx[k ++] = rx[rxindex][k];
                tx[k ++] = rx[rxindex][k];
                tx[k ++] = premrdat(2);
                tx[k ++] = mach_r;
                tx[k ++] = macl_r >> 16;
                tx[k ++] = macl_r;
                tx[k ++] = ip_r >> 16;
                tx[k ++] = ip_r;
                tx[k ++] = clientmach_r;
                tx[k ++] = clientmacl_r >> 16;
                tx[k ++] = clientmacl_r;
                tx[k ++] = clientip_r >> 16;
                tx[k ++] = clientip_r;
                txdesc[1] = k << 1;
                txdesc[0] |= DMA_TX_OWN;        // predat descriptor DMA controlleru
                ETH->DMATPDR = 0;               // zahajit prenos zapisem do registru
            }
            break;
        case 0x0800:            //UDP/IP
            if(k >= 1   ///////////////////// <- kontrolovat delku paketu
            && rx[rxindex][7] == premrdat(0x4500)
            &&(rx[rxindex][11] & premrdat(0x00FF)) == premrdat(0x0011)  // UDP
            && rx[rxindex][18] == premrdat(0x7563))                     // target
            {
                //////////////////////////////////////////////





                LED1();
            }
            break;
        }
        rxdesc[rxindex ++][0] = DMA_RX_OWN;                            // predat deskriptor
    }
}