/* ###################################################################
**     This component module is generated by Processor Expert. Do not modify it.
**     Filename    : McuGenericSWI2C.h
**     Project     : FRDM-K64F_Generator
**     Processor   : MK64FN1M0VLL12
**     Component   : GenericSWI2C
**     Version     : Component 01.028, Driver 01.00, CPU db: 3.00.000
**     Compiler    : GNU C Compiler
**     Date/Time   : 2024-07-09, 10:10, # CodeGen: 829
**     Abstract    :
**
**     Settings    :
**          Component name                                 : McuGenericSWI2C
**          Delay (ns)                                     : 1250
**          Trials                                         : 256
**          SDA                                            : SDK_BitIO
**          SCL                                            : SDK_BitIO
**          Wait                                           : McuWait
**          Yield                                          : no
**     Contents    :
**         ResetBus          - bool McuGenericSWI2C_ResetBus(void);
**         SendChar          - uint8_t McuGenericSWI2C_SendChar(uint8_t Chr);
**         RecvChar          - uint8_t McuGenericSWI2C_RecvChar(uint8_t *Chr);
**         SendBlock         - uint8_t McuGenericSWI2C_SendBlock(void *Ptr, uint16_t Siz, uint16_t *Snt);
**         SendBlockContinue - uint8_t McuGenericSWI2C_SendBlockContinue(void *Ptr, uint16_t Siz, uint16_t...
**         RecvBlock         - uint8_t McuGenericSWI2C_RecvBlock(void *Ptr, uint16_t Siz, uint16_t *Rcv);
**         RecvBlockCustom   - uint8_t McuGenericSWI2C_RecvBlockCustom(void *Ptr, uint16_t Siz, uint16_t...
**         SendAck           - void McuGenericSWI2C_SendAck(bool Ack);
**         SendStop          - uint8_t McuGenericSWI2C_SendStop(void);
**         SelectSlave       - uint8_t McuGenericSWI2C_SelectSlave(uint8_t Slv);
**         GetSelected       - uint8_t McuGenericSWI2C_GetSelected(uint8_t *Slv);
**         Deinit            - void McuGenericSWI2C_Deinit(void);
**         Init              - void McuGenericSWI2C_Init(void);
**
** * Copyright (c) 2014-2024, Erich Styger
**  * Web:         https://mcuoneclipse.com
**  * SourceForge: https://sourceforge.net/projects/mcuoneclipse
**  * Git:         https://github.com/ErichStyger/McuOnEclipse_PEx
**  * All rights reserved.
**  *
**  * Redistribution and use in source and binary forms, with or without modification,
**  * are permitted provided that the following conditions are met:
**  *
**  * - Redistributions of source code must retain the above copyright notice, this list
**  *   of conditions and the following disclaimer.
**  *
**  * - Redistributions in binary form must reproduce the above copyright notice, this
**  *   list of conditions and the following disclaimer in the documentation and/or
**  *   other materials provided with the distribution.
**  *
**  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
**  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
**  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
**  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
**  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
**  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
**  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
**  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
**  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
**  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
** ###################################################################*/
/*!
** @file McuGenericSWI2C.h
** @version 01.00
** @brief
**
*/         
/*!
**  @addtogroup McuGenericSWI2C_module McuGenericSWI2C module documentation
**  @{
*/         

/* MODULE McuGenericSWI2C. */

#include "McuGenericSWI2C.h"
#include "McuWait.h" /* waiting routines */
#include "McuLib.h" /* SDK defines */
#include "SDA1.h" /* SDA pin */
#include "SCL1.h" /* SCL pin */

/* Internal method prototypes */
static void Delay(void);
static uint8_t Read(void);
static bool GetAck(void);
static void Write(uint8_t Data);
static void InternalStop(void);


#if McuLib_CONFIG_SDK_USE_FREERTOS
  /* include RTOS header files */
  #include "FreeRTOS.h" /* for yielding */
  #include "task.h"
#endif

#if McuLib_CONFIG_SDK_USE_FREERTOS && McuGenericSWI2C_CONFIG_DO_YIELD
  #define McuGenericSWI2C_OSYIELD() taskYIELD()
#else
  #define McuGenericSWI2C_OSYIELD() /* do nothing */
#endif

#define OUTPUT      1U
#define INPUT       0U
#define WRITE       0U
#define READ        1U

static uint8_t SlaveAddr;             /* destination slave address      */

#define SCL_SetDir(dir) SCL1_SetDir(dir)
#define SCL_ClrVal()    SCL1_ClrVal()
#define SCL_GetVal()    SCL1_GetVal()

#define SDA_SetDir(dir) SDA1_SetDir(dir)
#define SDA_ClrVal()    SDA1_ClrVal()
#define SDA_GetVal()    SDA1_GetVal()

#if McuLib_CONFIG_SDK_VERSION_USED == McuLib_CONFIG_SDK_PROCESSOR_EXPERT
  #define SCL_Init()      /* Init does not exist with Processor Expert API */
  #define SCL_Deinit()    /* Deinit does not exist with Processor Expert API */
  #define SDA_Init()      /* Init does not exist with Processor Expert API */
  #define SDA_Deinit()    /* Deinit does not exist with Processor Expert API */
#else
  #define SCL_Init()      SCL1_Init()
  #define SCL_Deinit()    SCL1_Deinit()
  #define SDA_Init()      SDA1_Init()
  #define SDA_Deinit()    SDA1_Deinit()
#endif

static uint8_t SendStart(void) {
  uint16_t timeout;

  SDA_SetDir((bool)INPUT);     /* SDA HIGH - START SETUP*/
  SCL_SetDir((bool)INPUT);     /* CLOCK HIGH PULSE */
  Delay();                     /* CLOCK HIGH PULSE & BUS FREE TIME */
  /* check that we have a valid start condition: SDA needs to be high */
  timeout = McuGenericSWI2C_CONFIG_TIMEOUT_COUNTER_VALUE;
  while((SDA_GetVal()==0U)&&(timeout!=0U)) { /* WAIT FOR CLOCK HIGH PULSE */
    timeout--;
    McuGenericSWI2C_OSYIELD();
  }
  Delay();
  if (timeout==0) {
    InternalStop();
    return ERR_BUSY;
  }
  SDA_SetDir((bool)OUTPUT);
  SDA_ClrVal();                /* START CONDITION */
  Delay();                     /* START HOLD TIME */
  SCL_SetDir((bool)OUTPUT);
  SCL_ClrVal();                /* CLOCK LOW PULSE */
  Delay();
  return ERR_OK;
}

uint8_t McuGenericSWI2C_GetDeviceID(uint8_t deviceAddr, uint32_t *pId)
{
  uint16_t Trial;
  bool Acknowledge;
  uint8_t id[3];
  const uint8_t reserved = 0b11111000;

  Trial = McuGenericSWI2C_CONFIG_NOF_TRIALS;
  do {
    if (SendStart()!=ERR_OK) {
      return ERR_BUSY;
    }
    Write((uint8_t)(reserved + WRITE));
    Acknowledge = GetAck();
    Acknowledge = FALSE;
    --Trial;
  } while ((Trial != 0U) && Acknowledge);
  if (Acknowledge) {             /* WRONG ACKNOWLEDGE */
    SCL_SetDir((bool)OUTPUT);
    SCL_ClrVal();                /* CLOCK LOW PULSE */
    InternalStop();
    return ERR_BUSY;
  } else {
   /* restart here: send a start */
    if (SendStart()!=ERR_OK) {
      return ERR_BUSY;
    }
    SCL_SetDir((bool)OUTPUT);
    SCL_ClrVal();                /* CLOCK LOW PULSE */
    Delay();
  }
  Write((uint8_t)(reserved + READ));
  Delay();
  id[0] = Read();
  id[1] = Read();
  id[2] = Read();
  McuGenericSWI2C_SendAck((bool)McuGenericSWI2C_NOACK);
  pId[0] = id[0];
  pId[1] = id[1];
  pId[2] = id[2];
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  Delay (component GenericSWI2C)
**
**     Description :
**         This method is internal. It is used by Processor Expert only.
** ===================================================================
*/
static void Delay(void)
{
  McuGenericSWI2C_OSYIELD();
  McuWait_Waitns(McuGenericSWI2C_CONFIG_DELAY_NS);
}

/*
** ===================================================================
**     Method      :  Write (component GenericSWI2C)
**
**     Description :
**         This method is internal. It is used by Processor Expert only.
** ===================================================================
*/
static void Write(uint8_t Data)
{
  uint8_t Shift;
  uint8_t I;
  uint16_t timeout;

  Shift = 0x80U;
  for (I = 0x08U; I != 0U; I--) {
    if (Data & Shift) {
      SDA_SetDir((bool)INPUT);   /* SDA HIGH */
    } else {
      SDA_SetDir((bool)OUTPUT);
      SDA_ClrVal();              /* SDA LOW */
    }
    Delay();
    Shift = (uint8_t)(Shift >> 1);
    SCL_SetDir((bool)INPUT);     /* CLOCK HIGH PULSE */
    Delay();
    timeout = McuGenericSWI2C_CONFIG_TIMEOUT_COUNTER_VALUE;
    while((SCL_GetVal()==0U)&&(timeout!=0U)) { /* WAIT FOR CLOCK HIGH PULSE */
      timeout--;
      McuGenericSWI2C_OSYIELD();
    }
    Delay();
    SCL_SetDir((bool)OUTPUT);
    SCL_ClrVal();                /* CLOCK LOW PULSE */
    Delay();
  }
}

/*
** ===================================================================
**     Method      :  Read (component GenericSWI2C)
**
**     Description :
**         This method is internal. It is used by Processor Expert only.
** ===================================================================
*/
static uint8_t Read(void)
{
  uint8_t Shift;
  uint8_t I;
  uint16_t timeout;

  Shift = 0U;
  SDA_SetDir((bool)INPUT);       /* SDA INPUT MODE */
  Delay(); /* give SDA setup time */
  for (I = 0x08U; I != 0U; I--) {
    SCL_SetDir((bool)INPUT);     /* CLOCK HIGH PULSE */
    Delay();
    timeout = McuGenericSWI2C_CONFIG_TIMEOUT_COUNTER_VALUE;
    while((SCL_GetVal()==0U)&&(timeout!=0U)) { /* WAIT FOR CLOCK HIGH PULSE */
      timeout--;
      McuGenericSWI2C_OSYIELD();
    }
    Delay();
    Shift = (uint8_t)(Shift << 1);
    if (SDA_GetVal()) {
      Shift++;
    }
    SCL_SetDir((bool)OUTPUT);
    SCL_ClrVal();                /* CLOCK LOW PULSE */
    Delay();
  }
  return Shift;
}

/*
** ===================================================================
**     Method      :  GetAck (component GenericSWI2C)
**
**     Description :
**         This method is internal. It is used by Processor Expert only.
** ===================================================================
*/
static bool GetAck(void)
{
  uint16_t timeout;

  SDA_SetDir((bool)INPUT);       /* SDA HIGH */
  Delay();
  SCL_SetDir((bool)INPUT);       /* CLOCK HIGH PULSE */
  Delay();
  timeout = McuGenericSWI2C_CONFIG_TIMEOUT_COUNTER_VALUE;
  while((SCL_GetVal()==0U)&&(timeout!=0U)) { /* WAIT FOR CLOCK HIGH PULSE */
    timeout--;
    McuGenericSWI2C_OSYIELD();
  }
  return((bool)SDA_GetVal());    /* ACKNOWLEDGE VALUE */
}

/*
** ===================================================================
**     Method      :  SendAck (component GenericSWI2C)
**
**     Description :
**         The method sends ACK to the bus.
**     Parameters  :
**         NAME            - DESCRIPTION
**         Ack             - If acknowledge is high or low
**     Returns     : Nothing
** ===================================================================
*/
void McuGenericSWI2C_SendAck(bool Ack)
{
  uint16_t timeout;

  Delay();
  if (Ack) {
    SDA_SetDir((bool)INPUT);     /* MASTER NOACKNOWLEDGE - SDA HIGH */
  } else {
    SDA_SetDir((bool)OUTPUT);
    SDA_ClrVal();                /* MASTER ACKNOWLEDGE - SDA LOW */
  }
  Delay();
  SCL_SetDir((bool)INPUT);       /* HIGH CLOCK PULSE */
  Delay();
  timeout = McuGenericSWI2C_CONFIG_TIMEOUT_COUNTER_VALUE;
  while((SCL_GetVal()==0U)&&(timeout!=0U)) { /* WAIT FOR CLOCK HIGH PULSE */
    timeout--;
    McuGenericSWI2C_OSYIELD();
  }
  Delay();
  SCL_SetDir((bool)OUTPUT);
  SCL_ClrVal();                  /* LOW CLOCK PULSE */
  Delay();
  SDA_SetDir((bool)INPUT);       /* ACKNOWLEDGE END - SDA HIGH  */
  Delay();
}

/*
** ===================================================================
**     Method      :  InternalStop (component GenericSWI2C)
**
**     Description :
**         This method is internal. It is used by Processor Expert only.
** ===================================================================
*/
static void InternalStop(void)
{
  Delay();
  SDA_SetDir((bool)OUTPUT);
  SDA_ClrVal();                  /* STOP SETUP */
  SCL_SetDir((bool)INPUT);       /* CLOCK HIGH PULSE + STOP SETUP TIME */
  Delay();
  SDA_SetDir((bool)INPUT);       /* STOP CONDITION */
  Delay();                       /* stop setup time to SCL low (which might follow) */
}

/*
** ===================================================================
**     Method      :  ResetBus (component GenericSWI2C)
**
**     Description :
**         Reset bus if needed.
**     Parameters  : None
**     Returns     :
**         ---             - TRUE if bus is idle, FALSE if bus is
**                           busy/hung
** ===================================================================
*/
bool McuGenericSWI2C_ResetBus(void)
{
  char i;

  if(SDA_GetVal() && SCL_GetVal()) {
    return TRUE;
  }
  SCL_SetDir((bool)INPUT);
  SDA_SetDir((bool)INPUT);
  Delay();
  if(!SCL_GetVal()) {
    return FALSE; /* SCL held low externally, nothing we can do */
  }
  for(i = 0; i<9; i++) { /* up to 9 clocks until SDA goes high */
    SCL_SetDir((bool)OUTPUT);
    SCL_ClrVal();
    Delay();
    SCL_SetDir((bool)INPUT);
    Delay();
    if( SDA_GetVal()) {
      break; /* finally SDA high so we can generate a STOP */
    }
  } /* for */
  if(!SDA_GetVal()) {
    return FALSE; /* after 9 clocks still nothing */
  }
  InternalStop();
  return(SDA_GetVal() && SCL_GetVal()); /* both high then we succeeded */
}

/*
** ===================================================================
**     Method      :  SendChar (component GenericSWI2C)
**
**     Description :
**         When working as a MASTER, this method writes 7 bits of slave
**         address plus R/W bit = 0 to the I2C bus and then writes one
**         character (byte) to the bus. The slave address must be
**         specified before by the "SelectSlave" method or in the
**         component initialization section of 'Slave address init'
**         property. When working as the SLAVE, this method writes one
**         character (byte) to the bus. If the ERR_NOTAVAIL error code
**         returned, the char is successfully sent to master but the
**         master device responds by an acknowledgment instead of no
**         acknowledgment at the end of transfer. 'OnError' event is
**         called in this case.
**     Parameters  :
**         NAME            - DESCRIPTION
**         Chr             - Character to send
**     Returns     :
**         ---             - Error code, possible codes:
**                           ERR_OK - OK
**                           ERR_SPEED - This device does not work in
**                           the active speed mode
**                           ERR_BUSY - The slave device is busy, it
**                           does not respond by the acknowledgment
**                           (MASTER mode only)
**                           ERR_NOTAVAIL - The master device sends
**                           acknowledgment instead of no acknowledgment
**                           after the last byte transfer (SLAVE mode
**                           only)
**                           ERR_DISABLED - Device is disabled
**                           ERR_BUSOFF - Clock timeout elapsed (SLAVE
**                           mode only)
** ===================================================================
*/
uint8_t McuGenericSWI2C_SendChar(uint8_t Chr)
{
  uint16_t Trial;
  bool Acknowledge;
  uint16_t timeout;

  Trial = McuGenericSWI2C_CONFIG_NOF_TRIALS;
  do {
    SDA_SetDir((bool)INPUT);     /* SDA HIGH - START SETUP*/
    SCL_SetDir((bool)INPUT);     /* CLOCK HIGH PULSE */
    Delay();                       /* CLOCK HIGH PULSE & BUS FREE TIME */
    /* check that we have a valid start condition: SDA needs to be high */
    timeout = McuGenericSWI2C_CONFIG_TIMEOUT_COUNTER_VALUE;
    while((SDA_GetVal()==0U)&&(timeout!=0U)) { /* WAIT FOR CLOCK HIGH PULSE */
      timeout--;
      McuGenericSWI2C_OSYIELD();
    }
    Delay();
    if (timeout==0) {
      InternalStop();
      return ERR_BUSY;
    }
    SDA_SetDir((bool)OUTPUT);
    SDA_ClrVal();                /* START CONDITION */
    Delay();                       /* START HOLD TIME */
    SCL_SetDir((bool)OUTPUT);
    SCL_ClrVal();                /* CLOCK LOW PULSE */
    Delay();
    Write((uint8_t)(SlaveAddr + WRITE));
    Acknowledge = GetAck();
    --Trial;
  } while ((Trial != 0U) && Acknowledge);
  if (Acknowledge) {               /* WRONG ACKNOWLEDGE */
    SCL_SetDir((bool)OUTPUT);
    SCL_ClrVal();                /* CLOCK LOW PULSE */
    InternalStop();
    return ERR_BUSY;
  } else {
    SCL_SetDir((bool)OUTPUT);
    SCL_ClrVal();                /* CLOCK LOW PULSE */
    Delay();
  }
  Write(Chr);
  if (GetAck()) {                  /* WRONG ACKNOWLEDGE */
    SCL_SetDir((bool)OUTPUT);
    SCL_ClrVal();                /* CLOCK LOW PULSE */
    InternalStop();
    return ERR_BUSY;
  } else {
    SCL_SetDir((bool)OUTPUT);
    SCL_ClrVal();                /* CLOCK LOW PULSE */
    Delay();
  }
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  RecvChar (component GenericSWI2C)
**
**     Description :
**         When working as a MASTER, this method writes 7 bits of slave
**         address plus R/W bit = 1 to the I2C bus and then reads one
**         character (byte) from the bus. The slave address must be
**         specified before by the "SelectSlave" method or in the
**         component initialization section of 'Slave address init'
**         property. When working as a SLAVE, this method reads one
**         character (byte) from the bus.
**     Parameters  :
**         NAME            - DESCRIPTION
**       * Chr             - Pointer to received character
**     Returns     :
**         ---             - Error code, possible codes:
**                           ERR_OK - OK
**                           ERR_SPEED - This device does not work in
**                           the active speed mode
**                           ERR_BUSY - The slave device is busy, it
**                           does not respond by the acknowledgment
**                           (MASTER mode only)
**                           ERR_DISABLED - Device is disabled
**                           ERR_BUSOFF - Clock timeout elapsed (SLAVE
**                           mode only)
** ===================================================================
*/
uint8_t McuGenericSWI2C_RecvChar(uint8_t *Chr)
{
  uint16_t Trial;
  bool Acknowledge;
  uint16_t timeout;

  Trial = McuGenericSWI2C_CONFIG_NOF_TRIALS;
  do {
    SDA_SetDir((bool)INPUT);     /* SDA HIGH - START SETUP */
    SCL_SetDir((bool)INPUT);     /* CLOCK HIGH PULSE */
    Delay();                     /* CLOCK HIGH PULSE & BUS FREE TIME */
    /* check that we have a valid start condition: SDA needs to be high */
    timeout = McuGenericSWI2C_CONFIG_TIMEOUT_COUNTER_VALUE;
    while((SDA_GetVal()==0U)&&(timeout!=0U)) { /* WAIT FOR CLOCK HIGH PULSE */
      timeout--;
      McuGenericSWI2C_OSYIELD();
    }
    Delay();
    if (timeout==0) {
      InternalStop();
      return ERR_BUSY;
    }
    SDA_SetDir((bool)OUTPUT);
    SDA_ClrVal();                /* START CONDITION */
    Delay();                       /* START HOLD TIME */
    SCL_SetDir((bool)OUTPUT);
    SCL_ClrVal();                /* CLOCK LOW PULSE */
    Delay();
    Write((uint8_t)(SlaveAddr + READ));
    Acknowledge = GetAck();
    --Trial;
  } while ((Trial != 0U) && Acknowledge);
  if (Acknowledge) {
    SCL_SetDir((bool)OUTPUT);
    SCL_ClrVal();                /* CLOCK LOW PULSE */
    InternalStop();
    return ERR_BUSY;
  } else {
    SCL_SetDir((bool)OUTPUT);
    SCL_ClrVal();                /* CLOCK LOW PULSE */
    Delay();
  }
  *Chr = Read();
  McuGenericSWI2C_SendAck((bool)McuGenericSWI2C_NOACK);
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  SendBlock (component GenericSWI2C)
**
**     Description :
**         When working as a MASTER, this method writes 7 bits of slave
**         address plus R/W bit = 0 to the I2C bus and then writes the
**         block of characters to the bus. If the component is disabled
**         (by the "Disable" method or initialization), the block is
**         moved to the output buffer if the 'Output buffer size'
**         property is different from zero. The content of the output
**         buffer is sent immediately with the stop condition at the
**         end when the component is enabled by the "Enable" method.
**         After the output buffer transmission, the whole output
**         buffer is cleared. The slave address must be specified
**         before by the "SelectSlave" method or in component
**         initialization section of 'Slave address init' property.
**         When working as a SLAVE, this method writes block of
**         characters to the bus. If the ERR_NOTAVAIL error code is
**         returned, the whole block is successfully sent to a master
**         but the master device responds by an acknowledgment instead
**         of no acknowledgment sent at the end of the last block byte
**         transfer. 'OnError' event is called in this case.
**     Parameters  :
**         NAME            - DESCRIPTION
**       * Ptr             - A pointer to the block of data to send
**         Siz             - The size of the block
**       * Snt             - A pointer to the number of data that are
**                           sent (copied to buffer)
**     Returns     :
**         ---             - Error code, possible codes:
**                           ERR_OK - OK
**                           ERR_SPEED - This device does not work in
**                           the active speed mode
**                           ERR_BUSY - The slave device is busy, it
**                           does not respond by the acknowledgment
**                           (MASTER mode only)
**                           ERR_TXFULL - Output buffer is full (MASTER
**                           mode only)
**                           ERR_NOTAVAIL - The master device sends
**                           acknowledgment instead of no acknowledgment
**                           after the last byte transfer (SLAVE mode
**                           only)
**                           ERR_DISABLED - Device is disabled
**                           ERR_BUSOFF - Clock timeout elapsed (SLAVE
**                           mode only)
** ===================================================================
*/
uint8_t McuGenericSWI2C_SendBlock(void *Ptr, uint16_t Siz, uint16_t *Snt)
{
  register uint16_t I;
  bool Acknowledge;
  uint16_t Trial;
  uint16_t timeout;

  *Snt = 0U;
  Trial = McuGenericSWI2C_CONFIG_NOF_TRIALS;
  do {
    SDA_SetDir((bool)INPUT);     /* SDA HIGH  - START SETUP */
    SCL_SetDir((bool)INPUT);     /* CLOCK HIGH PULSE */
    Delay();                     /* CLOCK HIGH PULSE + BUS FREE TIME */
    /* check that we have a valid start condition: SDA needs to be high */
    timeout = McuGenericSWI2C_CONFIG_TIMEOUT_COUNTER_VALUE;
    while((SDA_GetVal()==0U)&&(timeout!=0U)) { /* WAIT FOR CLOCK HIGH PULSE */
      timeout--;
      McuGenericSWI2C_OSYIELD();
    }
    Delay();
    if (timeout==0) {
      return ERR_BUSY;
    }
    SDA_SetDir((bool)OUTPUT);
    SDA_ClrVal();                /* START CONDITION */
    Delay();                     /* START HOLD TIME */
    SCL_SetDir((bool)OUTPUT);
    SCL_ClrVal();                /* CLOCK LOW PULSE */
    Delay();
    Write((uint8_t)(SlaveAddr + WRITE));
    Acknowledge = GetAck();
    --Trial;
  } while ((Trial != 0U) && Acknowledge);
  if (Acknowledge) {
    return ERR_BUSY;
  } else {
    SCL_SetDir((bool)OUTPUT);
    SCL_ClrVal();                /* CLOCK LOW PULSE */
    Delay();
  }
  for (I = 0U; I < Siz; I++) {
    Write (*((const uint8_t*)Ptr + I) );
    if (GetAck()) {
      SCL_SetDir((bool)OUTPUT);
      SCL_ClrVal();              /* CLOCK LOW PULSE */
      InternalStop();
      return ERR_BUSY;
    } else {
      SCL_SetDir((bool)OUTPUT);
      SCL_ClrVal();              /* CLOCK LOW PULSE */
      Delay();
    }
    ++(*Snt);
  }
  Delay();
  timeout = McuGenericSWI2C_CONFIG_TIMEOUT_COUNTER_VALUE;
  while((SDA_GetVal()==0U)&&(timeout!=0U)) { /* WAIT FOR CLOCK HIGH PULSE */
    timeout--;
    McuGenericSWI2C_OSYIELD();
  }
  if (timeout==0) {
    return ERR_BUSY;
  }
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  SendBlockContinue (component GenericSWI2C)
**
**     Description :
**         Same is SendBlock() but does not send start condition. When
**         working as a MASTER, this method writes 7 bits of slave
**         address plus R/W bit = 0 to the I2C bus and then writes the
**         block of characters to the bus. If the component is disabled
**         (by the "Disable" method or initialization), the block is
**         moved to the output buffer if the 'Output buffer size'
**         property is different from zero. The content of the output
**         buffer is sent immediately with the stop condition at the
**         end when the component is enabled by the "Enable" method.
**         After the output buffer transmission, the whole output
**         buffer is cleared. The slave address must be specified
**         before by the "SelectSlave" method or in component
**         initialization section of 'Slave address init' property.
**         When working as a SLAVE, this method writes block of
**         characters to the bus. If the ERR_NOTAVAIL error code is
**         returned, the whole block is successfully sent to a master
**         but the master device responds by an acknowledgment instead
**         of no acknowledgment sent at the end of the last block byte
**         transfer. 'OnError' event is called in this case.
**     Parameters  :
**         NAME            - DESCRIPTION
**       * Ptr             - A pointer to the block of data to send
**         Siz             - The size of the block
**       * Snt             - A pointer to the number of data that are
**                           sent (copied to buffer)
**     Returns     :
**         ---             - Error code, possible codes:
**                           ERR_OK - OK
**                           ERR_SPEED - This device does not work in
**                           the active speed mode
**                           ERR_BUSY - The slave device is busy, it
**                           does not respond by the acknowledgment
**                           (MASTER mode only)
**                           ERR_TXFULL - Output buffer is full (MASTER
**                           mode only)
**                           ERR_NOTAVAIL - The master device sends
**                           acknowledgment instead of no acknowledgment
**                           after the last byte transfer (SLAVE mode
**                           only)
**                           ERR_DISABLED - Device is disabled
**                           ERR_BUSOFF - Clock timeout elapsed (SLAVE
**                           mode only)
** ===================================================================
*/
uint8_t McuGenericSWI2C_SendBlockContinue(void *Ptr, uint16_t Siz, uint16_t *Snt)
{
  register uint16_t I;
  uint16_t timeout;

  *Snt = 0U;
  for (I = 0U; I < Siz; I++) {
    Write (*((const uint8_t*)Ptr + I) );
    if (GetAck()) {
      SCL_SetDir((bool)OUTPUT);
      SCL_ClrVal();              /* CLOCK LOW PULSE */
      InternalStop();
      return ERR_BUSY;
    } else {
      SCL_SetDir((bool)OUTPUT);
      SCL_ClrVal();              /* CLOCK LOW PULSE */
      Delay();
    }
    ++(*Snt);
  }
  Delay();
  timeout = McuGenericSWI2C_CONFIG_TIMEOUT_COUNTER_VALUE;
  while((SDA_GetVal()==0U)&&(timeout!=0U)) { /* WAIT FOR CLOCK HIGH PULSE */
    timeout--;
    McuGenericSWI2C_OSYIELD();
  }
  if (timeout==0) {
    return ERR_BUSY;
  }
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  RecvBlockCustom (component GenericSWI2C)
**
**     Description :
**         Same as RecvBlock(), but with additional flags to control
**         the bus transfer.
**     Parameters  :
**         NAME            - DESCRIPTION
**       * Ptr             - A pointer to the block space for received
**                           data
**         Siz             - The size of the block
**       * Rcv             - A pointer to the number of actually
**                           received data
**         flagsStart      - Flags for start condition
**         flagsAck        - Flags for Ack after last byte
**     Returns     :
**         ---             - Error code, possible codes:
**                           ERR_OK - OK
**                           ERR_SPEED - This device does not work in
**                           the active speed mode
**                           ERR_BUSY - The slave device is busy, it
**                           does not respond by the acknowledgment
**                           (MASTER mode only)
**                           ERR_DISABLED - Device is disabled
**                           ERR_BUSOFF - Clock timeout elapsed (SLAVE
**                           mode only)
** ===================================================================
*/
uint8_t McuGenericSWI2C_RecvBlockCustom(void *Ptr, uint16_t Siz, uint16_t *Rcv, McuGenericSWI2C_EnumStartFlags flagsStart, McuGenericSWI2C_EnumAckFlags flagsAck)
{
  register uint16_t I;
  bool Acknowledge;
  uint16_t Trial;
  uint16_t timeout;

  *Rcv = 0U;
  Trial = McuGenericSWI2C_CONFIG_NOF_TRIALS;
  if (flagsStart == McuGenericSWI2C_SEND_START) {
    do {
      SDA_SetDir((bool)INPUT);     /* SDA HIGH - START SETUP */
      SCL_SetDir((bool)INPUT);     /* CLOCK HIGH PULSE */
      Delay();                     /* CLOCK HIGH PULSE + BUS FREE TIME */
      /* check that we have a valid start condition: SDA needs to be high */
      timeout = McuGenericSWI2C_CONFIG_TIMEOUT_COUNTER_VALUE;
      while((SDA_GetVal()==0U) && (timeout!=0U)) { /* WAIT FOR CLOCK HIGH PULSE */
        timeout--;
        McuGenericSWI2C_OSYIELD();
      }
      Delay();
      if (timeout==0) {
        /* InternalStop(); */
        return ERR_BUSY;
      }
      SDA_SetDir((bool)OUTPUT);
      SDA_ClrVal();                /* START CONDITION */
      Delay();                     /* START HOLD TIME */
      SCL_SetDir((bool)OUTPUT);
      SCL_ClrVal();                /* CLOCK LOW PULSE */
      Delay();
      Write((uint8_t)(SlaveAddr + READ));
      Acknowledge = GetAck();
      --Trial;
    } while ((Trial != 0U) && Acknowledge);
    if (Acknowledge) {
      /* SCL_SetDir((bool)OUTPUT); */
      /* SCL_ClrVal(); */               /* CLOCK LOW PULSE */
      /* InternalStop(); */
      return ERR_BUSY;
    } else {
      SCL_SetDir((bool)OUTPUT);
      SCL_ClrVal();                /* CLOCK LOW PULSE */
      Delay();
    }
  } /* McuGenericSWI2C_SEND_START */
  for (I = 0U; I < Siz; I++) {
    *((uint8_t *)Ptr + I) = Read();
    timeout = McuGenericSWI2C_CONFIG_TIMEOUT_COUNTER_VALUE;
    while((SDA_GetVal()==0U)&&(timeout!=0U)) { /* WAIT FOR CLOCK HIGH PULSE */
      timeout--;
      McuGenericSWI2C_OSYIELD();
    }
    if (timeout==0) {
      /* InternalStop(); */
      return ERR_BUSY;
    }
    if (I == (Siz - 1U)) {
      if(flagsAck == McuGenericSWI2C_SEND_LAST_ACK){
        McuGenericSWI2C_SendAck((bool)McuGenericSWI2C_NOACK);
      }
    } else {
      McuGenericSWI2C_SendAck((bool)McuGenericSWI2C_ACK);
    }
    ++(*Rcv);
  }
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  RecvBlock (component GenericSWI2C)
**
**     Description :
**         When working as a MASTER, this method writes 7 bits of slave
**         address plus R/W bit = 1 to the I2C bus and then reads the
**         block of characters from the bus. The slave address must be
**         specified before by the "SelectSlave" method or in component
**         initialization section of 'Slave address init' property.
**         When working as a SLAVE, this method reads the block of
**         characters from the bus.
**     Parameters  :
**         NAME            - DESCRIPTION
**       * Ptr             - A pointer to the block space for received
**                           data
**         Siz             - The size of the block
**       * Rcv             - A pointer to the number of actually
**                           received data
**     Returns     :
**         ---             - Error code, possible codes:
**                           ERR_OK - OK
**                           ERR_SPEED - This device does not work in
**                           the active speed mode
**                           ERR_BUSY - The slave device is busy, it
**                           does not respond by the acknowledgment
**                           (MASTER mode only)
**                           ERR_DISABLED - Device is disabled
**                           ERR_BUSOFF - Clock timeout elapsed (SLAVE
**                           mode only)
** ===================================================================
*/
uint8_t McuGenericSWI2C_RecvBlock(void *Ptr, uint16_t Siz, uint16_t *Rcv)
{
  return McuGenericSWI2C_RecvBlockCustom(Ptr, Siz, Rcv, McuGenericSWI2C_SEND_START, McuGenericSWI2C_SEND_LAST_ACK);
}

/*
** ===================================================================
**     Method      :  SendStop (component GenericSWI2C)
**
**     Description :
**         When working as a MASTER, if the 'Automatic stop condition'
**         property value is 'no', this method sends a valid stop
**         condition to the serial data line of the I2C bus to
**         terminate the communication on the bus after using send
**         methods. This method is enabled only if the component is in
**         MASTER mode and 'Automatic stop condition' property value is
**         'no'
**     Parameters  : None
**     Returns     :
**         ---             - Error code, possible codes:
**                           ERR_OK - OK
**                           ERR_SPEED - This device does not work in
**                           the active speed mode
**                           ERR_DISABLED - Device is disabled
** ===================================================================
*/
uint8_t McuGenericSWI2C_SendStop(void)
{
  Delay();
  SDA_SetDir((bool)OUTPUT);
  SDA_ClrVal();                  /* STOP SETUP */
  Delay();
  SCL_SetDir((bool)INPUT);       /* HIGH CLOCK PULSE + STOP SETUP TIME */
  Delay();
  SDA_SetDir((bool)INPUT);       /* STOP CONDITION */
  Delay(); /* add stop time */
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  SelectSlave (component GenericSWI2C)
**
**     Description :
**         When working as a MASTER, this method selects a new slave
**         for communication by its slave address value. Any send or
**         receive method are directed to or from the selected device,
**         until a new slave device is selected by this method. If the
**         selected slave uses 10-bit slave addressing, as the
**         parameter 7 bits must be passed, which involves 10-bit
**         addressing (11110XX), including two MSBs of slave address
**         (XX). The second byte of the 10-bit slave address must be
**         sent to the slave as a general character of send methods.
**         This method is available only if the component is in MASTER
**         mode.
**     Parameters  :
**         NAME            - DESCRIPTION
**         Slv             - Slave address value
**     Returns     :
**         ---             - Error code, possible codes:
**                           ERR_OK - OK
**                           ERR_SPEED - This device does not work in
**                           the active speed mode
**                           ERR_DISABLED -  Device is disabled
** ===================================================================
*/
uint8_t McuGenericSWI2C_SelectSlave(uint8_t Slv)
{
  SlaveAddr = (uint8_t)(Slv<<1);
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  GetSelected (component GenericSWI2C)
**
**     Description :
**         When working as a MASTER, this method returns the
**         identification address value of the slave, which is
**         currently selected for communication with the master. If the
**         current slave uses 10-bit slave addressing, the method
**         returns the first 7 bits only, which involves 10-bit
**         addressing (11110XX), including two MSBs of the slave
**         address (XX). This method is not able to return the rest
**         value of 10-bit slave address. This method is available only
**         if the component is in MASTER mode.
**     Parameters  :
**         NAME            - DESCRIPTION
**       * Slv             - A pointer to the current selected slave
**                           address value
**     Returns     :
**         ---             - Error code, possible codes:
**                           ERR_OK - OK
**                           ERR_SPEED - This device does not work in
**                           the active speed mode
** ===================================================================
*/
uint8_t McuGenericSWI2C_GetSelected(uint8_t *Slv)
{
  *Slv = (uint8_t)(SlaveAddr>>1);
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  Init (component GenericSWI2C)
**
**     Description :
**         Initializes the associated peripheral(s) and the components
**         internal variables.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuGenericSWI2C_Init(void)
{
  SlaveAddr = 0;
  SDA_Init();
  SCL_Init();
}

/*
** ===================================================================
**     Method      :  Deinit (component GenericSWI2C)
**
**     Description :
**         Driver de-initialization method.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuGenericSWI2C_Deinit(void)
{
  SCL_Deinit();
  SDA_Deinit();
  SlaveAddr = 0;
}

/* END McuGenericSWI2C. */

/*!
** @}
*/
