#include "stm8s.h"
#include "sensor.h"
#include "i2c.h"
#include "delay.h"

/* Defines */
#define AHT_I2C_ADDR    0x38

#define CMD_GET_STATUS  0x71
#define CMD_INIT        0xbe
#define CMD_MEASURE     0xac
#define CMD_MEASURE_CTL 0x33
#define CMD_MEASURE_NOP 0x00
#define CMD_SRESET      0xba
#define CMD_CALIBR1     0x1b
#define CMD_CALIBR2     0x1c
#define CMD_CALIBR3     0x1e

#define STATUS_BUSY 0x80
#define STATUS_CMD  0x40
#define STATUS_CYC  0x20
#define STATUS_CAL  0x08
#define STATUS_CALB 0x18

/* Functions prototypes */
static uint8_t Calc_CRC8(uint8_t *message, uint8_t Num);
static aht20_st_t JH_Reset_REG(uint8_t addr);

/**
 * Initialization
 */
aht20_st_t AHT20_Init(void)
{
  uint8_t buf[2];

  // Just powered on, it takes time for the product chip to be ready internally,
  // the delay is 100~500ms, and 500ms is recommended
  Delay(500);

  // When power on, send 0x71 to read the status word for the first time,
  // and judge whether the status word is 0x18.
  i2c_start();
  buf[0] = CMD_GET_STATUS;
  if (! i2c_send(AHT_I2C_ADDR, 1, buf)) {
    return AHT_St_Err;
  }

  /* get one byte */
  if (! i2c_request(AHT_I2C_ADDR, 1, buf)) {
    return AHT_St_Err;
  }

  if ((buf[0] & STATUS_CALB) != STATUS_CALB) {
    //reinitialize registers
    aht20_st_t rest;
    rest = JH_Reset_REG(0x1b);
    if (rest != AHT_St_OK) {
      return AHT_St_Err;
    }
    rest = JH_Reset_REG(0x1c);
    if (rest != AHT_St_OK) {
      return AHT_St_Err;
    }
    rest = JH_Reset_REG(0x1e);
    if (rest != AHT_St_OK) {
      return AHT_St_Err;
    }

    Delay(1);
  }

  return AHT_St_OK;
}

aht20_st_t AHT20_SoftReset(void)
{
  uint8_t buf[2];
  i2c_start();

  buf[0] = CMD_SRESET;
  if (! i2c_send(AHT_I2C_ADDR, 1, buf)) {
    return AHT_St_Err;
  }
  i2c_stop();

  return AHT_St_OK;
}

aht20_st_t AHT20_StartMeasure(void)
{
  uint8_t buf[4];
  i2c_start();

  buf[0] = CMD_MEASURE;
  buf[1] = CMD_MEASURE_CTL;
  buf[2] = CMD_MEASURE_NOP;
  if (! i2c_send(AHT_I2C_ADDR, 3, buf)) {
    return AHT_St_Err;
  }
  i2c_stop();

  return AHT_St_OK;
}

aht20_st_t AHT20_GetData(aht20_t * data)
{
  i2c_start();

  /* Now read 7 bytes of data */
  uint8_t buf[8];
  if (! i2c_request(AHT_I2C_ADDR, 7, buf)) {
    return AHT_St_Err;
  }

  if ((buf[0] & STATUS_BUSY) != 0) {
    return AHT_St_Bsy;
  }

  /* Calculate values */
  uint32_t result;

  /* Humidity = Srh * 100% / 2^20 */
  result = buf[1];
  result <<= 8;
  result |= buf[2];
  result <<= 8;
  result |= buf[3];
  result >>= 4;
  result *= 1000;
  result += 524288;
  result /= 256;
  result /= 256;
  result /= 16;
  data->Humidity = (uint16_t)result;

  /* Temperature = St * 200 / 2^20 - 50 */
  result = buf[3] & 0xf;
  result <<= 8;
  result |= buf[4];
  result <<= 8;
  result |= buf[5];
  result *= 2000;
  result += 524288;
  result /= 256;
  result /= 256;
  result /= 16;
  data->Temperature = (int16_t)(result - 500);

  return AHT_St_OK;
}

/**
 * CRC check type: CRC8/MAXIM
 * Polynomial: X8+X5+X4+1
 * Poly: 0011 0001 0x31
 * When the high bit is placed in the back, it becomes 1000 1100 0x8c
 */
static uint8_t Calc_CRC8(uint8_t *message, uint8_t Num)
{
  uint8_t i;
  uint8_t byte;
  uint8_t crc = 0xFF;

  for (byte=0; byte<Num; byte++) {
    crc ^= (message[byte]);
    for (i=8; i>0; --i) {
      if (crc & 0x80) {
        crc = (crc << 1) ^ 0x31;
      } else {
        crc = (crc << 1);
      }
    }
  }

  return crc;
}

/* Reset register */
static aht20_st_t JH_Reset_REG(uint8_t addr) {
  uint8_t buf[4];

  i2c_start();
  buf[0] = addr;
  buf[1] = 0;
  buf[2] = 0;
  if (! i2c_send(AHT_I2C_ADDR, 3, buf)) {
    return AHT_St_Err;
  }
  i2c_stop();

  Delay(5); //Delay about 5ms
  i2c_start();
  if (! i2c_request(AHT_I2C_ADDR, 3, buf)) {
    return AHT_St_Err;
  }

  Delay(10); //Delay about 10ms
  i2c_start();
  buf[0] = (0xB0|addr);
  if (! i2c_send(AHT_I2C_ADDR, 3, buf)) {
    return AHT_St_Err;
  }
  i2c_stop();

  return AHT_St_OK;
}
