/***********************************************************************************************\
* Freescale MMA8451,2,3Q Driver
*
* Filename: mma845x.c
*
*
* (c) Copyright 2010, Freescale, Inc.  All rights reserved.
*
* No part of this document must be reproduced in any form - including copied,
* transcribed, printed or by any electronic means - without specific written
* permission from Freescale Semiconductor.
*
\***********************************************************************************************/

#ifdef __cplusplus
extern "C" {
#endif

#include "Mcal.h"
#include "Siul2_Port_Ip.h"
#include "Siul2_Dio_Ip.h"
#include "Lpi2c_ip.h"
#include "IntCtrl_Ip.h"
#include "MMA845x.h"

/***********************************************************************************************\
* Private macros
\***********************************************************************************************/
#define ACC_I2C_INST 			0  /*use LPI2C0 for MMA8452Q 3-axi accelerator*/

#define ACC_I2C_MasterConfig	I2c_Lpi2cMasterChannel0_BOARD_InitPeripherals

#define ACC_I2C_IRQn 			LPI2C_0_IRQn /*define the */

#define MMA_TIMEOUT  			0xFFFFFF  /* define the MMA8452Q I2C communication timeout */

/***********************************************************************************************\
* Private type definitions
\***********************************************************************************************/

/***********************************************************************************************\
* Private prototypes
\***********************************************************************************************/
extern void OsIf_Delay_Ms(uint32_t nMsec);
/***********************************************************************************************\
* Private memory declarations
\***********************************************************************************************/

/***********************************************************************************************\
* Public memory declarations
\***********************************************************************************************/
int32_t MMA8452Q_ACC_x, MMA8452Q_ACC_y, MMA8452Q_ACC_z;


/***********************************************************************************************\
* Public functions
\***********************************************************************************************/
extern void LPI2C0_Master_Slave_IRQHandler(void);

/*
 * write the register at RegAddr with value of RegVal
 */
void IIC_RegWrite(uint8_t RegAddr, uint8_t RegVal)
{
	uint8_t ACC_masterTxBuffer[8] = {0};
	uint32 bytesRemaining = 0;

    ACC_masterTxBuffer[0] = RegAddr;/*set target register address*/
    ACC_masterTxBuffer[1] = RegVal;  /*set the register value to write*/
    Lpi2c_Ip_MasterSendData(ACC_I2C_INST,  ACC_masterTxBuffer, 2, true);/*transmit slave address + write and register address */

    /* wait for transfer complete */
    while(LPI2C_IP_BUSY_STATUS==Lpi2c_Ip_MasterGetTransferStatus(ACC_I2C_INST, &bytesRemaining));
}
/*
 * read back the register at RegAddr, and return one byte by *RegVal
 */
void IIC_RegRead(uint8_t RegAddr, uint8_t *RegVal)
{
	uint8_t ACC_masterTxBuffer[8] = {0};
	uint32 bytesRemaining = 0;
	Std_ReturnType retCode = E_OK;

	ACC_masterTxBuffer[0] = RegAddr;/*set target register address*/
	retCode |= (Std_ReturnType) Lpi2c_Ip_MasterSendData(ACC_I2C_INST,  ACC_masterTxBuffer, 1, false);/*transmit slave address + write and register address */

	/* wait for transfer complete */
	while(LPI2C_IP_BUSY_STATUS==Lpi2c_Ip_MasterGetTransferStatus(ACC_I2C_INST, &bytesRemaining));

	retCode |= (Std_ReturnType) Lpi2c_Ip_MasterReceiveData(ACC_I2C_INST,  RegVal, 1, true);/*transmit slave address + read and read the register*/

	/* wait for transfer complete */
	while(LPI2C_IP_BUSY_STATUS==Lpi2c_Ip_MasterGetTransferStatus(ACC_I2C_INST, &bytesRemaining));
}
/*
 * read back the register at RegAddr, and return Byte_Num byte by *RegVal
 */
void IIC_RegRead_MultiByte(uint8_t RegAddr, uint8_t *RegVal, uint32_t Byte_Num)
{
	uint8_t ACC_masterTxBuffer[8] = {0};

	uint32 bytesRemaining = 0;

	ACC_masterTxBuffer[0] = RegAddr;/*set target register address*/
	Lpi2c_Ip_MasterSendData(ACC_I2C_INST,  ACC_masterTxBuffer, 1, false);/*transmit slave address + write and register address */

	/* wait for transfer complete */
	while(LPI2C_IP_BUSY_STATUS==Lpi2c_Ip_MasterGetTransferStatus(ACC_I2C_INST, &bytesRemaining));

	Lpi2c_Ip_MasterReceiveData(ACC_I2C_INST,  RegVal, Byte_Num, true);/*transmit slave address + read and read the register*/

	/* wait for transfer complete */
	while(LPI2C_IP_BUSY_STATUS==Lpi2c_Ip_MasterGetTransferStatus(ACC_I2C_INST, &bytesRemaining));
}
/*********************************************************\
* Put MMA845xQ into Active Mode
\*********************************************************/
void MMA845x_Active ()
{
	uint8_t RegVal_Read = 0;

	IIC_RegRead(CTRL_REG1, &RegVal_Read);
	IIC_RegWrite(CTRL_REG1, (RegVal_Read|ACTIVE_MASK));
}

/*********************************************************\
* Put MMA845xQ into Standby Mode
\*********************************************************/
void MMA845x_Standby (void)
{
  uint8_t n;
  /*
  **  Read current value of System Control 1 Register.
  **  Put sensor into Standby Mode.
  **  Return with previous value of System Control 1 Register.
  */

	IIC_RegRead(CTRL_REG1,&n);
	IIC_RegWrite(CTRL_REG1, n & ~ACTIVE_MASK);
}

/***********************************************************************************\
* Initialize MMA845xQ
* configure the I2C interface
* read the device ID and identify the chip, if correct do initialization
\***********************************************************************************/
Std_ReturnType MMA845x_Init (void)
{
	uint8_t temp = 0;
	Std_ReturnType retCode;

	/* Initialize the I2C module for ACC communication  */
	retCode = Lpi2c_Ip_MasterInit(ACC_I2C_INST, &ACC_I2C_MasterConfig);

	/* Install LPI2C0 ISR and enable LPI2C0 IRQ */
	IntCtrl_Ip_InstallHandler(LPI2C0_IRQn, LPI2C0_Master_Slave_IRQHandler, NULL_PTR);
	IntCtrl_Ip_EnableIrq(LPI2C0_IRQn);

	/*initialize the I2C interface for MMA8452 accelerator communication*/
	Lpi2c_Ip_MasterSetSlaveAddr(ACC_I2C_INST, MMA845x_I2C_ADDRESS, ACC_I2C_MasterConfig.Is10bitAddr);/* set the slave address */

	IIC_RegRead(MMA845x_WHO_AM_I, &temp);/*read the device ID*/

	if(temp==MMA8452Q_ID)/*if it is matched, do initialization*/
	{
	  /* first step: Put the MMA8452 into Standby mode for configuration*/
	  MMA845x_Standby();
	  /*
	   * second step: configure the parameter as user requirements
	   *
	  **  Configure sensor for:
	  **    - Sleep Mode Poll Rate of 50Hz (20ms)
	  **    - System Output Data Rate of 200Hz (5ms)
	  **    - Full Scale of +/-8g
	  */
	  IIC_RegWrite(CTRL_REG1, ASLP_RATE_20MS+DATA_RATE_5MS);
	  IIC_RegWrite(XYZ_DATA_CFG_REG, FULL_SCALE_8G);

	  /* last step: Put the MMA8452 into Active mode for normal work*/
	  MMA845x_Active();

	  //LOGI(TAG,"The MMA8452A accelerator is initialized successfully!\r\n");
	  retCode = E_OK;
  }
  else
  {
	  //LOGE(TAG,"The MMA8452A accelerator initialization failed!\r\n");
	  retCode = E_NOT_OK;
  }

  return retCode;
}

/*********************************************************\
* get the 3-axis accelerator data with unit g from MMA845xQ
\*********************************************************/
void MMA845x_Get_accelerator (float *x, float *y, float *z)
{
	uint8_t Raw_Data[6] ={0};
	uint8_t Status_Flag = 0;

	uint32_t i = 0;

	signed int temp = 0;

	IIC_RegRead(MMA845x_STATUS_00,&Status_Flag);/*read back the status register*/

	if(Status_Flag&ZYXDR_MASK)/*if a new set of data is ready*/
	{

	//	IIC_RegRead_MultiByte(MMA845x_OUT_X_MSB,Raw_Data,6);/*read back the raw data*/

		for(i=0;i<6;i++)
		{
			 IIC_RegRead((i+1),&Raw_Data[i]);
		}

		/*
		 * get the x axis accelerated velocity
		 */
		temp = ((int16_t)(((uint16_t)Raw_Data[0]<<8) + Raw_Data[1]))>>4;

		*x = (float)temp/256; /*convert LSB count to g*/


		/*
		 * get the y axis accelerated velocity
		 */
		temp = ((int16_t)(((uint16_t)Raw_Data[2]<<8) + Raw_Data[3]))>>4;

		*y = (float)temp/256; /*convert LSB count to g*/

		/*
		 * get the z axis accelerated velocity
		 */
		temp = ((int16_t)(((uint16_t)Raw_Data[4]<<8) + Raw_Data[5]))>>4;

		*z = (float)temp/256; /*convert LSB count to g*/
	}
}

/*********************************************************\
* get the 3-axis accelerator data with unit LSB cnt from MMA845xQ
\*********************************************************/
void MMA845x_Get_accelerator_raw (int32_t *x, int32_t *y, int32_t *z)
{
	uint8_t Raw_Data[6] ={0};
	uint8_t Status_Flag = 0;

	uint32_t i = 0;

	signed int temp = 0;

	IIC_RegRead(MMA845x_STATUS_00,&Status_Flag);/*read back the status register*/

	if(Status_Flag&ZYXDR_MASK)/*if a new set of data is ready*/
	{

	//	IIC_RegRead_MultiByte(MMA845x_OUT_X_MSB,Raw_Data,6);/*read back the raw data*/

		for(i=0;i<6;i++)
		{
			 IIC_RegRead((i+1),&Raw_Data[i]);
		}

		/*
		 * get the x axis accelerated velocity
		 */
		temp = ((int16_t)(((uint16_t)Raw_Data[0]<<8) + Raw_Data[1]))>>4;

		*x = temp;


		/*
		 * get the y axis accelerated velocity
		 */
		temp = ((int16_t)(((uint16_t)Raw_Data[2]<<8) + Raw_Data[3]))>>4;

		*y = temp;

		/*
		 * get the z axis accelerated velocity
		 */
		temp = ((int16_t)(((uint16_t)Raw_Data[4]<<8) + Raw_Data[5]))>>4;

		*z = temp;
	}
}

/*********************************************************\
* a simple test of MMA8452 3-axis accelerator
\*********************************************************/
void MMA8452_Test(void)
{

	/********************************************************************************************
	 * if other I2C external device is used on the same I2C instance at the same time,
	 * it's a must to re-configure the I2C slave address
	 * as they are using the same I2C but with different salve address
	 * *****************************************************************************************/
	Lpi2c_Ip_MasterSetSlaveAddr(ACC_I2C_INST, MMA845x_I2C_ADDRESS, ACC_I2C_MasterConfig.Is10bitAddr);

	OsIf_Delay_Ms(1);	/* do some delay*/

	/* Divide the raw value by 256 to get the float value in unit g.  */
	MMA845x_Get_accelerator_raw(&MMA8452Q_ACC_x, &MMA8452Q_ACC_y, &MMA8452Q_ACC_z);
}


/***********************************************************************************************\
* Private functions
\***********************************************************************************************/

#ifdef __cplusplus
}
#endif
