/*
 * Copyright 2018 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "mgos.h"
#include "mgos_i2c.h"
#include "mgos_sht31.h"
#include "mgos_si7021.h"
#include "mgos_htu21df.h"
#include "mgos_mcp9808.h"
#include "mgos_ccs811.h"
#include "mgos_mpu9250.h"
#include "mgos_imu.h"
#include "mgos_barometer.h"
#include <fcntl.h>
#include <math.h>
#include <sys/ioctl.h>

#define I2CBUSNR    5

static void i2c_scanner(struct mgos_i2c *i2c) {
  int i;

  if (!i2c) {
    LOG(LL_ERROR, ("No global I2C bus configured"));
    return;
  }

  for (i = 0x3; i < 0x77; i++) {
    bool ret;
    ret = mgos_i2c_read(i2c, i, NULL, 0, true);
    if (ret) {
      LOG(LL_INFO, ("I2C Address 0x%02x %s", i, ret ? "true" : "false"));
    }
  }
}

bool i2c_dumpregs(struct mgos_i2c *i2c, uint8_t i2caddr);
bool i2c_dumpregs(struct mgos_i2c *i2c, uint8_t i2caddr) {
  uint16_t reg;
  int      value;

  for (reg = 0; reg < 256; reg++) {
    value = mgos_i2c_read_reg_b(i2c, i2caddr, reg);
    if (value < 0) {
      printf(" XX");
    }else {
      printf(" %02x", value);
    }
    if (reg % 16 == 15) {
      printf("\n");
    }
  }
  printf("\n");
  return true;
}

static bool do_ccs811(struct mgos_ccs811 *sensor) {
  float eco2, tvoc;

  if (!sensor) {
    return false;
  }

  eco2 = mgos_ccs811_get_eco2(sensor);
  tvoc = mgos_ccs811_get_tvoc(sensor);
  LOG(LL_INFO, ("eCO2=%.0fppm TVOC=%.0fppb", eco2, tvoc));

  return true;
}

static bool do_sht31(struct mgos_sht31 *sensor) {
  float temp, humid;

  if (!sensor) {
    return false;
  }

  temp  = mgos_sht31_getTemperature(sensor);
  humid = mgos_sht31_getHumidity(sensor);
  LOG(LL_INFO, ("temperature=%.2fC humidity=%.1f%%", temp, humid));

  return true;
}

static bool do_si7021(struct mgos_si7021 *sensor) {
  float temp, humid;

  if (!sensor) {
    return false;
  }

  temp  = mgos_si7021_getTemperature(sensor);
  humid = mgos_si7021_getHumidity(sensor);
  LOG(LL_INFO, ("temperature=%.2fC humidity=%.1f%%", temp, humid));

  return true;
}

static bool do_htu21df(struct mgos_htu21df *sensor) {
  float temp, humid;

  if (!sensor) {
    return false;
  }

  temp  = mgos_htu21df_getTemperature(sensor);
  humid = mgos_htu21df_getHumidity(sensor);
  LOG(LL_INFO, ("temperature=%.2fC humidity=%.1f%%", temp, humid));

  return true;
}

static bool do_mcp9808(struct mgos_mcp9808 *sensor) {
  float temp;

  if (!sensor) {
    return false;
  }

  temp = mgos_mcp9808_getTemperature(sensor);
  LOG(LL_INFO, ("temperature=%.2fC", temp));

  return true;
}

static bool do_mpu9250(struct mgos_mpu9250 *sensor) {
  float ax, ay, az;
  float gx, gy, gz;
  float mx, my, mz;

  if (!sensor) {
    return false;
  }

  if (mgos_mpu9250_get_accelerometer(sensor, &ax, &ay, &az)) {
    LOG(LL_INFO, ("Accel X=%.2f Y=%.2f Z=%.2f", ax, ay, az));
  }
  if (mgos_mpu9250_get_gyroscope(sensor, &gx, &gy, &gz)) {
    LOG(LL_INFO, ("Gyro  X=%.2f Y=%.2f Z=%.2f", gx, gy, gz));
  }
  if (mgos_mpu9250_get_magnetometer(sensor, &mx, &my, &mz)) {
    LOG(LL_INFO, ("Mag   X=%.2f Y=%.2f Z=%.2f", mx, my, mz));
  }
  return true;
}

static bool do_baro(struct mgos_barometer *sensor) {
  float pressure, temperature;

  if (!sensor)
    return false;

  if (!mgos_barometer_get_pressure(sensor, &pressure))
    pressure=NAN;

  if (!mgos_barometer_get_temperature(sensor, &temperature)) 
    temperature=NAN;

  LOG(LL_INFO, ("temperature=%.2fC pressure=%.0fPa", temperature, pressure));

  return true;
}

int main(int argc, char **argv, char **environ) {
  struct mgos_i2c *    i2c = NULL;
  struct mgos_si7021 * si7021 = NULL;
  struct mgos_sht31 *  sht31 = NULL;
  struct mgos_htu21df *htu21df = NULL;
  struct mgos_mcp9808 *mcp9808 = NULL;
  struct mgos_ccs811 * ccs811 = NULL;
  struct mgos_mpu9250 *mpu9250 = NULL;
  struct mgos_barometer *baro1 = NULL, *baro2 = NULL;

  if (!mgos_i2c_open(I2CBUSNR)) {
    LOG(LL_ERROR, ("Cannot open I2C bus %u", I2CBUSNR));
    return -1;
  }
  if (!(i2c = mgos_i2c_get_global())) {
    LOG(LL_ERROR, ("Cannot open I2C bus"));
    return -2;
  }

  i2c_scanner(i2c);

  /*
   * if (!(sht31 = mgos_sht31_create(i2c, 0x44)))
   * LOG(LL_ERROR, ("Cannot create SHT31 device"));
   * if (!(si7021 = mgos_si7021_create(i2c, 0x40)))
   * LOG(LL_ERROR, ("Cannot create SI7021 device"));
   * if (!(htu21df = mgos_htu21df_create(i2c, 0x40)))
   * LOG(LL_ERROR, ("Cannot create HTU21DF device"));
   * if (!(mcp9808 = mgos_mcp9808_create(i2c, 0x18)))
   * LOG(LL_ERROR, ("Cannot create MCP9808 device"));
   * if (!(ccs811 = mgos_ccs811_create(i2c, 0x5A)))
   * LOG(LL_ERROR, ("Cannot create CCS811 device"));
   */

  /*
  if (!(mpu9250 = mgos_mpu9250_create(i2c, 0x68))) {
    LOG(LL_ERROR, ("Cannot create MPU9250 device"));
  } else {
    mgos_mpu9250_set_accelerometer_range(mpu9250, RANGE_2G);
    mgos_mpu9250_set_gyroscope_range(mpu9250, RANGE_GYRO_250);
    mgos_mpu9250_set_magnetometer_scale(mpu9250, SCALE_14_BITS);
    mgos_mpu9250_set_magnetometer_speed(mpu9250, MAG_100_HZ);
  }
  */
  if (!(baro1=mgos_barometer_create_i2c(i2c, 0x60, BARO_MPL3115))) {
    LOG(LL_ERROR, ("Cannot create barometer"));
  } else {
    mgos_barometer_set_cache_ttl(baro1, 1000);
  }

  if (!(baro2=mgos_barometer_create_i2c(i2c, 0x76, BARO_BME280))) {
    LOG(LL_ERROR, ("Cannot create barometer"));
  } else {
    mgos_barometer_set_cache_ttl(baro2, 1000);
  }

  for (;;) {
    do_sht31(sht31);
    do_si7021(si7021);
    do_htu21df(htu21df);
    do_mcp9808(mcp9808);
    do_ccs811(ccs811);
    do_mpu9250(mpu9250);
    do_baro(baro1);
    do_baro(baro2);
    sleep(1);
  }

  mgos_sht31_destroy(&sht31);
  mgos_si7021_destroy(&si7021);
  mgos_htu21df_destroy(&htu21df);
  mgos_mcp9808_destroy(&mcp9808);
  mgos_ccs811_destroy(&ccs811);
  mgos_mpu9250_destroy(&mpu9250);
  mgos_barometer_destroy(&baro1);
  mgos_barometer_destroy(&baro2);

  return 0;
  (void)argc;
  (void)argv;
  (void)environ;
}
