/**
  * @brief  Handle EEPROM Write operation 
  * @param  Device : sEE CPAL device instance
  * @retval None
  */
uint32_t sEE_WriteHandler(CPAL_DevTypeDef Device)
{
	uint32_t DataNum = 0;

	/* wait until EEPROM ready for transfer */
	while (sEE_WaitEepromStandbyState(Device) == CPAL_FAIL) ;

	/* if there are remaining data for write */
	if (sEE_WriteStructures[Device]->sEENextWrite != 0) {
		sEE_WriteStructures[Device]->sEEWriteAddr +=
		    sEE_WriteStructures[Device]->sEEDataNum;
		sEE_WriteStructures[Device]->sEEpBuffer +=
		    sEE_WriteStructures[Device]->sEEDataNum;
		sEE_WriteStructures[Device]->sEENextWrite = 0;

		/* if page must be written in EEPROM */
		if (sEE_WriteStructures[Device]->sEENumOfPage != 0) {
			sEE_WriteStructures[Device]->sEEDataNum =
			    (uint32_t) ((uint16_t) sEE_DevStructures[Device]->
					sEEPageSize);
			sEE_WriteStructures[Device]->sEENumOfPage--;
		}
		/* if single byte must be written in EEPROM */
		else if (sEE_WriteStructures[Device]->sEENumOfSingle != 0) {
			sEE_WriteStructures[Device]->sEEDataNum =
			    (uint32_t) ((uint8_t) sEE_WriteStructures[Device]->
					sEENumOfSingle);
			sEE_WriteStructures[Device]->sEENumOfSingle = 0;
			sEE_WriteStructures[Device]->sEENextWrite = 0;
		}

		/* update number of date for write */
		DataNum = sEE_WriteStructures[Device]->sEEDataNum;

		/* if another data must be written */
		if ((sEE_WriteStructures[Device]->sEENumOfPage != 0)
		    || (sEE_WriteStructures[Device]->sEENumOfSingle != 0)) {
			sEE_WriteStructures[Device]->sEENextWrite = 1;
		}

		/* write data in EEPROM */
		sEE_WritePage(sEE_DevStructures[Device],
			      (uint8_t *) sEE_WriteStructures[Device]->
			      sEEpBuffer,
			      sEE_WriteStructures[Device]->sEEWriteAddr,
			      DataNum);
	} else {
		if (sEE_DevStructures[Device]->sEEState != sEE_STATE_ERROR) {
			/* Reset EEPROM State */
			sEE_DevStructures[Device]->sEEState = sEE_STATE_IDLE;
		}
	}

	return CPAL_PASS;
}
/**
  * @brief  Writes buffer of data to the I2C EEPROM.
  * @param  pBuffer : pointer to the buffer  containing the data to be written 
  *         to the EEPROM.
  * @param  WriteAddr : EEPROM's internal address to write to.
  * @param  NumByteToWrite : number of bytes to write to the EEPROM.
  * @retval None
  */
void sEE_WriteBuffer(uint8_t* pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite)
{
  uint16_t NumOfPage = 0, NumOfSingle = 0, count = 0;
  uint16_t Addr = 0;

  Addr = WriteAddr % sEE_PAGESIZE;
  count = sEE_PAGESIZE - Addr;
  NumOfPage =  NumByteToWrite / sEE_PAGESIZE;
  NumOfSingle = NumByteToWrite % sEE_PAGESIZE;
 
  /*!< If WriteAddr is sEE_PAGESIZE aligned  */
  if(Addr == 0) 
  {
    /*!< If NumByteToWrite < sEE_PAGESIZE */
    if(NumOfPage == 0) 
    {
      /* Store the number of data to be written */
      sEEDataNum = NumOfSingle;
      /* Start writing data */
      sEE_WritePage(pBuffer, WriteAddr, (uint8_t*)(&sEEDataNum));
      /* Wait transfer through DMA to be complete */
      sEETimeout = sEE_LONG_TIMEOUT;
      while (sEEDataNum > 0)
      {
        if((sEETimeout--) == 0) {sEE_TIMEOUT_UserCallback(); return;};
      }
      sEE_WaitEepromStandbyState();
    }
    /*!< If NumByteToWrite > sEE_PAGESIZE */
    else  
    {
      while(NumOfPage--)
      {
        /* Store the number of data to be written */
        sEEDataNum = sEE_PAGESIZE;        
        sEE_WritePage(pBuffer, WriteAddr, (uint8_t*)(&sEEDataNum)); 
        /* Wait transfer through DMA to be complete */
        sEETimeout = sEE_LONG_TIMEOUT;
        while (sEEDataNum > 0)
        {
          if((sEETimeout--) == 0) {sEE_TIMEOUT_UserCallback(); return;};
        }      
        sEE_WaitEepromStandbyState();
        WriteAddr +=  sEE_PAGESIZE;
        pBuffer += sEE_PAGESIZE;
      }

      if(NumOfSingle!=0)
      {
        /* Store the number of data to be written */
        sEEDataNum = NumOfSingle;          
        sEE_WritePage(pBuffer, WriteAddr, (uint8_t*)(&sEEDataNum));
        /* Wait transfer through DMA to be complete */
        sEETimeout = sEE_LONG_TIMEOUT;
        while (sEEDataNum > 0)
        {
          if((sEETimeout--) == 0) {sEE_TIMEOUT_UserCallback(); return;};
        }    
        sEE_WaitEepromStandbyState();
      }
    }
  }
  /*!< If WriteAddr is not sEE_PAGESIZE aligned  */
  else 
  {
    /*!< If NumByteToWrite < sEE_PAGESIZE */
    if(NumOfPage== 0) 
    {
      /*!< If the number of data to be written is more than the remaining space 
      in the current page: */
      if (NumByteToWrite > count)
      {
        /* Store the number of data to be written */
        sEEDataNum = count;        
        /*!< Write the data contained in same page */
        sEE_WritePage(pBuffer, WriteAddr, (uint8_t*)(&sEEDataNum));
        /* Wait transfer through DMA to be complete */
        sEETimeout = sEE_LONG_TIMEOUT;
        while (sEEDataNum > 0)
        {
          if((sEETimeout--) == 0) {sEE_TIMEOUT_UserCallback(); return;};
        }          
        sEE_WaitEepromStandbyState();      
        
        /* Store the number of data to be written */
        sEEDataNum = (NumByteToWrite - count);          
        /*!< Write the remaining data in the following page */
        sEE_WritePage((uint8_t*)(pBuffer + count), (WriteAddr + count), (uint8_t*)(&sEEDataNum));
        /* Wait transfer through DMA to be complete */
        sEETimeout = sEE_LONG_TIMEOUT;
        while (sEEDataNum > 0)
        {
          if((sEETimeout--) == 0) {sEE_TIMEOUT_UserCallback(); return;};
        }     
        sEE_WaitEepromStandbyState();        
      }      
      else      
      {
        /* Store the number of data to be written */
        sEEDataNum = NumOfSingle;         
        sEE_WritePage(pBuffer, WriteAddr, (uint8_t*)(&sEEDataNum));
        /* Wait transfer through DMA to be complete */
        sEETimeout = sEE_LONG_TIMEOUT;
        while (sEEDataNum > 0)
        {
          if((sEETimeout--) == 0) {sEE_TIMEOUT_UserCallback(); return;};
        }          
        sEE_WaitEepromStandbyState();        
      }     
    }
    /*!< If NumByteToWrite > sEE_PAGESIZE */
    else
    {
      NumByteToWrite -= count;
      NumOfPage =  NumByteToWrite / sEE_PAGESIZE;
      NumOfSingle = NumByteToWrite % sEE_PAGESIZE;
      
      if(count != 0)
      {  
        /* Store the number of data to be written */
        sEEDataNum = count;         
        sEE_WritePage(pBuffer, WriteAddr, (uint8_t*)(&sEEDataNum));
        /* Wait transfer through DMA to be complete */
        sEETimeout = sEE_LONG_TIMEOUT;
        while (sEEDataNum > 0)
        {
          if((sEETimeout--) == 0) {sEE_TIMEOUT_UserCallback(); return;};
        }     
        sEE_WaitEepromStandbyState();
        WriteAddr += count;
        pBuffer += count;
      } 
      
      while(NumOfPage--)
      {
        /* Store the number of data to be written */
        sEEDataNum = sEE_PAGESIZE;          
        sEE_WritePage(pBuffer, WriteAddr, (uint8_t*)(&sEEDataNum));
        /* Wait transfer through DMA to be complete */
        sEETimeout = sEE_LONG_TIMEOUT;
        while (sEEDataNum > 0)
        {
          if((sEETimeout--) == 0) {sEE_TIMEOUT_UserCallback(); return;};
        }        
        sEE_WaitEepromStandbyState();
        WriteAddr +=  sEE_PAGESIZE;
        pBuffer += sEE_PAGESIZE;  
      }
      if(NumOfSingle != 0)
      {
        /* Store the number of data to be written */
        sEEDataNum = NumOfSingle;           
        sEE_WritePage(pBuffer, WriteAddr, (uint8_t*)(&sEEDataNum)); 
        /* Wait transfer through DMA to be complete */
        sEETimeout = sEE_LONG_TIMEOUT;
        while (sEEDataNum > 0)
        {
          if((sEETimeout--) == 0) {sEE_TIMEOUT_UserCallback(); return;};
        }         
        sEE_WaitEepromStandbyState();
      }
    }
  }  
}
/**
  * @brief  Writes buffer of data to the I2C EEPROM.
  * @param  sEEInitStruct : Pointer to sEE Device structure
  * @param  pBuffer : pointer to the buffer  containing the data to be written 
  *         to the EEPROM.
  * @param  WriteAddr : EEPROM's internal address to write to.
  * @param  NumByteToWrite : number of bytes to write to the EEPROM.
  * @retval None
  */
uint32_t sEE_WriteBuffer(sEE_InitTypeDef * sEEInitStruct, uint8_t * pBuffer,
			 uint16_t WriteAddr, uint32_t NumByteToWrite)
{
	uint32_t DataNum = 0;
	uint16_t count = 0;
	uint16_t Addr = 0;

	if (sEEInitStruct->sEEState == sEE_STATE_IDLE) {
		sEEInitStruct->sEEState = sEE_STATE_WRITING;

		sEE_WriteStructures[sEEInitStruct->sEE_CPALStructure->
				    CPAL_Dev]->sEEDataNum = 0;
		sEE_WriteStructures[sEEInitStruct->sEE_CPALStructure->
				    CPAL_Dev]->sEEWriteAddr = 0;
		sEE_WriteStructures[sEEInitStruct->sEE_CPALStructure->
				    CPAL_Dev]->sEEpBuffer = pNULL;
		sEE_WriteStructures[sEEInitStruct->sEE_CPALStructure->
				    CPAL_Dev]->sEENumOfPage = 0;
		sEE_WriteStructures[sEEInitStruct->sEE_CPALStructure->
				    CPAL_Dev]->sEENextWrite = 0;
		sEE_WriteStructures[sEEInitStruct->sEE_CPALStructure->
				    CPAL_Dev]->sEENumOfSingle = 0;

		/* if one data will be written */
		if (NumByteToWrite == 1) {
			/* Transfer complete */
			sEE_WriteStructures[sEEInitStruct->sEE_CPALStructure->
					    CPAL_Dev]->sEENextWrite = 0;

			/* update number od data for write */
			DataNum = NumByteToWrite;

			if (sEE_WritePage
			    (sEEInitStruct, pBuffer, WriteAddr,
			     DataNum) != CPAL_PASS) {
				return CPAL_FAIL;
			}
		}
		/* Use Write page */
		else {
			/* if Address aligned reset count value to 0 */
			Addr = WriteAddr % sEEInitStruct->sEEPageSize;

			if (Addr == 0) {
				count = 0;
			} else {
				count = sEEInitStruct->sEEPageSize - Addr;

				if (NumByteToWrite <= count) {
					count = NumByteToWrite;
				}
			}

			/* Get Number of page for write and number of single byte */
			sEE_WriteStructures[sEEInitStruct->sEE_CPALStructure->
					    CPAL_Dev]->sEENumOfPage =
			    (uint16_t) ((NumByteToWrite -
					 count) / sEEInitStruct->sEEPageSize);
			sEE_WriteStructures[sEEInitStruct->sEE_CPALStructure->
					    CPAL_Dev]->sEENumOfSingle =
			    (uint8_t) ((NumByteToWrite -
					count) % sEEInitStruct->sEEPageSize);

			/* If WriteAddr is sEE_PAGESIZE is not aligned  */
			if (Addr != 0) {
				/* Update Number of data to write */
				sEE_WriteStructures[sEEInitStruct->
						    sEE_CPALStructure->
						    CPAL_Dev]->sEEDataNum =
				    count;
			}
			/* If WriteAddr is sEE_PAGESIZE is aligned  */
			else {
				/* if only single byte must be written */
				if (sEE_WriteStructures
				    [sEEInitStruct->sEE_CPALStructure->
				     CPAL_Dev]->sEENumOfPage == 0) {
					/* update number of data to write */
					sEE_WriteStructures[sEEInitStruct->
							    sEE_CPALStructure->
							    CPAL_Dev]->
					    sEEDataNum =
					    sEE_WriteStructures[sEEInitStruct->
								sEE_CPALStructure->
								CPAL_Dev]->
					    sEENumOfSingle;

					/* reset number of single */
					sEE_WriteStructures[sEEInitStruct->
							    sEE_CPALStructure->
							    CPAL_Dev]->
					    sEENumOfSingle = 0;
				} else {
					/* update number of data to write */
					sEE_WriteStructures[sEEInitStruct->
							    sEE_CPALStructure->
							    CPAL_Dev]->
					    sEEDataNum =
					    (uint32_t) ((uint16_t)
							sEEInitStruct->
							sEEPageSize);

					/* update number of page */
					sEE_WriteStructures[sEEInitStruct->
							    sEE_CPALStructure->
							    CPAL_Dev]->
					    sEENumOfPage--;
				}
			}

			/* update global variable */
			DataNum =
			    sEE_WriteStructures[sEEInitStruct->
						sEE_CPALStructure->CPAL_Dev]->
			    sEEDataNum;
			sEE_WriteStructures[sEEInitStruct->sEE_CPALStructure->
					    CPAL_Dev]->sEEWriteAddr =
			    (uint32_t) ((uint16_t) WriteAddr);
			sEE_WriteStructures[sEEInitStruct->sEE_CPALStructure->
					    CPAL_Dev]->sEEpBuffer = pBuffer;

			/* If there are remaining data to transfer */
			if ((sEE_WriteStructures
			     [sEEInitStruct->sEE_CPALStructure->CPAL_Dev]->
			     sEENumOfPage != 0)
			    ||
			    (sEE_WriteStructures
			     [sEEInitStruct->sEE_CPALStructure->CPAL_Dev]->
			     sEENumOfSingle != 0)) {
				/* update global variable */
				sEE_WriteStructures[sEEInitStruct->
						    sEE_CPALStructure->
						    CPAL_Dev]->sEENextWrite = 1;
			}

			/* Write data on EEPROM */
			if (sEE_WritePage
			    (sEEInitStruct, pBuffer, WriteAddr,
			     DataNum) != CPAL_PASS) {
				return CPAL_FAIL;
			}

		}
		return CPAL_PASS;
	} else {
		return CPAL_FAIL;
	}
}
/**
  * @brief  Writes block of data to the EEPROM. In this function, the number of
  *         WRITE cycles are reduced, using Page WRITE sequence.
  * @param  pBuffer: pointer to the buffer  containing the data to be written
  *         to the EEPROM.
  * @param  WriteAddr: EEPROM's internal address to write to.
  * @param  NumByteToWrite: number of bytes to write to the EEPROM.
  * @retval None
  */
void sEE_WriteBuffer(uint8_t* pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite)
{
    uint16_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
    uint16_t   sEE_DataNum = 0;

    Addr = WriteAddr % sEE_PAGESIZE;
    count = sEE_PAGESIZE - Addr;
    NumOfPage =  NumByteToWrite / sEE_PAGESIZE;
    NumOfSingle = NumByteToWrite % sEE_PAGESIZE;

    if (Addr == 0) /*!< WriteAddr is sEE_PAGESIZE aligned  */
    {
        if (NumOfPage == 0) /*!< NumByteToWrite < sEE_PAGESIZE */
        {
            sEE_DataNum = NumByteToWrite;
            sEE_WritePage(pBuffer, WriteAddr, &sEE_DataNum);
        }
        else /*!< NumByteToWrite > sEE_PAGESIZE */
        {
            while (NumOfPage--)
            {
                sEE_DataNum = sEE_PAGESIZE;
                sEE_WritePage(pBuffer, WriteAddr, &sEE_DataNum);
                WriteAddr +=  sEE_PAGESIZE;
                pBuffer += sEE_PAGESIZE;
            }

            sEE_DataNum = NumOfSingle;
            sEE_WritePage(pBuffer, WriteAddr, &sEE_DataNum);
        }
    }
    else /*!< WriteAddr is not sEE_PAGESIZE aligned  */
    {
        if (NumOfPage == 0) /*!< NumByteToWrite < sEE_PAGESIZE */
        {
            if (NumOfSingle > count) /*!< (NumByteToWrite + WriteAddr) > sEE_PAGESIZE */
            {
                temp = NumOfSingle - count;
                sEE_DataNum = count;
                sEE_WritePage(pBuffer, WriteAddr, &sEE_DataNum);
                WriteAddr +=  count;
                pBuffer += count;

                sEE_DataNum = temp;
                sEE_WritePage(pBuffer, WriteAddr, &sEE_DataNum);
            }
            else
            {
                sEE_DataNum = NumByteToWrite;
                sEE_WritePage(pBuffer, WriteAddr, &sEE_DataNum);
            }
        }
        else /*!< NumByteToWrite > sEE_PAGESIZE */
        {
            NumByteToWrite -= count;
            NumOfPage =  NumByteToWrite / sEE_PAGESIZE;
            NumOfSingle = NumByteToWrite % sEE_PAGESIZE;

            sEE_DataNum = count;

            sEE_WritePage(pBuffer, WriteAddr, &sEE_DataNum);
            WriteAddr +=  count;
            pBuffer += count;

            while (NumOfPage--)
            {
                sEE_DataNum = sEE_PAGESIZE;

                sEE_WritePage(pBuffer, WriteAddr, &sEE_DataNum);
                WriteAddr +=  sEE_PAGESIZE;
                pBuffer += sEE_PAGESIZE;
            }

            if (NumOfSingle != 0)
            {
                sEE_DataNum = NumOfSingle;

                sEE_WritePage(pBuffer, WriteAddr, &sEE_DataNum);
            }
        }
    }
}