#include <stm32h7xx.h>
#include <mymain.h>
#include <error.h>
#include <compiler_port.h>
#include <ethernet.h>
#include <net.h>
#include <net_mem.h>
#include <string.h>

//Transmit buffer
#pragma data_alignment = 4
#pragma location = STM32H7XX_ETH_RAM_SECTION
static uint8_t txBuffer[STM32H7XX_ETH_TX_BUFFER_COUNT][STM32H7XX_ETH_TX_BUFFER_SIZE];
//Receive buffer
#pragma data_alignment = 4
#pragma location = STM32H7XX_ETH_RAM_SECTION
static uint8_t rxBuffer[STM32H7XX_ETH_RX_BUFFER_COUNT][STM32H7XX_ETH_RX_BUFFER_SIZE];
//Transmit DMA descriptors
#pragma data_alignment = 4
#pragma location = STM32H7XX_ETH_RAM_SECTION
static Stm32h7xxTxDmaDesc txDmaDesc[STM32H7XX_ETH_TX_BUFFER_COUNT];
//Receive DMA descriptors
#pragma data_alignment = 4
#pragma location = STM32H7XX_ETH_RAM_SECTION
static Stm32h7xxRxDmaDesc rxDmaDesc[STM32H7XX_ETH_RX_BUFFER_COUNT];

//Текущий tx descriptor
static uint_t txIndex;
//Текущий rx descriptor
static uint_t rxIndex;

uint8_t buf[] = {0xCA, 0xAA};
NetBuffer buffer = {1,1, {buf, 2, 2}};


static void stm32h7xxEthInitGpio(void);
static void stm32h7xxEthInitDmaDesc(void);
static error_t stm32h7xxEthSendPacket(NetInterface *interface, NetBuffer *buffer, size_t offset);
static error_t stm32h7xxEthInit(NetInterface *interface);

void mymain(void) {
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOE_CLK_ENABLE();
  __HAL_RCC_GPIOG_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
   
  int a = buf[0] + buf[1] +  buffer.chunkCount;

   
  NetInterfaceInit(&_NetInterface); 
  MODIFY_REG(GPIOA->MODER, GPIO_MODER_MODE4_Msk, GPIO_MODER_MODE4_0);                          
  GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED4_0;        
  GPIOA->PUPDR |= GPIO_PUPDR_PUPD4_1;     
      
  stm32h7xxEthInit(&_NetInterface);
///  stm32h7xxEthEnableIrq(&_NetInterface);
  
  while (1) {
  // отправка пакета дангных
    stm32h7xxEthSendPacket(&_NetInterface, &buffer, 0);
    HAL_Delay(10);
    __NOP();
  }
}

/**
 * @brief STM32H7 Ethernet MAC initialization
 * @param[in] interface Underlying network interface
 * @return Error code
 **/
static error_t stm32h7xxEthInit(NetInterface *interface) {
   error_t error;
  //------------------------------------GPIO------------------------------------
  // Инициализация GPIO
  stm32h7xxEthInitGpio();
  
  //--------------------------------Тактирование--------------------------------  
  //Вкл тактирование MAC контроллера
  __HAL_RCC_ETH1MAC_CLK_ENABLE();
  __HAL_RCC_ETH1TX_CLK_ENABLE();
  __HAL_RCC_ETH1RX_CLK_ENABLE();
  
  //-----------------------------------RESET------------------------------------
  //Сброс MAC и DMA контроллеров
  RCC->AHB1RSTR |= RCC_AHB1RSTR_ETH1MACRST;
  RCC->AHB1RSTR &= ~(RCC_AHB1RSTR_ETH1MACRST);
  ETH->DMAMR |= ETH_DMAMR_SWR;
  
  //Ждем окончания сброса
  while(ETH->DMAMR & ETH_DMAMR_SWR) { }
  
  //-------------------------------------MAC------------------------------------
  //MAC (full duplex, 100mbps, Giant packet size limit control enable)
  //Преамбула 7 бит
  ETH->MACCR = ETH_MACCR_GPSLCE | ETH_MACCR_DM | ETH_MACCR_FES;
  ETH->MACCR &= ~(ETH_MACCR_PRELEN);
  
  //Установка максимального размера Ethernet пакета
  ETH->MACECR = STM32H7XX_ETH_RX_BUFFER_SIZE;
  
  //Фильтрация: принимать все входящие посылки
  ETH->MACPFR = ETH_MACPFR_PR;
  
  //отключить управление потоком
  ETH->MACTFCR = 0;
  ETH->MACRFCR = 0;
  
  //MAC прерывания отключены
  ETH->MACIER = 0;
  
  //PHY в MII режиме 
  ETH->MACHWF0R &= ~(ETH_MACHWF0R_ACTPHYSEL);
  
  //Установка MAC адреса устройства
  ETH->MACA0LR = 0x00AB | (0xCDEF << 16); // MAC 00-AB-CD-EF-07-43      //@todo исправить на то, что внизу потом
  ETH->MACA0HR = 0x0743;
  ///ETH->MACA0LR = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
  ///ETH->MACA0HR = interface->macAddr.w[2];
  
  //IPv4 компа
  ETH->MACARPAR = 0xC0A801E; // ip 192.168.1.30
  
  //Прервания по достижению half-value отключены 
  ETH->MMCTIMR = ETH_MMCTIMR_TXLPITRCIM | ETH_MMCTIMR_TXLPIUSCIM |
    ETH_MMCTIMR_TXGPKTIM | ETH_MMCTIMR_TXMCOLGPIM | ETH_MMCTIMR_TXSCOLGPIM;

  ETH->MMCRIMR = ETH_MMCRIMR_RXLPITRCIM | ETH_MMCRIMR_RXLPIUSCIM |
    ETH_MMCRIMR_RXUCGPIM | ETH_MMCRIMR_RXALGNERPIM | ETH_MMCRIMR_RXCRCERPIM;
   
  ///  //eth_HCLK(CSR clock)
  ///  ETH->MACMDIOAR = ETH_MACMDIOAR_CR_DIV124;
  
  // Установить приоритет прерываний(4 bits for pre-emption priority, no bits for subpriority)
  //NVIC_SetPriorityGrouping(STM32H7XX_ETH_IRQ_PRIORITY_GROUPING);

  //прерывание ethernet
  //NVIC_SetPriority(ETH_IRQn, NVIC_EncodePriority(STM32H7XX_ETH_IRQ_PRIORITY_GROUPING,
  //  STM32H7XX_ETH_IRQ_GROUP_PRIORITY, STM32H7XX_ETH_IRQ_SUB_PRIORITY));
  //------------------------------------DMA-------------------------------------
  //Настройка режима работы системной шины
  ETH->DMASBMR |= ETH_DMASBMR_AAL; 
  
  //Настройка дескрипторов DMA
  stm32h7xxEthInitDmaDesc();
  
  //Таблица дескрипторов непрерывная
  ETH->DMACCR = ETH_DMACCR_DSL_0BIT;
  
  //Настройка передачи данных
  ETH->DMACTCR = ETH_DMACTCR_TPBL_1PBL;
  
  //Настройка приема данных
  ETH->DMACRCR = ETH_DMACRCR_RPBL_1PBL;
  ETH->DMACRCR |= (STM32H7XX_ETH_RX_BUFFER_SIZE << 1) & ETH_DMACRCR_RBSZ;
  
  //Вкл прерывания на прием и передачу
  //ETH->DMACIER = ETH_DMACIER_NIE | ETH_DMACIER_RIE | ETH_DMACIER_TIE;
   
  // Настройка рабочего режима DMA
  ETH->DMAMR = ETH_DMAMR_INTM_0 | ETH_DMAMR_PR_1_1;
  //-------------------------------------MTL------------------------------------
  //Enable store and forward mode
  ETH->MTLTQOMR |= ETH_MTLTQOMR_TSF;
  ETH->MTLRQOMR |= ETH_MTLRQOMR_RSF;
  //---------------------------------ENABLE ETH---------------------------------
  //enable the MAC receiver only after the DMA is active (ñì. RM0433 ñò.2879)
  //Разрешить прием и передачу по DMA
  ETH->DMACTCR |= ETH_DMACTCR_ST;
  ETH->DMACRCR |= ETH_DMACRCR_SR;
  // Разрешение приема и пердачи MAC
  ETH->MACCR |= ETH_MACCR_TE | ETH_MACCR_RE; 
  //возврат
  return NO_ERROR; 
}

/** @brief Таблица дескрипторов  DMA **/
static void stm32h7xxEthInitDmaDesc(void) {
  // (DMA TX desc list) 
  for(int i = 0; i < STM32H7XX_ETH_TX_BUFFER_COUNT; i++) {
    //The descriptor is initially owned by the application
    txDmaDesc[i].tdes0 = 0;
    txDmaDesc[i].tdes1 = 0;
    txDmaDesc[i].tdes2 = 0;
    txDmaDesc[i].tdes3 = 0;
  }

  //Initialize TX descriptor index
  txIndex = 0;

  //(RX DMA desc list)
  for(int i = 0; i < STM32H7XX_ETH_RX_BUFFER_COUNT; i++)
  {
    //The descriptor is initially owned by the DMA
    rxDmaDesc[i].rdes0 = (uint32_t) rxBuffer[i];
    rxDmaDesc[i].rdes1 = 0;
    rxDmaDesc[i].rdes2 = 0;
    rxDmaDesc[i].rdes3 = ETH_RDES3_OWN | ETH_RDES3_IOC | ETH_RDES3_BUF1V;
  }

  //Initialize RX descriptor index
  rxIndex = 0;

  //Начало листа дескрипторов передачи (TX desc list)
  ETH->DMACTDLAR = (uint32_t) &txDmaDesc[0];
  //Количество дескрипторов
  ETH->DMACTDRLR = STM32H7XX_ETH_TX_BUFFER_COUNT - 1;

  //Начало листа дескрипторов приема (RX desc list)
  ETH->DMACRDLAR = (uint32_t) &rxDmaDesc[0];
  //Кол-во
  ETH->DMACRDRLR = STM32H7XX_ETH_RX_BUFFER_COUNT - 1;
}

/**
 * @brief Send a packet
 * @param[in] interface Underlying network interface
 * @param[in] buffer Multi-part buffer containing the data to send
 * @param[in] offset Offset to the first data byte
 * @param[in] ancillary Additional options passed to the stack along with
 *   the packet
 * @return Error code
 **/

static error_t stm32h7xxEthSendPacket(NetInterface *interface, NetBuffer *bufPtr, uint32_t offset) {
  static uint8_t temp[STM32H7XX_ETH_TX_BUFFER_SIZE];
  uint32_t length;

  //Суммарная длина пакета
  length = netBufferGetLength(bufPtr) - offset;

  //если длина больше макс, то возврат с ошибкой
  if(length > STM32H7XX_ETH_TX_BUFFER_SIZE) {
     //ошибка длины
     return ERROR_INVALID_LENGTH;
  }

  //Копируем пользовательские данные в буфер
  netBufferRead(temp, bufPtr, offset, length);
  memcpy(txBuffer[txIndex], temp, (length + 3) & ~3UL);
  ///osMemcpy(txBuffer[txIndex], temp, (length + 3) & ~3UL);

  //Set the start address of the buffer
  txDmaDesc[txIndex].tdes0 = (uint32_t) txBuffer[txIndex];
  //Write the number of bytes to send
  txDmaDesc[txIndex].tdes2 = ETH_TDES2_IOC | (length & ETH_TDES2_B1L);
  //Give the ownership of the descriptor to the DMA
  txDmaDesc[txIndex].tdes3 = ETH_TDES3_OWN | ETH_TDES3_FD | ETH_TDES3_LD;

  //Data synchronization barrier
  __DSB();

  //Clear TBU flag to resume processing
  ETH->DMACSR = ETH_DMACSR_TBU;
  //Instruct the DMA to poll the transmit descriptor list
  ETH->DMACTDTPR = 0;
  //Increment index and wrap around if necessary
  if(++txIndex >= STM32H7XX_ETH_TX_BUFFER_COUNT)
  {
     txIndex = 0;
  }

  //Check whether the next buffer is available for writing
  if((txDmaDesc[txIndex].tdes3 & ETH_TDES3_OWN) == 0)
  {
     //The transmitter can accept another packet
     ///osSetEvent(&interface->nicTxEvent);
  }

  //Data successfully written
  return NO_ERROR;
}


/**@brief ethernet GPIO */
static void stm32h7xxEthInitGpio(void) {
   GPIO_InitTypeDef GPIO_InitStructure;

   //Enable SYSCFG clock
   __HAL_RCC_SYSCFG_CLK_ENABLE();

   //Enable GPIO clocks
   __HAL_RCC_GPIOA_CLK_ENABLE();
   __HAL_RCC_GPIOB_CLK_ENABLE();
   __HAL_RCC_GPIOC_CLK_ENABLE();
   __HAL_RCC_GPIOE_CLK_ENABLE();
   __HAL_RCC_GPIOG_CLK_ENABLE();
   __HAL_RCC_GPIOH_CLK_ENABLE();
   __HAL_RCC_GPIOI_CLK_ENABLE();

   //Select MII interface mode
   HAL_SYSCFG_ETHInterfaceSelect(SYSCFG_ETH_MII);

   //Configure MII pins
   GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
   GPIO_InitStructure.Pull = GPIO_NOPULL;
   GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
   GPIO_InitStructure.Alternate = GPIO_AF11_ETH;

   
   // ETH_MII_CRS(PA0) ETH_MII_RX_CLK(PA1) ETH_MDIO(PA2) ETH_MII_COL(PA3)
   // ETH_MII_RX_DV(PA7)
   GPIO_InitStructure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | 
                            GPIO_PIN_3 | GPIO_PIN_7;
   HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
   
   //ETH_MII_RXD2(PB0), ETH_MII_RXD3(PB1), ETH_MII_TXD3(PB8), ETH_MII_RX_ER(PB10)
   // ETH_MII_TX_EN(PB11), ETH_MII_TXD0(PB12), ETH_MII_TXD0(PB13)
   GPIO_InitStructure.Pin = GPIO_PIN_0  | GPIO_PIN_1  | GPIO_PIN_8 | GPIO_PIN_10 |
                            GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13;
   HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
   
   
   // ETH_MDC (PC1), ETH_MII_TXD2(PC2), ETH_MII_TX_CLK(PC3),
   // ETH_MII_RXD0(PC4), ETH_MII_RXD1(PC5)
   GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 |
     GPIO_PIN_5;
   HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
}


