/* bme280.c - Driver for Bosch BME280 temperature and pressure sensor */

/*
 * Copyright (c) 2016, 2017 Intel Corporation
 * Copyright (c) 2017 IpTronix S.r.l.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <kernel.h>
#include <drivers/sensor.h>
#include <init.h>
#include <drivers/gpio.h>
#include <drivers/i2c.h>
#include <drivers/spi.h>
#include <sys/byteorder.h>
#include <sys/__assert.h>

#include <logging/log.h>

#include "bme280.h"
#include <zephyr.h>
#include <math.h>

#define DT_DRV_COMPAT bosch_bme280

#define BME280_BUS_SPI DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
#define BME280_BUS_I2C DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)

LOG_MODULE_REGISTER(BME280, CONFIG_SENSOR_LOG_LEVEL);

#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0
#warning "BME280 driver enabled without any devices"
#endif
const struct device *dev1;
/*
 * This driver is an example of why devices should be resolvable at
 * link time instead of only at runtime via device_get_binding().
 *
 * We only need to store 'bus' and 'spi_cs' in RAM because we can't
 * resolve devices at link time. They should be moved to ROM if that
 * becomes possible. That would in turn enable several further
 * cleanups.
 */

struct bme280_spi_cfg {
	struct spi_config spi_cfg;
	const char *cs_gpios_label;
};

union bme280_bus_config {
#if BME280_BUS_SPI
	const struct bme280_spi_cfg *spi_cfg;
#endif
#if BME280_BUS_I2C
	uint16_t i2c_addr;
#endif
};

struct bme280_config {
	const char *bus_label;
	const struct bme280_reg_io *reg_io;
	const union bme280_bus_config bus_config;
};

typedef int (*bme280_reg_read_fn)(const struct device *bus,
				  const union bme280_bus_config *bus_config,
				  uint8_t start, uint8_t *buf, int size);
typedef int (*bme280_reg_write_fn)(const struct device *bus,
				   const union bme280_bus_config *bus_config,
				   uint8_t reg, uint8_t val);

struct bme280_reg_io {
	bme280_reg_read_fn read;
	bme280_reg_write_fn write;
};

static inline struct bme280_data *to_data(const struct device *dev)
{
	return dev->data;
}

static inline const struct bme280_config *to_config(const struct device *dev)
{
	return dev->config;
}

static inline const struct device *to_bus(const struct device *dev)
{
	return to_data(dev)->bus;
}

static inline const union bme280_bus_config *to_bus_config(const struct device *dev)
{
	return &to_config(dev)->bus_config;
}

#if BME280_BUS_SPI
static inline const struct spi_config *
to_spi_config(const union bme280_bus_config *bus_config)
{
	return &bus_config->spi_cfg->spi_cfg;
}

static int bme280_reg_read_spi(const struct device *bus,
			       const union bme280_bus_config *bus_config,
			       uint8_t start, uint8_t *buf, int size)
{
	uint8_t addr;
	const struct spi_buf tx_buf = {
		.buf = &addr,
		.len = 1
	};
	const struct spi_buf_set tx = {
		.buffers = &tx_buf,
		.count = 1
	};
	struct spi_buf rx_buf[2];
	const struct spi_buf_set rx = {
		.buffers = rx_buf,
		.count = 2
	};
	int i;

	rx_buf[0].buf = NULL;
	rx_buf[0].len = 1;

	rx_buf[1].len = 1;

	for (i = 0; i < size; i++) {
		int ret;

		addr = (start + i) | 0x80;
		rx_buf[1].buf = &buf[i];

		ret = spi_transceive(bus, to_spi_config(bus_config), &tx, &rx);
		if (ret) {
			LOG_DBG("spi_transceive FAIL %d\n", ret);
			return ret;
		}
	}

	return 0;
}

static int bme280_reg_write_spi(const struct device *bus,
				const union bme280_bus_config *bus_config,
				uint8_t reg, uint8_t val)
{
	uint8_t cmd[2] = { reg & 0x7F, val };
	const struct spi_buf tx_buf = {
		.buf = cmd,
		.len = 2
	};
	const struct spi_buf_set tx = {
		.buffers = &tx_buf,
		.count = 1
	};
	int ret;

	ret = spi_write(bus, to_spi_config(bus_config), &tx);
	if (ret) {
		LOG_DBG("spi_write FAIL %d\n", ret);
		return ret;
	}
	return 0;
}

static const struct bme280_reg_io bme280_reg_io_spi = {
	.read = bme280_reg_read_spi,
	.write = bme280_reg_write_spi,
};
#endif /* BME280_BUS_SPI */

#if BME280_BUS_I2C
static int bme280_reg_read_i2c(const struct device *bus,
			       const union bme280_bus_config *bus_config,
			       uint8_t start, uint8_t *buf, int size)
{
	return i2c_burst_read(bus, bus_config->i2c_addr,start, buf, size);

                              //return i2c_read(bus,buf, size, bus_config->i2c_addr);

}

static int bme280_reg_write_i2c(const struct device *bus,
				const union bme280_bus_config *bus_config,
				uint8_t reg, uint8_t val)
{
	return i2c_reg_write_byte(bus, bus_config->i2c_addr,
				  reg, val);
}

static const struct bme280_reg_io bme280_reg_io_i2c = {
	.read = bme280_reg_read_i2c,
	.write = bme280_reg_write_i2c,
};
#endif /* BME280_BUS_I2C */

static inline int bme280_reg_read(const struct device *dev,
				  uint8_t start, uint8_t *buf, int size)
{
	return to_config(dev)->reg_io->read(to_bus(dev), to_bus_config(dev),
					    start, buf, size);
}

static inline int bme280_reg_write(const struct device *dev, uint8_t reg,
				   uint8_t val)
{
        printf("ADDR = %X\n",reg);
	return to_config(dev)->reg_io->write(to_bus(dev), to_bus_config(dev),
					     reg, val);
}



/* * @brief This internal API is used to compensate the raw temperature data and
 * return the compensated temperature data in double data type.
 */
/*##########################################################################################################################*/
/*##########################################################################################################################*/

double bmp3_pow(double base, uint8_t power)
{
  double pow_output = 1;

  while (power != 0) {
    pow_output = base * pow_output;
    power--;
  }

  return pow_output;
}


int8_t set_config()
{
    int8_t rslt;
    /* Used to select the settings user needs to change */
    uint16_t settings_sel;

    /* Select the pressure and temperature sensor to be enabled */
    devv.settings.press_en = BMP3_ENABLE;
    devv.settings.temp_en = BMP3_ENABLE;
    /* Select the output data rate and oversampling settings for pressure and temperature */
    devv.settings.odr_filter.press_os = BMP3_NO_OVERSAMPLING;
    devv.settings.odr_filter.temp_os = BMP3_NO_OVERSAMPLING;
    devv.settings.odr_filter.odr = BMP3_ODR_200_HZ;
    /* Assign the settings which needs to be set in the sensor */
    settings_sel = BMP3_PRESS_EN_SEL | BMP3_TEMP_EN_SEL | BMP3_PRESS_OS_SEL | BMP3_TEMP_OS_SEL | BMP3_ODR_SEL;
    rslt = bmp3_set_sensor_settings(settings_sel);

    /* Set the power mode to normal mode */
    devv.settings.op_mode = BMP3_NORMAL_MODE;
    rslt = bmp3_set_op_mode();

    return rslt;
}

float readTemperature(){
  uint8_t sensor_comp;
  sensor_comp = BMP3_TEMP;
  struct bmp3_data data12;
  bmp3_get_sensor_data(sensor_comp, &data12);
  printf("Read Temperature = %f\n",data12.temperature);
  return data12.temperature;
}

float readPressure(){
  uint8_t sensor_comp;
  sensor_comp = BMP3_PRESS;
  struct bmp3_data data12;
  bmp3_get_sensor_data(sensor_comp, &data12);
  printf("Read Pressure = %f\n",data12.pressure);
  return data12.pressure;
}

/*!
 * @brief This API reads the data from the given register address of the sensor.
 */
int8_t bmp3_get_regs(const struct device *dev, uint8_t reg_addr, uint8_t *reg_data, uint16_t len)
{
    int err;
    //devv.read(devv.devv_id, reg_addr, reg_data, len);
    //printk("Entered Get Regs\n");
    uint16_t temp_len = len +1;
  uint16_t i;
  uint8_t temp_buff[len + 1];
  //-----SPI-----
  if (devv.intf == BMP3_SPI_INTF) {
    reg_addr = reg_addr | 0x80;
    //dev.read(dev.dev_id, reg_addr, temp_buff, temp_len);
    err = bme280_reg_read(dev1, reg_addr, temp_buff, temp_len);
    for (i = 0; i < len; i++){
      reg_data[i] = temp_buff[i + 1];
    }
  }
  //-----I2C-----
  else if(devv.intf == BMP3_I2C_INTF){
    //dev.read(dev.dev_id, reg_addr, reg_data, len);
    err = bme280_reg_read(dev1, reg_addr, reg_data, len);
  }
  return 0;
    //printk("Register Reading ;length = %d, Register = %X, Reg Data = %d\n",len,reg_addr,reg_data);
    //int ar_len = sizeof(reg_data)/sizeof(reg_data[0]);
    //for(int i;i<ar_len;i++){
    //    printk("%d",reg_data[i]);
    //}  
    //printk("\n");
    //for(int i;i<=ar_len;i++){
    //    printk("%d",reg_data[i]);
    //}  
    //printk("\n");

    //    for(int i;i<=ar_len;i++){
    //    printk("%x",reg_data[i]);
    //}  
    //printk("\n");
}

/*!
/*!
 * @brief This API writes the given data to the register address
 * of the sensor.
 */
int8_t bmp3_set_regs(const struct device *dev,uint8_t *reg_addr, const uint8_t *reg_data, uint8_t len)
{
  int8_t rslt;
  uint8_t temp_buff[len * 2];
  uint16_t temp_len;
  uint8_t reg_addr_cnt;

  // Check for arguments validity 
  if ((reg_addr != NULL) && (reg_data != NULL) && (len != 0)) {
    temp_buff[0] = reg_data[0];
    if (devv.intf == BMP3_SPI_INTF) {
      for (reg_addr_cnt = 0; reg_addr_cnt < len; reg_addr_cnt++)
        reg_addr[reg_addr_cnt] = reg_addr[reg_addr_cnt] & 0x7F;
    }
    //rslt = devv.write(devv.devv_id, reg_addr[0], temp_buff, len);
    rslt = bme280_reg_write(dev1, reg_addr[0], temp_buff);
  }
  return rslt;
}

/*!
 * @brief This API sets the power control(pressure enable and
 * temperature enable), over sampling, odr and filter
 * settings in the sensor.
 */
int8_t bmp3_set_sensor_settings(uint32_t desired_settings)
{
  int8_t rslt;
  if (POWER_CNTL&desired_settings) {
    /* Set the power control settings */
    rslt = set_pwr_ctrl_settings(desired_settings);
  }
  return rslt;
}

/*!
 * @brief This API performs the soft reset of the sensor.
 */
int8_t reset(const struct device *dev)
{
  int8_t rslt;
  uint8_t reg_addr = BMP3_CMD_ADDR;
  /* 0xB6 is the soft reset command */
  uint8_t soft_rst_cmd = 0xB6;
  uint8_t cmd_rdy_status;
  uint8_t cmd_err_status;

  /* Check for command ready status */
  //DBG();
  rslt = bmp3_get_regs(dev1,BMP3_SENS_STATUS_REG_ADDR, &cmd_rdy_status, 1);
  /* devvice is ready to accept new command */
  if ((cmd_rdy_status & BMP3_CMD_RDY) && (rslt == BMP3_OK)) {
    /* Write the soft reset command in the sensor */
    printf("Writing soft reset commands = REgister = %X, Value = %X\n",reg_addr,soft_rst_cmd);
    rslt = bmp3_set_regs(dev1,&reg_addr, &soft_rst_cmd, 1);
    /* Proceed if everything is fine until now */
//    DBG();
    if (rslt == BMP3_OK) {
      /* Wait for 2 ms */
      K_MSEC(2);
      //devv.delay_ms(2);
      /* Read for command error status */
      rslt = bmp3_get_regs(dev1,BMP3_ERR_REG_ADDR, &cmd_err_status, 1);
      /* check for command error status */
      if ((cmd_err_status & BMP3_CMD_ERR) || (rslt != BMP3_OK)) {
        /* Command not written hence return
           error */
           printf("Command not written\n");
        rslt = BMP3_E_CMD_EXEC_FAILED;
      }
    }
  } else {
    rslt = BMP3_E_CMD_EXEC_FAILED;
  }
  return rslt;
}


/*!
 * @brief This API sets the power mode of the sensor.
 */
int8_t bmp3_set_op_mode()
{
  int8_t rslt;
  //rslt = write_power_mode();
  return rslt;
}
/*!
 * @brief This internal API writes the power mode in the sensor.
 */

/*!
 * @brief This API reads the pressure, temperature or both data from the
 * sensor, compensates the data and store it in the bmp3_data structure
 * instance passed by the user.
 */

int8_t bmp3_get_sensor_data(uint8_t sensor_comp, struct bmp3_data *comp_data)
{
  int8_t rslt;
  /* Array to store the pressure and temperature data read from
  the sensor */
  uint8_t reg_data[BMP3_P_T_DATA_LEN] = {0};
  struct bmp3_uncomp_data uncomp_data = {0};
  //int arr_len = sizeof(reg_data)/sizeof(reg_data[0]);
  //for (int i;i<=arr_len;i++){
  //  printf("Calib %d = %d\n",i,reg_data[i]);
  //}
  if ((comp_data != NULL)) {
    /* Read the pressure and temperature data from the sensor */
    //DBG();
    rslt = bmp3_get_regs(dev1,BMP3_DATA_ADDR, reg_data, BMP3_P_T_DATA_LEN);
      //    printk("Uncompensated Data\n");
      //int ar_len = sizeof(reg_data)/sizeof(reg_data[0]);
      //for(int i;i<=ar_len;i++){
      //  printk("%d",reg_data[i]);
      //}  
    if (rslt == BMP3_OK) {
      /* Parse the read data from the sensor */
      parse_sensor_data(reg_data, &uncomp_data);
      /* Compensate the pressure/temperature/both data read
         from the sensor */
      rslt = compensate_data(sensor_comp, &uncomp_data, comp_data, &devv.calib_data);
    }
  } else {
    rslt = BMP3_E_NULL_PTR;
  }

  return rslt;
}


int8_t write_power_mode()
{
  int8_t rslt;
  uint8_t reg_addr = BMP3_PWR_CTRL_ADDR;
  uint8_t op_mode = devv.settings.op_mode;
  /* Temporary variable to store the value read from op-mode register */
  uint8_t op_mode_reg_val;

  /* Read the power mode register */
  //DBG();
  rslt = bmp3_get_regs(dev1,reg_addr, &op_mode_reg_val, 1);
  /* Set the power mode */
  if (rslt == BMP3_OK) {
    op_mode_reg_val = BMP3_SET_BITS(op_mode_reg_val, BMP3_OP_MODE, op_mode);
    op_mode_reg_val = 51;
    /* Write the power mode in the register */
    printf("Write Power Mode Writing = %X to addr = %X\n",op_mode_reg_val,reg_addr);
    rslt = bmp3_set_regs(dev1,&reg_addr, &op_mode_reg_val, 1);
    printf("Write Power Mode Writing = %X to addr = %X\n",op_mode_reg_val,reg_addr);
    
  }

  return rslt;
}

/* * @brief This API sets the pressure enable and temperature enable
 * settings of the sensor.
 */
/*!
 * @brief This internal API reads the calibration data from the sensor, parse
 * it then compensates it and store in the devvice structure.
 */
int8_t get_calib_data(const struct device *dev)
{
  int8_t rslt;
  uint8_t reg_addr = BMP3_CALIB_DATA_ADDR;
  /* Array to store calibration data */
  uint8_t calib_data[BMP3_CALIB_DATA_LEN] = {0};
  
  /* Read the calibration data from the sensor */
  //DBG();
  rslt = bmp3_get_regs(dev,reg_addr, calib_data, BMP3_CALIB_DATA_LEN);
  /* Parse calibration data and store it in devvice structure */
  parse_calib_data(calib_data);
  int arr_len = sizeof(calib_data)/sizeof(calib_data[0]);
  //for (int i;i<=arr_len;i++){
  //  printf("Calib %d = %d\n",i,calib_data[i]);
  //}
  return rslt;
}


int8_t set_pwr_ctrl_settings(uint32_t desired_settings)
{
  int8_t rslt;
  uint8_t reg_addr = BMP3_PWR_CTRL_ADDR;
  uint8_t reg_data;
  //DBG();
  rslt = bmp3_get_regs(dev1,reg_addr, &reg_data, 1);
  if (rslt == BMP3_OK) {
    if (desired_settings & BMP3_PRESS_EN_SEL) {
      /* Set the pressure enable settings in the
      register variable */
      reg_data = BMP3_SET_BITS_POS_0(reg_data, BMP3_PRESS_EN, devv.settings.press_en);
      printf("Inside PWR ctrl111 = %d\n",reg_data);
    }
    if (desired_settings & BMP3_TEMP_EN_SEL) {
      /* Set the temperature enable settings in the
      register variable */
      reg_data = BMP3_SET_BITS(reg_data, BMP3_TEMP_EN, devv.settings.temp_en);
      printf("Inside PWR ctrl = %d\n",reg_data);
    }
    /* Write the power control settings in the register */
    reg_data = 51;
    printf("PWR Control Settings WRITING Return = %d, Writed =%d to REG = %X\n",rslt,reg_data,reg_addr);
    rslt = bmp3_set_regs(dev1,&reg_addr, &reg_data, 1);
    
    //rslt = bme280_reg_read(dev, BME280_REG_COMP_START,
			 //     op_, sizeof(buf));
  }

  return rslt;
}

/*!
 *  @brief This internal API is used to parse the pressure or temperature or
 *  both the data and store it in the bmp3_uncomp_data structure instance.
 */
void parse_sensor_data(const uint8_t *reg_data, struct bmp3_uncomp_data *uncomp_data)
{
  /* Temporary variables to store the sensor data */
  uint32_t data_xlsb;
  uint32_t data_lsb;
  uint32_t data_msb;

  /* Store the parsed register values for pressure data */
  data_xlsb = (uint32_t)reg_data[0];
  data_lsb = (uint32_t)reg_data[1] << 8;
  data_msb = (uint32_t)reg_data[2] << 16;
  uncomp_data->pressure = data_msb | data_lsb | data_xlsb;
  //printf("Parse Sensor Data\n");
  //uncomp_data->pressure  = reg_data[2]&reg_data[1]&reg_data[0];
  //uncomp_data->temperature = reg_data[5]&reg_data[4]&reg_data[3];
  //uncomp_data->temperature = (reg_data[5] << 16) | (reg_data[4] << 8) | (reg_data[3]);
  //Serial.println(uncomp_data->pressure);
  /* Store the parsed register values for temperature data */
  data_xlsb = (uint32_t)reg_data[3];
  data_lsb = (uint32_t)reg_data[4] << 8;
  data_msb = (uint32_t)reg_data[5] << 16;
  uncomp_data->temperature = data_msb | data_lsb | data_xlsb;

  //Serial.println(uncomp_data->temperature);
}

/*!
 * @brief This internal API is used to compensate the pressure or temperature
 * or both the data according to the component selected by the user.
 */
int8_t compensate_data(uint8_t sensor_comp, const struct bmp3_uncomp_data *uncomp_data,
             struct bmp3_data *comp_data, struct bmp3_calib_data *calib_data)
{
  int8_t rslt = BMP3_OK;

  if ((uncomp_data != NULL) && (comp_data != NULL) && (calib_data != NULL)) {
    /* If pressure or temperature component is selected */
    if (sensor_comp & (BMP3_PRESS | BMP3_TEMP)) {
      /* Compensate the temperature data */
      comp_data->temperature = compensate_temperature(uncomp_data, calib_data);
    }
    if (sensor_comp & BMP3_PRESS) {
      /* Compensate the pressure data */
      comp_data->pressure = compensate_pressure(uncomp_data, calib_data);
    }
  } else {
    rslt = BMP3_E_NULL_PTR;
  }

  return rslt;
}
/*##########################################################################################################################*/
/*##########################################################################################################################*/


/*$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$*/
/*!
 *  @brief This internal API is used to parse the calibration data, compensates
 *  it and store it in devvice structure
 */
void parse_calib_data(const uint8_t *reg_data)
{
  /* Temporary variable to store the aligned trim data */
  struct bmp3_reg_calib_data *reg_calib_data = &devv.calib_data.reg_calib_data;
  struct bmp3_quantized_calib_data *quantized_calib_data = &devv.calib_data.quantized_calib_data;
  /* Temporary variable */
  double temp_var;

  /* 1 / 2^8 */
  temp_var = 0.00390625f;
  reg_calib_data->par_t1 = BMP3_CONCAT_BYTES(reg_data[1], reg_data[0]);
  quantized_calib_data->par_t1 = ((double)reg_calib_data->par_t1 / temp_var);

  reg_calib_data->par_t2 = BMP3_CONCAT_BYTES(reg_data[3], reg_data[2]);
  temp_var = 1073741824.0f;
  quantized_calib_data->par_t2 = ((double)reg_calib_data->par_t2 / temp_var);

  reg_calib_data->par_t3 = (int8_t)reg_data[4];
  temp_var = 281474976710656.0f;
  quantized_calib_data->par_t3 = ((double)reg_calib_data->par_t3 / temp_var);

  reg_calib_data->par_p1 = (int16_t)BMP3_CONCAT_BYTES(reg_data[6], reg_data[5]);

  temp_var = 1048576.0f;
  quantized_calib_data->par_p1 = ((double)(reg_calib_data->par_p1 - (16384)) / temp_var);

  reg_calib_data->par_p2 = (int16_t)BMP3_CONCAT_BYTES(reg_data[8], reg_data[7]);
  temp_var = 536870912.0f;
  quantized_calib_data->par_p2 = ((double)(reg_calib_data->par_p2 - (16384)) / temp_var);

  reg_calib_data->par_p3 = (int8_t)reg_data[9];
  temp_var = 4294967296.0f;
  quantized_calib_data->par_p3 = ((double)reg_calib_data->par_p3 / temp_var);

  reg_calib_data->par_p4 = (int8_t)reg_data[10];
  temp_var = 137438953472.0f;
  quantized_calib_data->par_p4 = ((double)reg_calib_data->par_p4 / temp_var);

  reg_calib_data->par_p5 = BMP3_CONCAT_BYTES(reg_data[12], reg_data[11]);
  /* 1 / 2^3 */
  temp_var = 0.125f;
  quantized_calib_data->par_p5 = ((double)reg_calib_data->par_p5 / temp_var);

  reg_calib_data->par_p6 = BMP3_CONCAT_BYTES(reg_data[14],  reg_data[13]);
  temp_var = 64.0f;
  quantized_calib_data->par_p6 = ((double)reg_calib_data->par_p6 / temp_var);

  reg_calib_data->par_p7 = (int8_t)reg_data[15];
  temp_var = 256.0f;
  quantized_calib_data->par_p7 = ((double)reg_calib_data->par_p7 / temp_var);

  reg_calib_data->par_p8 = (int8_t)reg_data[16];
  temp_var = 32768.0f;
  quantized_calib_data->par_p8 = ((double)reg_calib_data->par_p8 / temp_var);

  reg_calib_data->par_p9 = (int16_t)BMP3_CONCAT_BYTES(reg_data[18], reg_data[17]);
  temp_var = 281474976710656.0f;
  quantized_calib_data->par_p9 = ((double)reg_calib_data->par_p9 / temp_var);

  reg_calib_data->par_p10 = (int8_t)reg_data[19];
  temp_var = 281474976710656.0f;
  quantized_calib_data->par_p10 = ((double)reg_calib_data->par_p10 / temp_var);

  reg_calib_data->par_p11 = (int8_t)reg_data[20];
  temp_var = 36893488147419103232.0f;
  quantized_calib_data->par_p11 = ((double)reg_calib_data->par_p11 / temp_var);
}

/*!
 * @brief This internal API is used to compensate the raw temperature data and
 * return the compensated temperature data in double data type.
 */
double compensate_temperature(const struct bmp3_uncomp_data *uncomp_data,
            struct bmp3_calib_data *calib_data)
{
  //printf("Compensate Temperature &&&&&&&&&&&&&&&&&&&&&\n");
  uint32_t uncomp_temp = uncomp_data->temperature;
  double partial_data1;
  double partial_data2;

  partial_data1 = (double)(uncomp_temp - calib_data->quantized_calib_data.par_t1);
  partial_data1 = (double)(uncomp_temp - calib_data->quantized_calib_data.par_t1);
  partial_data2 = (double)(partial_data1 * calib_data->quantized_calib_data.par_t2);
  /* Update the compensated temperature in calib structure since this is
     needed for pressure calculation */
  calib_data->quantized_calib_data.t_lin = partial_data2 + (partial_data1 * partial_data1)
              * calib_data->quantized_calib_data.par_t3;

  /* Return compensated temperature */
  return calib_data->quantized_calib_data.t_lin;
}

/*!
 * @brief This internal API is used to compensate the raw pressure data and
 * return the compensated pressure data in double data type.
 */

double compensate_pressure(const struct bmp3_uncomp_data *uncomp_data,
          const struct bmp3_calib_data *calib_data)
{
  const struct bmp3_quantized_calib_data *quantized_calib_data = &calib_data->quantized_calib_data;
  /* Variable to store the compensated pressure */
  double comp_press;
  /* Temporary variables used for compensation */
  double partial_data1;
  double partial_data2;
  double partial_data3;
  double partial_data4;
  double partial_out1;
  double partial_out2;
  
  partial_data1 = quantized_calib_data->par_p6 * quantized_calib_data->t_lin;
  partial_data2 = quantized_calib_data->par_p7 * bmp3_pow(quantized_calib_data->t_lin, 2);
  partial_data3 = quantized_calib_data->par_p8 * bmp3_pow(quantized_calib_data->t_lin, 3);
  partial_out1 = quantized_calib_data->par_p5 + partial_data1 + partial_data2 + partial_data3;
  
  
  partial_data1 = quantized_calib_data->par_p2 * quantized_calib_data->t_lin;
  partial_data2 = quantized_calib_data->par_p3 * bmp3_pow(quantized_calib_data->t_lin, 2);
  partial_data3 = quantized_calib_data->par_p4 * bmp3_pow(quantized_calib_data->t_lin, 3);
  partial_out2 = uncomp_data->pressure *
      (quantized_calib_data->par_p1 + partial_data1 + partial_data2 + partial_data3);
      
  
  
  partial_data1 = bmp3_pow((double)uncomp_data->pressure, 2);
  partial_data2 = quantized_calib_data->par_p9 + quantized_calib_data->par_p10 * quantized_calib_data->t_lin;
  partial_data3 = partial_data1 * partial_data2;
  partial_data4 = partial_data3 + bmp3_pow((double)uncomp_data->pressure, 3) * quantized_calib_data->par_p11;
  comp_press = partial_out1 + partial_out2 + partial_data4;
  return comp_press;
}
/*$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$*/
/*$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$*/
//float pow(float x, float y){

//}
//double pow(double x, double n){
//  double ret = x;
//  int i;
//  if(n){
//    for(i=0;i<n-1;i++){
//      ret = x*ret;
//    }
//  }
//  else{
//    ret = 1;
//  }
//  return ret;
//}

uint8_t * readRaw(int check){
    int8_t rslt;
    uint8_t reg_data[BMP3_P_T_DATA_LEN] = {0};
    struct bmp3_uncomp_data uncomp_data = {0};
    rslt = bmp3_get_regs(dev1,BMP3_DATA_ADDR, reg_data, BMP3_P_T_DATA_LEN);
    parse_sensor_data(reg_data, &uncomp_data);
    printf("Raw Reading --------------------- \n");
    if(check == 0){
    return uncomp_data.temperature;
    }
    else if(check == 1){
        return uncomp_data.pressure;
    }
    else{
        return reg_data;
    }
}
float  readRaw1(int check){
    int8_t rslt;
    uint8_t reg_data[BMP3_P_T_DATA_LEN] = {0};
    struct bmp3_uncomp_data uncomp_data = {0};
    rslt = bmp3_get_regs(dev1,BMP3_DATA_ADDR, reg_data, BMP3_P_T_DATA_LEN);
    parse_sensor_data(reg_data, &uncomp_data);
    printf("Raw Reading --------------------- \n");
    if(check == 0){
    return uncomp_data.temperature;
    }
    else {
        return uncomp_data.pressure;
    }
}

float readCalibratedAltitude(float seaLevel)
{
  float pressure = readPressure();
  return (1.0 - pow((float)pressure / seaLevel, 0.190284))* 287.15 / 0.0065;
}

float readSeaLevel(float altitude)
{
  float pressure = readPressure();
  printk("Pressure while sealevel = %d\n",pressure);
  return (pressure / pow(1.0 - (altitude / 44330.0), 5.255));
}

float readAltitude(void)
{
  float pressure = readPressure();
  return (1.0 - pow((float)pressure / 101325, 0.190284)) * 287.15 / 0.0065;
}

void INTEnable(){
  uint8_t reg_data = 0x40;
  uint8_t reg_addr = BMP3_INT_CTRL_ADDR;
  bmp3_set_regs(dev1,&reg_addr, &reg_data, 1);
}
/*$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$*/
/*$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$*/
/*$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$*/
float sealevel;

static int bme280_sample_fetch(const struct device *dev,
			       enum sensor_channel chan)
{
	struct bme280_data *data = to_data(dev);
	uint8_t buf[6] = {0};
        //struct bmp3_uncomp_data uncomp_data = {0};

	int32_t adc_press, adc_temp, adc_humidity;
	int size = 6;
	int ret;

	__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);

#ifdef CONFIG_BME280_MODE_FORCED
	ret = bme280_reg_write(dev, BME280_REG_CTRL_MEAS, BME280_CTRL_MEAS_VAL);
	if (ret < 0) {
		return ret;
	}

	do {
		k_sleep(K_MSEC(3));
		ret = bme280_reg_read(dev, BME280_REG_STATUS, buf, 1);
		if (ret < 0) {
			return ret;
		}
	} while (buf[0] & 0x08);
#endif        
        data->comp_temp = readTemperature();
        //data->comp_press = readCalibratedAltitude(sealevel);
        data->comp_press = readPressure();
        int k = 2;
        float press,temp;
        if(k==0 | k==1){
          if(k == 0){
           temp = readRaw1(k);
            printf("------------------- Temperature -------------------- = %f\n",temp);
          }
          else{
          press = readRaw1(k);
          printf("------------------- Pressure -------------------- = %f\n",press);
          }
        }
        else{
        uint8_t *myarr = readRaw(k);
        printf("------------------- ARRAY --------------------\n");
        for(int i = 0; i < 6; i++)
          {
            printf("%X\n",myarr[i]);
          }
        }
        //data->comp_press = readAltitude();
	//if (data->chip_id == BME280_CHIP_ID) {
	//	size = 8;
	//}
	//ret = bme280_reg_read(dev, BME280_REG_PRESS_MSB, buf, size);
	//if (ret < 0) {
	//	return ret;
	//}
        

	return 0;
}

static int bme280_channel_get(const struct device *dev,
			      enum sensor_channel chan,
			      struct sensor_value *val)
{
	struct bme280_data *data = to_data(dev);
	switch (chan) {
	case SENSOR_CHAN_AMBIENT_TEMP:
		/*
		 * data->comp_temp has a resolution of 0.01 degC.  So
		 * 5123 equals 51.23 degC.
		 */

                        //data->comp_temp = readTemperature();

		val->val1 = data->comp_temp;
		val->val2 = data->comp_temp; //% 100.0 * 10000.0;
		break;
	case SENSOR_CHAN_PRESS:
		/*
		 * data->comp_press has 24 integer bits and 8
		 * fractional.  Output value of 24674867 represents
		 * 24674867/256 = 96386.2 Pa = 963.862 hPa
		 */
                //data->comp_press = readPressure();
		//val->val1 = (data->comp_press >> 8)/1000U;
                //data->comp_press = readCalibratedAltitude(sealevel);
                //data->comp_press = readAltitude();

                val->val1 = data->comp_press;
                //val->val2 = (data->comp_press >> 8) % 1000.0 * 1000U + (((data->comp_press & 0xff) * 1000U) >> 8);
		break;
	case SENSOR_CHAN_HUMIDITY:
		/*
		 * data->comp_humidity has 22 integer bits and 10
		 * fractional.  Output value of 47445 represents
		 * 47445/1024 = 46.333 %RH
		 */
		//val->val1 = (data->comp_humidity >> 10);
		//val->val2 = (((data->comp_humidity & 0x3ff) * 1000U * 1000U) >> 10);
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

static const struct sensor_driver_api bme280_api_funcs = {
	.sample_fetch = bme280_sample_fetch,
	.channel_get = bme280_channel_get,
};

static int bme280_read_compensation(const struct device *dev)
{
	//struct bme280_data *data = to_data(dev);
        struct bme280_data *data = to_data(dev);
	uint16_t buf[21];
	//uint8_t hbuf[7];
	int err = 0;
        //printf("Size of Bufer Data = %i\n",sizeof(buf));
	err = bme280_reg_read(dev, BME280_REG_COMP_START,
			      buf, sizeof(buf));
       
	if (err < 0) {
		LOG_DBG("COMP_START read failed: %d", err);
		return err;
	}
	return 0;
}

static int bme280_chip_init(const struct device *dev)
{
	struct bme280_data *data = to_data(dev);
	int err;

        printk("------------------ Getting Started ----------------- \n");
        printf("%x, %x, %x\n",dev->api,dev->config,dev->data);
        printf("%x, %x, %x\n",dev1->api,dev1->config,dev1->data);

	err = bme280_reg_read(dev, BME280_REG_ID, &data->chip_id, 1);
	if (err < 0) {
		LOG_DBG("ID read failed: %d", err);
		return err;
	}

	if (data->chip_id == BME280_CHIP_ID) {
		LOG_DBG("ID OK");
	}
	 else {
		LOG_DBG("bad chip id 0x%x", data->chip_id);
		return -ENOTSUP;
	}

	//err = bme280_read_compensation(dev);
	//if (err < 0) {
	//	return err;
	//}

	return 0;
}

#if BME280_BUS_SPI
static inline int bme280_is_on_spi(const struct device *dev)
{
	return to_config(dev)->reg_io == &bme280_reg_io_spi;
}

static inline int bme280_spi_init(const struct device *dev)
{
	struct bme280_data *data = to_data(dev);
	const struct bme280_spi_cfg *spi_cfg = to_bus_config(dev)->spi_cfg;

	if (spi_cfg->cs_gpios_label != NULL) {
		data->spi_cs.gpio_dev = device_get_binding(
			spi_cfg->cs_gpios_label);
		if (!data->spi_cs.gpio_dev) {
			LOG_DBG("can't get GPIO SPI CS device %s",
				spi_cfg->cs_gpios_label);
			return -ENODEV;
		}
	} else {
		LOG_DBG("no chip select set");
	}

	return 0;
}
#else
static inline int bme280_is_on_spi(const struct device *dev)
{
	return 0;
}

static inline int bme280_spi_init(const struct device *dev)
{
	return 0;
}
#endif
void set_iic_addr(uint8_t addr){
_addr = addr;
}

int bme280_init(const struct device *dev)
{
	const char *name = dev->name;
	struct bme280_data *data = to_data(dev);
	const struct bme280_config *config = to_config(dev);
	int rc;
        int *ptr=&dev1;
        *ptr = dev;
	LOG_DBG("initializing %s", name);

	data->bus = device_get_binding(config->bus_label);
	if (!data->bus) {
		LOG_DBG("bus \"%s\" not found", config->bus_label);
		rc = -EINVAL;
		goto done;
	}

	if (bme280_is_on_spi(dev)) {
		rc = bme280_spi_init(dev);
		if (rc < 0) {
			rc = -EINVAL;
			goto done;
		}
	}

	rc = bme280_chip_init(dev);
	if (rc < 0) {
		rc = -EINVAL;
		goto done;
	}

	rc = 0;

done:
	if (rc == 0) {
		LOG_DBG("%s OK", name);
	} else {
		LOG_DBG("%s failed", name);
	}
        set_iic_addr(BMP3_I2C_ADDR_PRIM);
        devv.dev_id = _addr;
        devv.intf = BMP3_I2C_INTF;

  int8_t rslt;
  uint8_t chip_id = 0;
  /* Read the chip-id of bmp3 sensor */

  devv.dev_id = _addr;
  rslt = bmp3_get_regs(dev1,BMP3_CHIP_ID_ADDR, &chip_id, 1);
  /* Proceed if everything is fine until now */

    /******************* Power Settings *******************/
    rslt = bmp3_set_regs(dev1,BMP3_PWR_CTRL_ADDR, 33, 1); // Or 33 Hex
    rslt = bmp3_set_regs(dev1,BMP3_OSR_ADDR, 0, 1); // Or 000000 Hex
    K_MSEC(5);
  if (rslt == BMP3_OK) {
    /* Check for chip id validity */
    if (chip_id == BMP3_CHIP_ID) {
      devv.chip_id = chip_id;
      /* Reset the sensor */
      rslt = reset(dev1);
      if (rslt == BMP3_OK) {
        /* Read the calibration data */
        printf("Calibrating\n");
        rslt = get_calib_data(dev1);
      }
    } else {
      rslt = BMP3_E_DEV_NOT_FOUND;
      return rslt;
    }
  }

  //set_config();

    uint8_t cmd_rdy_status;
    bmp3_get_regs(dev1,BMP3_SENS_STATUS_REG_ADDR, &cmd_rdy_status, 1);
   printf("Sensor Stataus register = %X, Value = %X\n",BMP3_SENS_STATUS_REG_ADDR,cmd_rdy_status);
//    uint8_t reg_return;
//      uint8_t reg_data;
//rslt = bmp3_get_regs(dev1,BMP3_PWR_CTRL_ADDR, &reg_data, 1);
//    printf("PWR Control Settings READ Return = %d, Register = %X, Reg_Data = %d\n",rslt,BMP3_PWR_CTRL_ADDR,reg_data);
    
//rslt = bmp3_get_regs(dev1,BMP3_PWR_CTRL_ADDR, &reg_return, 1);
//    printf("Write Power Mode Returned = %d, Register = %X, Reg data = %d\n",rslt, BMP3_PWR_CTRL_ADDR,reg_return);




        sealevel = readSeaLevel(920);
        printf("Sealevel = %f\n",sealevel);

	return rc;

}

/*
 * Device creation macro, shared by BME280_DEFINE_SPI() and
 * BME280_DEFINE_I2C().
 */

#define BME280_DEVICE_INIT(inst)					\
	DEVICE_AND_API_INIT(bme280_##inst,				\
			    DT_INST_LABEL(inst),			\
			    bme280_init,				\
			    &bme280_data_##inst,			\
			    &bme280_config_##inst,			\
			    POST_KERNEL,				\
			    CONFIG_SENSOR_INIT_PRIORITY,		\
			    &bme280_api_funcs);

/*
 * Instantiation macros used when a device is on a SPI bus.
 */

#define BME280_HAS_CS(inst) DT_INST_SPI_DEV_HAS_CS_GPIOS(inst)

#define BME280_DATA_SPI_CS(inst)					\
	{ .spi_cs = {							\
		.gpio_pin = DT_INST_SPI_DEV_CS_GPIOS_PIN(inst),		\
		.gpio_dt_flags = DT_INST_SPI_DEV_CS_GPIOS_FLAGS(inst),	\
		},							\
	}

#define BME280_DATA_SPI(inst)						\
	COND_CODE_1(BME280_HAS_CS(inst),				\
		    (BME280_DATA_SPI_CS(inst)),				\
		    ({}))

#define BME280_SPI_CS_PTR(inst)						\
	COND_CODE_1(BME280_HAS_CS(inst),				\
		    (&(bme280_data_##inst.spi_cs)),			\
		    (NULL))

#define BME280_SPI_CS_LABEL(inst)					\
	COND_CODE_1(BME280_HAS_CS(inst),				\
		    (DT_INST_SPI_DEV_CS_GPIOS_LABEL(inst)), (NULL))

#define BME280_SPI_CFG(inst)						\
	(&(struct bme280_spi_cfg) {					\
		.spi_cfg = {						\
			.frequency =					\
				DT_INST_PROP(inst, spi_max_frequency),	\
			.operation = (SPI_WORD_SET(8) |			\
				      SPI_TRANSFER_MSB |		\
				      SPI_MODE_CPOL |			\
				      SPI_MODE_CPHA),			\
			.slave = DT_INST_REG_ADDR(inst),		\
			.cs = BME280_SPI_CS_PTR(inst),			\
		},							\
		.cs_gpios_label = BME280_SPI_CS_LABEL(inst),		\
	})

#define BME280_CONFIG_SPI(inst)						\
	{								\
		.bus_label = DT_INST_BUS_LABEL(inst),			\
		.reg_io = &bme280_reg_io_spi,				\
		.bus_config = { .spi_cfg = BME280_SPI_CFG(inst)	}	\
	}

#define BME280_DEFINE_SPI(inst)						\
	static struct bme280_data bme280_data_##inst =			\
		BME280_DATA_SPI(inst);					\
	static const struct bme280_config bme280_config_##inst =	\
		BME280_CONFIG_SPI(inst);				\
	BME280_DEVICE_INIT(inst)

/*
 * Instantiation macros used when a device is on an I2C bus.
 */

#define BME280_CONFIG_I2C(inst)						\
	{								\
		.bus_label = DT_INST_BUS_LABEL(inst),			\
		.reg_io = &bme280_reg_io_i2c,				\
		.bus_config =  { .i2c_addr = DT_INST_REG_ADDR(inst), }	\
	}

#define BME280_DEFINE_I2C(inst)						\
	static struct bme280_data bme280_data_##inst;			\
	static const struct bme280_config bme280_config_##inst =	\
		BME280_CONFIG_I2C(inst);				\
	BME280_DEVICE_INIT(inst)

/*
 * Main instantiation macro. Use of COND_CODE_1() selects the right
 * bus-specific macro at preprocessor time.
 */

#define BME280_DEFINE(inst)						\
	COND_CODE_1(DT_INST_ON_BUS(inst, spi),				\
		    (BME280_DEFINE_SPI(inst)),				\
		    (BME280_DEFINE_I2C(inst)))

DT_INST_FOREACH_STATUS_OKAY(BME280_DEFINE)