/**
  ******************************************************************************
  * @file    openbl_core.c
  * @author  MCD Application Team
  * @brief   Open Bootloader core file
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2023 Puya Semiconductor Co.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by Puya under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

#include "openbl_core.h"

static uint32_t NumberOfInterfaces = 0U;
static OPENBL_HandleTypeDef a_InterfacesTable[INTERFACES_SUPPORTED];
static OPENBL_HandleTypeDef *p_Interface;
 

/**
  * @brief  This function is used to initialize the registered interfaces in the Open Bootloader MW.
  * @retval None.
  */
void OPENBL_Init(void)
{
  uint32_t counter;

  for (counter = 0U; counter < NumberOfInterfaces; counter++)
  {
    if (a_InterfacesTable[counter].p_Ops->Init != NULL)
    {
      a_InterfacesTable[counter].p_Ops->Init();
    }
  }
}

/**
  * @brief  This function is used to de-initialize the registered interfaces in the Open Bootloader MW.
  * @retval None.
  */
void OPENBL_DeInit(void)
{
  uint32_t counter;

  for (counter = 0U; counter < NumberOfInterfaces; counter++)
  {
    if (a_InterfacesTable[counter].p_Ops->DeInit != NULL)
    {
      a_InterfacesTable[counter].p_Ops->DeInit();
    }
  }
}

void OPENBL_DeInit_Actice(void)
{
  if (p_Interface == NULL)
    return;

  if (p_Interface->p_Ops->DeInit != NULL)
  {
    p_Interface->p_Ops->DeInit();
  }

  p_Interface = NULL;
}

/**
  * @brief  This function is used to register a given interface in the Open Bootloader MW.
  * @retval None.
  */
int OPENBL_RegisterInterface(OPENBL_HandleTypeDef *Interface)
{
  if (NumberOfInterfaces < INTERFACES_SUPPORTED)
  {
    a_InterfacesTable[NumberOfInterfaces].p_Ops = Interface->p_Ops;
    a_InterfacesTable[NumberOfInterfaces].p_IO = Interface->p_IO;

    NumberOfInterfaces++;
    return 0;
  }
  else
  {
    return -1;
  }
}

/**
  * @brief  This function is used to detect if there is any activity on a given interface.
  * @retval None.
  */
int OPENBL_InterfaceDetection(void)
{
  uint32_t counter;
  uint8_t detected = 0U;

  for (counter = 0U; counter < NumberOfInterfaces; counter++)
  {
    if (a_InterfacesTable[counter].p_Ops->Detection != NULL)
    {
      detected = a_InterfacesTable[counter].p_Ops->Detection();

      if (detected == 1U)
      {
        p_Interface = &(a_InterfacesTable[counter]);

        //DeInit other interface
        for (uint32_t i = 0U; i < NumberOfInterfaces; i++)
        {
          if (counter == i)
          {
            continue;
          }

          if (a_InterfacesTable[i].p_Ops->DeInit != NULL)
          {
            a_InterfacesTable[i].p_Ops->DeInit();
          }
        }

        break;
      }
    }
  }

  return detected;
}

/**
  * @brief  This function is used to execute the right command.
  * @retval None.
  */
void OPENBL_ProtocolProcess(void)
{
  if (p_Interface->p_Ops->CommandProcess != NULL)
  {
    p_Interface->p_Ops->CommandProcess();
  }
}

/**
  * @brief  This function is used to read data from interface.
  * @retval None.
  */
void OPENBL_Read(uint8_t *buf, uint16_t size)
{
  if (p_Interface->p_IO->Read != NULL)
  {
    p_Interface->p_IO->Read(buf, size);
  }
}

/**
  * @brief  This function is used to write data from interface.
  * @retval None.
  */
void OPENBL_Write(uint8_t *buf, uint16_t size)
{
  if (p_Interface->p_IO->Write != NULL)
  {
    p_Interface->p_IO->Write(buf, size);
  }
}

uint8_t OPENBL_ReadByte(void)
{
  uint8_t byte;
  OPENBL_Read(&byte, 1);
  return byte;
}

void OPENBL_WriteByte(uint8_t byte)
{
  OPENBL_Write(&byte, 1);
}
/************************ (C) COPYRIGHT Puya *****END OF FILE******************/
