#include <string.h>

// ピン設定 | Pin assignments
#define GT_DTR 4      // DTR
#define GT_DSR 6      // DSR
#define GT_TRDY 7     // TRDY <--未使用 | unused in this sample

void setup() {
  // ピン初期設定 | Pin setting
  pinMode(GT_DTR, INPUT);
  pinMode(GT_DSR, OUTPUT);
  pinMode(GT_TRDY, INPUT);
  digitalWrite(GT_DSR, LOW);

  // シリアル通信の初期設定 | Serial communication initialization
  Serial.begin(38400); // 38400bps Baud rate
  Serial.setTimeout(100); // シリアルタイムアウト | Serial timeout

  // メーターの最小値と最大値を設定 | Set min and max values for meter
  setMeterRange(0, 240);
}

// 変数 | Variable
const int numReadings = 10; // 平均化に使用する読み取り回数 | Number of readings to use for averaging
int readings[numReadings];  // 読み取り値を格納する配列 | Array to store readings
int readIndex = 0;          // 現在の読み取りインデックス | Current reading index
int total = 0;              // 読み取り値の合計 | Sum of readings
int average = 0;            // 平均値 | Average

void loop() {
  // 古い読み取り値を合計から引く | Subtract old readings from the total
  total -= readings[readIndex];

  // 新しい読み取り値を取得し、合計に加える | Get a new reading and add it to the total
  readings[readIndex] = analogRead(A0);
  total += readings[readIndex];

  // インデックスを進める（末尾に到達したらリセット） | Advance the index (reset when the end is reached)
  readIndex = (readIndex + 1) % numReadings;

  // 平均値を計算 | Calculate average
  average = analogRead(A0);

  // 平均値を0-240の範囲にマッピングし、範囲内に収める | Mapping the mean to a range of 0-240 and staying within the range
  int meterValue = constrain(map(average, 0, 1023, 0, 240), 0, 240);

  // GT-SPに値を送信 | Send value to GT-SP
  sendMeterValueToGTSP(meterValue);

  delay(100); // 100ミリ秒待つ | Wait 100 milliseconds
}

// GT-SPにメーターの最小値と最大値を設定 | Set min and max values for meter
void setMeterRange(int minValue, int maxValue) {
  sendCommandToGTSP(0x1E, minValue); // Set minimum value
  sendCommandToGTSP(0x1F, maxValue); // Set maximum value
}

// GT-SPに値を送信 | Send value to GT-SP
void sendMeterValueToGTSP(int value) {
  sendCommandToGTSP(0x10, value);
}

// GT-SPにコマンドを送信 | Send command to GT-SP
void sendCommandToGTSP(int property, int value) {
  gtsp_ObjPrpSet_val(0, property, 4, value);
}

/********************** GT-SP関数 | Function for GT-SP **********************/
////////////////////////////////////////////////////
// オブジェクト制御コマンド-プロパティ読み出し（数値用）| Read property value (for Value)
////////////////////////////////////////////////////
unsigned long gtsp_ObjPrpRead_val(int obj, int prp, int ln) {
  unsigned long val;

  gt_print("CMD"); // コマンドヘッダ | Command header
  gt_put(0xd4); // オブジェクト-プロパティ設定コマンド | Object-Property Setting
  gt_put(obj >> 0); // オブジェクトNo. 下位バイト | Object No. Lower byte
  gt_put(obj >> 8); // オブジェクトNo. 上位バイト | Object No. Upper byte
  gt_put(prp >> 0); // プロパティNo. 下位バイト | Property No. Lower byte
  gt_put(prp >> 8); // プロパティNo. 上位バイト | Property No. Upper byte
  gt_put(ln >> 0); // データ長 最下位バイト | Data length Least significant byte
  gt_put(ln >> 8); // データ長 下位バイト | Data length second byte
  gt_put(ln >> 16); // データ長 上位バイト | Data length third byte
  gt_put(ln >> 24); // データ長 最上位バイト | Data length Most significant byte

  // プロパティデータ受信 | Property data received
  while (Serial.available() == 0) {}
  val = gtsp_signal_read_val();
  return val;
}

////////////////////////////////////////////////////
// データ受信（文字列用）| Receive data from GT-SP (for String)
////////////////////////////////////////////////////
String gtsp_signal_read() {
  byte res_dl[4] = "";
  unsigned long dl;
  char res_data_char[255] = "";

  if (Serial.find("RESb", 4)) {
    Serial.readBytes(res_dl, 4); // データ長抽出 | Data-length extraction
    dl = (unsigned long)(res_dl[0] + (res_dl[1] << 8) + (res_dl[2] << 16) + (res_dl[3] << 24)); // データ長変換 | Data length
    Serial.readBytes(res_data_char, dl); // データ抽出 | Read data
    Serial.print("Received data: ");
    for (unsigned int i = 0; i < dl; i++) {
      Serial.print(res_data_char[i], HEX);
      Serial.print(" ");
    }
    Serial.println();
    return String(res_data_char); // String type conversion, return
  }
  return "";
}

////////////////////////////////////////////////////
//  データ受信(数値用) | Receive data from GT-SP (for Value)
//  (バイト長4バイトまで | Byte length is up to 4 byte)
////////////////////////////////////////////////////
unsigned long gtsp_signal_read_val(){
 
  byte res_dl[4] = "";
  unsigned long dl;
  byte res_val[4] = "";
  unsigned long val;
 
  if (Serial.find("RESb", 4)){
    Serial.readBytes(res_dl, 4); //データ長抽出 | Read data length
    dl = (unsigned long)(res_dl[0] + (res_dl[1]<<8) + (res_dl[2]<<16) + (res_dl[3]<<24)); //データ長変換 | Data length
    Serial.readBytes(res_val, dl); //データ抽出 | Read data
    val = (unsigned long)(res_val[0] + (res_val[1]<<8) + (res_val[2]<<16) + (res_val[3]<<24)); //データ抽出 | Read data
    return val; //リターン | Return 
  }
}

////////////////////////////////////////////////////
// 1byte送信 | Send byte to GT-SP
////////////////////////////////////////////////////
void gt_put(unsigned char onebyte) {
  while (digitalRead(GT_DTR) == HIGH) {} // busycheck
  Serial.write(onebyte);
}

////////////////////////////////////////////////////
// 文字列送信 | Send String to GT-SP
////////////////////////////////////////////////////
void gt_print(String val) {
  int val_i;
  // 文字列を1文字ずつ送信 | Send string per one byte
  for (val_i = 0; val_i < val.length(); val_i++) {
    while (digitalRead(GT_DTR) == HIGH) {} // busycheck
    Serial.print(val.substring(val_i, val_i + 1));
  }
}

////////////////////////////////////////////////////
// オブジェクト制御コマンド - プロパティ設定 (数値用) | Object Control Command - Property Setting (for Value)
////////////////////////////////////////////////////
void gtsp_ObjPrpSet_val(int obj, int prp, int ln, unsigned long val) {
  gt_print("CMD"); // コマンドヘッダ | Command header
  gt_put(0xD3); // オブジェクト-プロパティ設定コマンド | Object-Property Setting
  gt_put(obj >> 0); // オブジェクトNo. 下位バイト | Object No. Lower byte
  gt_put(obj >> 8); // オブジェクトNo. 上位バイト| Object No. Upper byte
  gt_put(prp >> 0); // プロパティNo. 下位バイト | Property No. Lower byte
  gt_put(prp >> 8); // プロパティNo. 上位バイト| Property No. Upper byte
  gt_put(ln >> 0); // データ長 最下位バイト | Data length Least significant byte
  gt_put(ln >> 8); // データ長 下位バイト | Data length second byte
  gt_put(ln >> 16); // データ長 上位バイト | Data length third byte
  gt_put(ln >> 24); // データ長 最上位バイト| Data length Most significant byte
  if (ln >= 1) { gt_put(val >> 0); } // データ 最下位バイト | Data Least significant byte
  if (ln >= 2) { gt_put(val >> 8); } // データ 下位バイト | Data second byte
  if (ln >= 3) { gt_put(val >> 16); } // データ 上位バイト | Data third byte
  if (ln >= 4) { gt_put(val >> 24); } // データ 最上位バイト| Data Most significant byte
}
