#include <Wire.h>
#include <Adafruit_AHTX0.h>

#define pwmPin A0
#define get_timing (900)
#define dsp_timing (3000)
#define bkout_segment (10)

Adafruit_AHTX0 aht;

int BH1750_addr = 0x23; // @ADD = L i2cデバイス(BH7150)のAddresse
byte buff[2];

/*  微気象変数      */
signed int dsp_temp,dsp_hum;    //気温、相対湿度
float valf = 0;   //日射
float ppfd;   //ppfd換算
int dsp_ppfd;   //表示
signed int soil_moisture = 0;  //土壌水分
signed long Dsp_Co2=0;     //co2

unsigned int tmr_get_soil_moisture = 0;    //土壌水分センサー取得フラグ
unsigned int tmr_get_radiation = 0;    //日射センサー取得フラグ
unsigned int tmr_get_temp_hum = 0;    //日射センサー取得フラグ

int prevVal = LOW;

long th, tl, h, l, ppm;

char tstr[20] ;

/*    7セグ       */
unsigned int scan_no;

signed int pv_dsp = 0;    //表示する値 -99.9~999.9

int pinA = 2;
int pinB = 3;
int pinC = 4;
int pinD = 5;
int pinE = 11;
int pinF = 12;
int pinG = 13;
int pinDP = 6;

int D1 = 7;
int D2 = 9;
int D3 = 8;
int D4 = 10;

unsigned int disp_1000;
unsigned int disp_100;
unsigned int disp_10;
unsigned int disp_1;

unsigned int count_1000ms;

/*  表示    */
unsigned int flg_disp;  //表示するもの
unsigned int count_disp;  //表示カウンタ

void setup() {
  /*  割り込み    */
  TCB2.CCMP = 250;  // TOP値の設定(割り込み周期 = カウント周期(4us) * TOP値, TOP値 = 割り込み周期 / 4us)
  TCB2.CTRLB = (TCB2_CTRLB & 0b10101000) + 0b00000000;  //タイマーのGPIO出力ON、クロックソースを設定
  TCB2.CTRLA = (TCB2_CTRLA & 0b11111000) + 0b00000101;  //カウント周期を設定してカウントスタート
  TCB2.INTCTRL = 1;  //割り込み許可

  /*  CO2   */
  pinMode(pwmPin, INPUT);


  /*  照度BH1750    */
  Wire.begin(); 

  Wire.beginTransmission(BH1750_addr); // 指定したアドレスのI2Cスレーブに対して送信処理開始
  Wire.write(0x07);                    // Reset Data register
  Wire.endTransmission();              // I2Cデバイスとの送信を終了

  Wire.beginTransmission(BH1750_addr); // 指定したアドレスのI2Cスレーブに対して送信処理開始
  Wire.write(0x10);                    // H-resolution mode設定
  Wire.endTransmission();              // I2Cデバイスとの送信を終了
  
  delay(200);                          // update 120ms以上@DataSheet

  /*  温湿度AHT21   */
  aht.begin(); // AHT21の初期化

  /*  7セグ     */
  pinMode(pinA, OUTPUT);
  pinMode(pinB, OUTPUT);
  pinMode(pinC, OUTPUT);
  pinMode(pinD, OUTPUT);
  pinMode(pinE, OUTPUT);
  pinMode(pinF, OUTPUT);
  pinMode(pinG, OUTPUT);
  pinMode(D1, OUTPUT);
  pinMode(D2, OUTPUT);
  pinMode(D3, OUTPUT);
  pinMode(D4, OUTPUT);

  /*  シリアル通信    */
  Serial.begin(9600);

}


/************************************************************************/
/*      7セグ   (LOW = 光る)                                            */
/************************************************************************/
//どのセグを光らせるか
void digit1(){
  digitalWrite(D1, HIGH);
  digitalWrite(D2, LOW);
  digitalWrite(D3, LOW);
  digitalWrite(D4, LOW);
}
      
void digit2(){
  digitalWrite(D1, LOW);
  digitalWrite(D2, HIGH);
  digitalWrite(D3, LOW);
  digitalWrite(D4, LOW);
}
      
void digit3(){
  digitalWrite(D1, LOW);
  digitalWrite(D2, LOW);
  digitalWrite(D3, HIGH);
  digitalWrite(D4, LOW);
}
      
void digit4(){
  digitalWrite(D1, LOW);
  digitalWrite(D2, LOW);
  digitalWrite(D3, LOW);
  digitalWrite(D4, HIGH);
}

void all4Digits(){
  digitalWrite(D1, HIGH);
  digitalWrite(D2, HIGH);
  digitalWrite(D3, HIGH);
  digitalWrite(D4, HIGH);
}

//何を光らせるか
void bk_out(){
  digitalWrite(pinA, HIGH);
  digitalWrite(pinB, HIGH);
  digitalWrite(pinC, HIGH);
  digitalWrite(pinD, HIGH);
  digitalWrite(pinE, HIGH);
  digitalWrite(pinF, HIGH);
  digitalWrite(pinG, HIGH);
}

void zero(){
  digitalWrite(pinA, LOW);
  digitalWrite(pinB, LOW);
  digitalWrite(pinC, LOW);
  digitalWrite(pinD, LOW);
  digitalWrite(pinE, LOW);
  digitalWrite(pinF, LOW);
  digitalWrite(pinG, HIGH);
}

void one(){
  digitalWrite(pinA, HIGH);
  digitalWrite(pinB, LOW);
  digitalWrite(pinC, LOW);
  digitalWrite(pinD, HIGH);
  digitalWrite(pinE, HIGH);
  digitalWrite(pinF, HIGH);
  digitalWrite(pinG, HIGH);
}

void two(){
  digitalWrite(pinA, LOW);
  digitalWrite(pinB, LOW);
  digitalWrite(pinC, HIGH);
  digitalWrite(pinD, LOW);
  digitalWrite(pinE, LOW);
  digitalWrite(pinF, HIGH);
  digitalWrite(pinG, LOW);
}
  
void three(){
  digitalWrite(pinA, LOW);
  digitalWrite(pinB, LOW);
  digitalWrite(pinC, LOW);
  digitalWrite(pinD, LOW);
  digitalWrite(pinE, HIGH);
  digitalWrite(pinF, HIGH);
  digitalWrite(pinG, LOW);
}
    
void four(){
  digitalWrite(pinA, HIGH);
  digitalWrite(pinB, LOW);
  digitalWrite(pinC, LOW);
  digitalWrite(pinD, HIGH);
  digitalWrite(pinE, HIGH);
  digitalWrite(pinF, LOW);
  digitalWrite(pinG, LOW);
}
    
void five(){
  digitalWrite(pinA, LOW);
  digitalWrite(pinB, HIGH);
  digitalWrite(pinC, LOW);
  digitalWrite(pinD, LOW);
  digitalWrite(pinE, HIGH);
  digitalWrite(pinF, LOW);
  digitalWrite(pinG, LOW);
}
    
void six(){
  digitalWrite(pinA, LOW);
  digitalWrite(pinB, HIGH);
  digitalWrite(pinC, LOW);
  digitalWrite(pinD, LOW);
  digitalWrite(pinE, LOW);
  digitalWrite(pinF, LOW);
  digitalWrite(pinG, LOW);
}
    
void seven(){
  digitalWrite(pinA, LOW);
  digitalWrite(pinB, LOW);
  digitalWrite(pinC, LOW);
  digitalWrite(pinD, HIGH);
  digitalWrite(pinE, HIGH);
  digitalWrite(pinF, HIGH);
  digitalWrite(pinG, HIGH);
}
    
void eight(){
  digitalWrite(pinA, LOW);
  digitalWrite(pinB, LOW);
  digitalWrite(pinC, LOW);
  digitalWrite(pinD, LOW);
  digitalWrite(pinE, LOW);
  digitalWrite(pinF, LOW);
  digitalWrite(pinG, LOW);
}
    
void nine(){
  digitalWrite(pinA, LOW);
  digitalWrite(pinB, LOW);
  digitalWrite(pinC, LOW);
  digitalWrite(pinD, HIGH);
  digitalWrite(pinE, HIGH);
  digitalWrite(pinF, LOW);
  digitalWrite(pinG, LOW);
}

void ( * const SegmentArray[])(void) = {
  zero,
  one,
  two,
  three,
  four,
  five,
  six,
  seven,
  eight,
  nine,
  bk_out,
};


/********************************************************/
/*          CO2(MH-Z19C)                                */
/********************************************************/
void co2(void)
{
  long tt = millis();

  //電圧を取得
  int myVal = digitalRead(pwmPin);

  //パルス長の計測
  if (myVal == HIGH) {
    if (myVal != prevVal) {
      h = tt;
      tl = h - l;
      prevVal = myVal;
    }
  } 
  else
  {
    if (myVal != prevVal)
    {
      l = tt;
      th = l - h;
      prevVal = myVal;
      ppm = 5000 * (th - 2) / (th + tl - 4);
      Serial.println("PPM = " + String(ppm));
      Dsp_Co2 = ppm;
    }
  }
}


/********************************************************/
/*          Soil moisture                                */
/********************************************************/
void Soil_Moisture(void)
{
  Serial.print("Moisture Sensor Value:");
  noInterrupts(); //割り込み禁止
  soil_moisture = analogRead(A0);
  interrupts(); //割り込み許可
  Serial.println(soil_moisture);
}


/********************************************************/
/*          Radiation 日射                                */
/********************************************************/
void get_radiation(void){
  
  int   i = 0;
  
  Wire.beginTransmission(BH1750_addr);   // 指定したアドレスのI2Cスレーブに対して送信処理開始
  Wire.requestFrom(BH1750_addr, 2);      // I2Cデバイスのアドレスおよびデータ量を指定

  noInterrupts(); //割り込み禁止
  
  //2byte読み取り
  while(Wire.available()){
    buff[i] = Wire.read();
    i++;
  }

  interrupts(); //割り込み許可

  Wire.endTransmission();                // I2Cデバイスとの送信を終了
  
  valf=((buff[0]<<8)|buff[1]);         // buff[0]を8bitシフトしてbuff[1]とor取り2byteデータに変換
  valf = valf/1.2;                     // Measurement Accuracy 1.2倍@Typ.(@DataSheet)
  
  if(valf<0){ Serial.print("> 65535:Overflow"); // Overflowを表示(測定範囲 1 ~ 65535 lx @DataSheet)
  }
  else{
    Serial.print((int)valf,DEC);       // 整数および10進表示←分解能は1@DataSheet
  }
  Serial.println(" lx"); 

  ppfd = valf / 54;       //lux → ppfd

  dsp_ppfd = (int)ppfd;
  
}



/********************************************************/
/*          温湿度                                      */
/********************************************************/
void get_temp_hum(void)
{
  sensors_event_t humidity, temp;

  aht.getEvent(&humidity, &temp); // AHT21から湿度と温度の取得

  Serial.print("温度:");
  Serial.println((int)temp.temperature);
  dsp_temp = (int)temp.temperature;
  Serial.print("相対湿度:");
  Serial.println((int)humidity.relative_humidity);
  dsp_hum = (int)humidity.relative_humidity;
}

/************************************************************************/
/*      表示                                                           */
/************************************************************************/
void display()
{
  switch(flg_disp)
  {
    case (0):
      pv_dsp = dsp_temp;  //気温
      break;
    case (1):
      pv_dsp = dsp_hum;  //相対湿度
      break;
    case (2):
      pv_dsp = dsp_ppfd;  //日射(lx)
      break;
    case (3):
      pv_dsp = soil_moisture;  //土壌水分
      break;
    case (4):
      pv_dsp = Dsp_Co2;  //Co2
    default:
      break;
  }

  if(pv_dsp < 1000)
  {
    disp_1000 = bkout_segment;   
  }
  else
  {
    disp_1000 = pv_dsp / 1000;
  }

  if(pv_dsp < 100)
  {
    disp_100 = bkout_segment;   
  }
  else
  {
    disp_100 = pv_dsp % 1000 /100;
  }

  if(pv_dsp < 10)
  {
    disp_10 = bkout_segment;   
  }
  else
  {
    disp_10 = pv_dsp % 100 / 10;
  }

  disp_1 = pv_dsp % 10;
}


/********************************************************/
/*          割り込み (1ms)                               */
/********************************************************/
ISR(TCB2_INT_vect) {
  TCB2.INTFLAGS = 1;  //割り込みフラグのクリア

  /*  表示    */
  if(count_disp<dsp_timing)
  {
    count_disp++;
  }
  else
  {
    count_disp = 0;
    if(flg_disp < 4)
    {
      flg_disp++;
    }
    else
    {
      flg_disp = 0;
    }
  }

  if(tmr_get_soil_moisture < get_timing)
  {
    tmr_get_soil_moisture++;
  }

  if(tmr_get_radiation < get_timing)
  {
    tmr_get_radiation++;
  }

  if(tmr_get_temp_hum < get_timing)
  {
    tmr_get_temp_hum++;
  }

  if(scan_no < 4)
  {
    scan_no++;
  }
  else
  {
    scan_no = 0;
  }

  /*  7セグ     */
  count_1000ms++;

  /*ブラックアウト*/
  bk_out();

    switch (scan_no)
  {
    /*  1000桁    */
    case 0:
      digit1();
      SegmentArray[disp_1000]();
      break;
    /*  100桁    */
    case 1:
      digit2();
      SegmentArray[disp_100]();
      break;
    /*  10桁    */
    case 2:
      digit3();
      SegmentArray[disp_10]();
      break;
    /*  1桁    */
    case 3:
      digit4();
      SegmentArray[disp_1]();
      break;
    default:
      break;
  }
}


/********************************************************/
/*          メインループ                                */
/********************************************************/
void loop() {
  if (tmr_get_soil_moisture > 10) //1秒に1回
  {
    Soil_Moisture();
    tmr_get_soil_moisture = 0;
  }
  if (tmr_get_radiation > 10) //1秒に1回
  {
    get_radiation();
    tmr_get_radiation = 0;
  }
  if (tmr_get_temp_hum > 10) //1秒に1回
  {
    get_temp_hum();
    tmr_get_temp_hum = 0;
  }
  co2();
  display();
}