
#include "mpu9250.h"

enum Mscale {
  MFS_14BITS = 0, // 0.6 mG per LSB
  MFS_16BITS      // 0.15 mG per LSB
};

uint8_t Mscale = MFS_16BITS; // MFS_14BITS or MFS_16BITS, 14-bit or 16-bit magnetometer resolution
uint8_t Mmode = 0x06;        // Either 8 Hz 0x02) or 100 Hz (0x06) magnetometer data ODR
float aRes, gRes, mRes;      // scale resolutions per LSB for the sensors

float gyroBias[3] = {0, 0, 0};
float accelBias[3] = {0, 0, 0}; // Bias corrections for gyro and accelerometer
float magCalibration[3] = {0, 0, 0};
float magbias[3] = {0, 0, 0};  // Factory mag calibration and mag bias

static int32_t	accel_bias_int[3] = {0, 0, 0};
static int32_t  gyro_bias_int[3] = {0, 0, 0};

//================================================================
//			INIT MPU9250
//================================================================
void mpu9250_InitMPU9250()
{
	mpu9250_ResetMPU9250();
	HAL_Delay(100);
	// wake up device
	i2c1_WriteRegByte_IT(MPU9250_ADDRESS, PWR_MGMT_1, 	0x00); // Clear sleep mode bit (6), enable all sensors
	HAL_Delay(100); // Delay 100 ms for PLL to get established on x-axis gyro; should check for PLL ready interrupt
	i2c1_WriteRegByte_IT(MPU9250_ADDRESS, PWR_MGMT_1, 	0x01);  // Set clock source to be PLL with x-axis gyroscope reference, bits 2:0 = 001
	i2c1_WriteRegByte_IT(MPU9250_ADDRESS, PWR_MGMT_2, 	0x00);
	i2c1_WriteRegByte_IT(MPU9250_ADDRESS, CONFIG, 		BANDWITH_GYRO_250_HZ); //41
	i2c1_WriteRegByte_IT(MPU9250_ADDRESS, SMPLRT_DIV, 	SAMPLE_RATE_DIVIDER_0);
	i2c1_WriteRegByte_IT(MPU9250_ADDRESS, GYRO_CONFIG, 	GYRO_FULL_SCALE_1000_DPS);
	i2c1_WriteRegByte_IT(MPU9250_ADDRESS, ACCEL_CONFIG, 	ACC_FULL_SCALE_4_G);
	i2c1_WriteRegByte_IT(MPU9250_ADDRESS, ACCEL_CONFIG2, BANDWITH_ACCEL_41_Hz);
	i2c1_WriteRegByte_IT(MPU9250_ADDRESS, INT_PIN_CFG, 	BYPASS_EN); // 0x37 0x02
}
//================================================================
//			INIT MAGNETOMETER AK8963
//================================================================
void mpu9250_InitAK8963(float * destination)
{
// First extract the factory calibration for each magnetometer axis
uint8_t rawData[3];  // x/y/z gyro calibration data stored here
i2c1_WriteRegByte_IT( AK8963_ADDRESS, AK8963_CNTL, 0x00); // Power down magnetometer
HAL_Delay(10);
i2c1_WriteRegByte_IT( AK8963_ADDRESS, AK8963_CNTL, 0x0F); // Enter Fuse ROM access mode
HAL_Delay(10);
i2c1_ReadRegBuffer_IT( AK8963_ADDRESS, AK8963_ASAX,&rawData[0],3);  // Read the x-, y-, and z-axis calibration values
destination[0] =  (float)(rawData[0] - 128)/256.0f + 1.0f;   // Return x-axis sensitivity adjustment values, etc.
destination[1] =  (float)(rawData[1] - 128)/256.0f + 1.0f;
destination[2] =  (float)(rawData[2] - 128)/256.0f + 1.0f;
i2c1_WriteRegByte_IT(AK8963_ADDRESS, AK8963_CNTL, 0x00); // Power down magnetometer
HAL_Delay(10);
// Configure the magnetometer for continuous read and highest resolution
// set Mscale bit 4 to 1 (0) to enable 16 (14) bit resolution in CNTL register,
// and enable continuous mode data acquisition Mmode (bits [3:0]), 0010 for 8 Hz and 0110 for 100 Hz sample rates
i2c1_WriteRegByte_IT(AK8963_ADDRESS, AK8963_CNTL, Mscale << 4 | Mmode); // Set magnetometer data resolution and sample ODR  // 0x0A 0x16
HAL_Delay(10);
}
//================================================================
//	GET MPU9250 DEVICE ID (Default Value : 0x71)
//================================================================
uint8_t mpu9250_WhoAmI(void)
{
	uint8_t response=0;
	i2c1_ReadRegBuffer_IT( MPU9250_ADDRESS, WHO_AM_I_MPU9250 ,&response,1);
	return response;
}
//================================================================
// 		GET MAGNETOMETER AK8963 DEVICE ID
//================================================================
uint8_t mpu9250_MagWhoAmI(void)
{
	uint8_t response=0;
	i2c1_ReadRegBuffer_IT( AK8963_ADDRESS, WHO_AM_I_AK8963 ,&response,1);
	return response;
}
//================================================================
//				STEP
//================================================================
void mpu9250_Step(void)
{
		const float conversion_Acc = 4.0/32768.0;
		const float conversion_Gyro = (100.0/32768.0)*(PI/18.0);
		uint8_t Buf[14];
		// ____________________________________
		// :::  accelerometer and gyroscope :::

		// Lecture de 14 Registres à partir de ACCEL_XOUT_H
		// ACCEL_XOUT_H, ACCEL_XOUT_L, ACCEL_YOUT_H, ACCEL_YOUT_L, ACCEL_ZOUT_H, ACCEL_ZOUT_L
		// TEMP_OUT_H, TEMP_OUT_L, GYRO_XOUT_H, GYRO_XOUT_L, GYRO_YOUT_H, GYRO_YOUT_L, GYRO_ZOUT_H, GYRO_ZOUT_L
		i2c1_ReadRegBuffer( MPU9250_ADDRESS,ACCEL_XOUT_H ,Buf,14);

		int16_t ax=-(Buf[0]<<8 | Buf[1]);
		int16_t ay=-(Buf[2]<<8 | Buf[3]);
		int16_t az=Buf[4]<<8 | Buf[5];

		ax=ax+accel_bias_int[0];
		ay=ay+accel_bias_int[1];
		az=az-accel_bias_int[2];

		int16_t gx=-(Buf[8]<<8 | Buf[9]);
		int16_t gy=-(Buf[10]<<8 | Buf[11]);
		int16_t gz=Buf[12]<<8 | Buf[13];

		gx = gx + gyro_bias_int[0];
		gy = gy + gyro_bias_int[1];
		gz = gz - gyro_bias_int[2];

		float f_gx = gx * conversion_Gyro;
		float f_gy = gy * conversion_Gyro;
		float f_gz = gz * conversion_Gyro;

		float f_ax = ax * conversion_Acc;
		float f_ay = ay * conversion_Acc;
		float f_az = az * conversion_Acc;

#ifndef USE_MAGNETOMETER
		MadgwickAHRSupdateIMU(f_gx,f_gy,f_gz,f_ax,f_ay,f_az);
#elif USE_MAGNETOMETER
	   	//_____________________
	    // :::  Magnetometer :::
	    // Read register Status 1 and wait for the DRDY: Data Ready
		const float conversion_Mag = 1.0;

	    uint8_t magStatus1=0;
	    do
	    {
	   	 i2c1_ReadRegBuffer_IT( AK8963_ADDRESS,AK8963_ST1 ,&magStatus1,1);
	    }
	    while (!(magStatus1&0x01));
	    // Read magnetometer data
	    uint8_t Mag[7];
	   	i2c1_ReadRegBuffer_IT( AK8963_ADDRESS,AK8963_XOUT_L,Mag,7);
    	int16_t mx=-(Mag[3]<<8 | Mag[2]);
    	int16_t my=-(Mag[1]<<8 | Mag[0]);
    	int16_t mz=-(Mag[5]<<8 | Mag[4]);

		float f_mx = mx * conversion_Mag;
		float f_my = my * conversion_Mag;
		float f_mz = mz * conversion_Mag;

		MadgwickAHRSupdate(f_gx,f_gy,f_gz,f_ax,f_ay,f_az,);
		term_printf("f_mx: %f",f_mx);
		term_printf("f_my: %f",f_my);
		term_printf("f_mz: %f",f_mz);
#endif		
		// term_printf("________\n");
		// term_printf("q0: %f\n",get_q0());
		// term_printf("q1: %f\n",get_q1());
		// term_printf("q2: %f\n",get_q2());
		// term_printf("q3: %f\n",get_q3());
  }
//================================================================
//			READ ACCELERATION
//================================================================
void mpu9250_ReadAccelData(int16_t * destination)
{
  uint8_t rawData[6];  // x/y/z accel register data stored here
  i2c1_ReadRegBuffer_IT( MPU9250_ADDRESS, ACCEL_XOUT_H,&rawData[0],6);  // Read the six raw data registers into data array
  destination[0] = (int16_t)(((int16_t)rawData[0] << 8) | rawData[1]) ;  // Turn the MSB and LSB into a signed 16-bit value
  destination[1] = (int16_t)(((int16_t)rawData[2] << 8) | rawData[3]) ;
  destination[2] = (int16_t)(((int16_t)rawData[4] << 8) | rawData[5]) ;
}
//================================================================
//			READ GYRO
//================================================================
void mpu9250_ReadGyroData(int16_t * destination)
{
  uint8_t rawData[6];  // x/y/z gyro register data stored here
  i2c1_ReadRegBuffer_IT( MPU9250_ADDRESS, GYRO_XOUT_H, &rawData[0],6);  // Read the six raw data registers sequentially into data array
  destination[0] = (int16_t)(((int16_t)rawData[0] << 8) | rawData[1]) ;  // Turn the MSB and LSB into a signed 16-bit value
  destination[1] = (int16_t)(((int16_t)rawData[2] << 8) | rawData[3]) ;
  destination[2] = (int16_t)(((int16_t)rawData[4] << 8) | rawData[5]) ;
}
//================================================================
//			READ MAGNETOMETER
//================================================================
void mpu9250_ReadMagData(int16_t * destination)
{
  uint8_t rawData[7];  // x/y/z gyro register data, ST2 register stored here, must read ST2 at end of data acquisition
  uint8_t magStatus1=0;
  do
  {
 	 i2c1_ReadRegBuffer_IT( AK8963_ADDRESS,AK8963_ST1 , &magStatus1,1);
  }
  while (!(magStatus1&0x01)); // wait for magnetometer data ready bit to be set

  i2c1_ReadRegBuffer_IT(AK8963_ADDRESS, AK8963_XOUT_L, &rawData[0],7);  // Read the six raw data and ST2 registers sequentially into data array
  uint8_t c = rawData[6]; // End data read by reading ST2 register
    if(!(c & 0x08)) { // Check if magnetic sensor overflow set, if not then report data
    destination[0] = (int16_t)(((int16_t)rawData[1] << 8) | rawData[0]);  // Turn the MSB and LSB into a signed 16-bit value
    destination[1] = (int16_t)(((int16_t)rawData[3] << 8) | rawData[2]) ;  // Data stored as little Endian
    destination[2] = (int16_t)(((int16_t)rawData[5] << 8) | rawData[4]) ;
   }
}
//================================================================
//			READ TEMPERATURE
//================================================================
int16_t mpu9250_ReadTempData()
{
  uint8_t rawData[2];  // x/y/z gyro register data stored here
  i2c1_ReadRegBuffer_IT( MPU9250_ADDRESS, TEMP_OUT_H, &rawData[0],2);  // Read the two raw data registers sequentially into data array
  return (int16_t)(((int16_t)rawData[0]) << 8 | rawData[1]) ;  // Turn the MSB and LSB into a 16-bit value
}
//================================================================
//			RESET MPU9250
//================================================================
void mpu9250_ResetMPU9250()
{
	i2c1_WriteRegByte_IT( MPU9250_ADDRESS, PWR_MGMT_1, 0x80); // Write a one to bit 7 reset bit; toggle reset device
	  HAL_Delay(100);
}
//================================================================
//			CALIBRATE
//================================================================
void mpu9250_CalibrateMPU9250()
{
	int nb_mes=0;
	uint8_t Buf[14];
	int16_t ax=0, ay=0, az=0;
	int16_t gx=0, gy=0, gz=0;
	int32_t ax_acc=0, ay_acc=0, az_acc=0;
	int32_t	gx_acc=0, gy_acc=0, gz_acc=0;
	//uint8_t data[12]; // data array to hold accelerometer and gyro x, y, z, data

	for(nb_mes=0 ; nb_mes < 100 ; nb_mes++)
	{
	i2c1_ReadRegBuffer_IT( MPU9250_ADDRESS,ACCEL_XOUT_H ,  Buf,14);
	ax=(int16_t)((int16_t)Buf[0]<<8 	| Buf[1]);
	ay=(int16_t)((int16_t)Buf[2]<<8 	| Buf[3]);
	az=(int16_t)((int16_t)Buf[4]<<8 	| Buf[5]);
	gx=(int16_t)((int16_t)Buf[8]<<8 	| Buf[9]);
	gy=(int16_t)((int16_t)Buf[10]<<8 	| Buf[11]);
	gz=(int16_t)((int16_t)Buf[12]<<8 	| Buf[13]);

	ax_acc=ax_acc+(int32_t)ax;
	ay_acc=ay_acc+(int32_t)ay;
	az_acc=az_acc+(int32_t)az;
	gx_acc=gx_acc+(int32_t)gx;
	gy_acc=gy_acc+(int32_t)gy;
	gz_acc=gz_acc+(int32_t)gz;

	HAL_Delay(20);
	}

	accel_bias_int[0]=ax_acc/100;
	accel_bias_int[1]=ay_acc/100;
	accel_bias_int[2]=az_acc/100;
	gyro_bias_int[0]=gx_acc/100;
	gyro_bias_int[1]=gy_acc/100;
	gyro_bias_int[2]=gz_acc/100;

	// NORMALIZATION AND PUSH INTO BIAS HARDWARE REGISTER --> DOESN'T WORK
	// Construct the gyro biases for push to the hardware gyro bias registers, which are reset to zero upon device startup
	/*data[0] = (-gyro_bias_int[0]/GYRO_RATIO  >> 8) 	& 0xFF; // Divide by 4 to get 32.9 LSB per deg/s to conform to expected bias input format
	data[1] = (-gyro_bias_int[0]/GYRO_RATIO )       & 0xFF; // Biases are additive, so change sign on calculated average gyro biases
	data[2] = (-gyro_bias_int[1]/GYRO_RATIO   >> 8) & 0xFF;
	data[3] = (-gyro_bias_int[1]/GYRO_RATIO )       & 0xFF;
	data[4] = (-gyro_bias_int[2]/GYRO_RATIO   >> 8) & 0xFF;
	data[5] = (-gyro_bias_int[2]/GYRO_RATIO )       & 0xFF;*/

	// Push gyro biases to hardware registers ('works' randomly)
/*	i2c1_WriteRegByte_IT(MPU9250_ADDRESS, XG_OFFSET_H, data[0]);
	i2c1_WriteRegByte_IT(MPU9250_ADDRESS, XG_OFFSET_L, data[1]);
	i2c1_WriteRegByte_IT(MPU9250_ADDRESS, YG_OFFSET_H, data[2]);
	i2c1_WriteRegByte_IT(MPU9250_ADDRESS, YG_OFFSET_L, data[3]);
	i2c1_WriteRegByte_IT(MPU9250_ADDRESS, ZG_OFFSET_H, data[4]);
	i2c1_WriteRegByte_IT(MPU9250_ADDRESS, ZG_OFFSET_L, data[5]);*/
}

//=================================================================

