/*
 * KY-Logger for NIPR
 * 2014/7
 *
 * センサ
 * 　BMP180
 * 　SHT75
 *
 * 湿度センサーSHTにはV3とV4の２種類あり係数が違うので注意
 * 　Sensirion.cppに係数の定義があるので適宜切り替える
 *
 */
#include <Arduino.h>
#include <SPI.h>
#include <Wire.h>
#include <SD.h>
#include <EEPROM.h>
#include <avr/sleep.h>
#include <avr/pgmspace.h>	// for PROGMEM

#include "Sensirion.h"	// ソース(.c .h)を同じディレクトリに配置
#include "SFE_BMP180.h"
#include "myutil.h"


#define	VER  "1.0"

// EEPROMの記録アドレス
#define	EEPROM_ID  0
#define	EEPROM_SAMPLE  1
// Loger ID
byte ID;
#define	ID_MAX  99
// Sample sec 1-255
byte sample;
#define	SAMPLE_DEFAULT	1
#define	SAMPLE_MIN	1
#define	SAMPLE_MAX	240

// LED
const int LED_RED = 8;
const int LED_BLUE = 9;

// SHT7xデバイス
const uint8_t dataPin1  =  4;  // データ端子定義
const uint8_t clockPin1 =  5;  // クロック端子定義

float temperature1; // 温度格納用変数 degC
float humidity1;    // 湿度格納用変数 %RH
float dewpoint1;    // 露点温度格納用変数

Sensirion tempSensor1 = Sensirion(dataPin1, clockPin1);

// BMP180 気圧センサ
float pressure=0, tempPress;
SFE_BMP180 bmp180;

// SD カード
#define	SD_CS	10

// RTC
#define	RTC_INT_PIN	2
int RTC8564_SLAVE_ADRS=0x51; // RTC のスレーブアドレス
typedef struct {
  int sec, minute, hour;
  int day, week, month, year;  // year=00-99
} MyDateTime;
void getTime(MyDateTime *t);
MyDateTime  now;	// 現在時刻
byte  before_sec=255;	// 1秒前の時刻の秒
byte rtc_intf; // RTC INTかかったら1になる

// 動作モード　SLEEP/IDLE
#define	MODE_SLEEP	0	// 通常の観測モード 毎秒SLEEPする
#define	MODE_IDLE	1	// 時刻セットなどコマンドを受け付けるモード　SLEEPしない
//#define	MODE_MON	2	// モニタモード　SLEEPしない
byte mode;
byte idle_cnt;		// IDLEモードのタイムアウトカウント sec単位
#define	IDLE_CNT_TIMEOUT	60	// sec単位
byte mon_flag;

// 電源モニタ
float v_batt=0; // Volt

/*
 * DEBUG Serial OUT
 */
//#define	DEBUG_SERIAL	// デバッグ用シリアル出力　使用時に定義する

#ifdef	DEBUG_SERIAL
	#define	DEBUG_SERIAL_INIT()	Serial.begin(9600)
	#define	DEBUG_SERIAL_FLUSH()	Serial.flush()
	// 文字列をFLASHとRAMに格納する
	#define	PDEBUG(s)		Serial.print(s)
	#define	PDEBUG_ARG(s,t)	Serial.print(s,t)
	#define	PDEBUGLN(s)		Serial.println(s)
	#define	PDEBUGLN_ARG(s,t)	Serial.println(s,t)
	// 文字列をFLASHのみに格納する
	#define	PDEBUG_PGM(s)	PDEBUG_PGM0(PSTR(s))
	#define	PDEBUGLN_PGM(s)	PDEBUGLN_PGM0(PSTR(s))
#else
	#define	DEBUG_SERIAL_INIT()	Serial.begin(9600)
	#define	DEBUG_SERIAL_FLUSH()	Serial.flush()
	#define	PDEBUG(s)
	#define	PDEBUG_ARG(s,t)
	#define	PDEBUGLN(s)
	#define	PDEBUGLN_ARG(s,t)

	#define	PDEBUG_PGM(s)
	#define	PDEBUGLN_PGM(s)
#endif
__attribute__((noinline)) void PDEBUG_PGM0(PGM_P str) {
	for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.write(c);
}
__attribute__((noinline)) void PDEBUGLN_PGM0(PGM_P str) {
	PDEBUG_PGM0(str);
	Serial.println();
}
// 通常のシリアル出力文字列をFLASHに格納する
#define	SERIAL_PGM(s)	PDEBUG_PGM0(PSTR(s))
#define	SERIALLN_PGM(s)	PDEBUGLN_PGM0(PSTR(s))

void SerialPurge(void)
{
  delay(100);
  while(Serial.available() > 0){
    char c = Serial.read();
    delay(100);
  }
}
/*
 * RTC関係
 */
#define BCD2Decimal(x)		(((x>>4)*10)+(x&0xf))

/*
 * SLEEP
 */
// If not included in Arduino AVR toolset...
#ifndef sleep_bod_disable()
#define sleep_bod_disable() \
do { \
  uint8_t tempreg; \
  __asm__ __volatile__("in %[tempreg], %[mcucr]" "\n\t" \
                       "ori %[tempreg], %[bods_bodse]" "\n\t" \
                       "out %[mcucr], %[tempreg]" "\n\t" \
                       "andi %[tempreg], %[not_bodse]" "\n\t" \
                       "out %[mcucr], %[tempreg]" \
                       : [tempreg] "=&d" (tempreg) \
                       : [mcucr] "I" _SFR_IO_ADDR(MCUCR), \
                         [bods_bodse] "i" (_BV(BODS) | _BV(BODSE)), \
                         [not_bodse] "i" (~_BV(BODSE))); \
} while (0)
#endif

//-------------------------------------------------
/*
 * BMP180 気圧・温度取得
 * press Pressure hPa
 * temp Temperature degC
 */
void getPress(float *press, float *temp)
{
  char status;
  double P, T;
//  double p0,a;
  // Start a temperature measurement:
  // If request is successful, the number of ms to wait is returned.
  // If request is unsuccessful, 0 is returned.
  status = bmp180.startTemperature();
  if (status != 0)
  {
    // Wait for the measurement to complete:
    delay(status);

    // Retrieve the completed temperature measurement:
    // Note that the measurement is stored in the variable T.
    // Function returns 1 if successful, 0 if failure.

    status = bmp180.getTemperature(T);
    if (status != 0)
    {
      // Print out the measurement:
//      PDEBUG("temperature: ");
//      PDEBUG_ARG(T,2);
//      PDEBUGLN(" deg C");

      // Start a pressure measurement:
      // The parameter is the oversampling setting, from 0 to 3 (highest res, longest wait).
      // If request is successful, the number of ms to wait is returned.
      // If request is unsuccessful, 0 is returned.

      status = bmp180.startPressure(3);
      if (status != 0)
      {
        // Wait for the measurement to complete:
        delay(status);

        // Retrieve the completed pressure measurement:
        // Note that the measurement is stored in the variable P.
        // Note also that the function requires the previous temperature measurement (T).
        // (If temperature is stable, you can do one temperature measurement for a number of pressure measurements.)
        // Function returns 1 if successful, 0 if failure.

        status = bmp180.getPressure(P,T);
        if (status != 0)
        {
          // Print out the measurement:
//          PDEBUG("absolute pressure: ");
//          PDEBUG_ARG(P,2);
//          PDEBUGLN(" hPa");
        }
        else PDEBUGLN("error retrieving pressure measurement\n");
      }
      else PDEBUGLN("error starting pressure measurement\n");
    }
    else PDEBUGLN("error retrieving temperature measurement\n");
  }
  else PDEBUGLN("error starting temperature measurement\n");
  *press = P;
  *temp = T;

}
//-------------------------------------------------
/*
 * BCDで取得してDecimalに変換する
 */
void getTime(MyDateTime *t)
{
  uint8_t bsec, bminute, bhour, bday, bweek, bmonth, byear;
  //　時刻データを取得 BCD
  i2cReadBegin(RTC8564_SLAVE_ADRS, 0x02, 7);
  bsec   = Wire.read() & 0x7F ;   //  2
  bminute = Wire.read() & 0x7F ;   //  3
  bhour   = Wire.read() & 0x3F ;   //  4
  bday    = Wire.read() & 0x3F ;   //  5
  bweek   = Wire.read() & 0x07 ;   //  6
  bmonth  = Wire.read() & 0x1F ;   //  7
  byear   = Wire.read();           //  8 2桁

  t->sec = BCD2Decimal(bsec);
  t->minute = BCD2Decimal(bminute);
  t->hour = BCD2Decimal(bhour);
  t->day = BCD2Decimal(bday);
  t->month = BCD2Decimal(bmonth);
  t->year = BCD2Decimal(byear);
}
/*
 * RTC SET
 * ye YEAR 00-99　 BCD値
 *  ....
 * se second BCD値
 * 日時をBCD値で渡すこと
 */
void setTime(byte ye, byte mo, byte da, byte ho, byte mi, byte se)
{
	Wire.beginTransmission(RTC8564_SLAVE_ADRS);
	Wire.write(0x00);	// write reg addr 00
	Wire.write(0x00);	// 00 Control 1, STOP=1
	Wire.write(0x11);	// 01 Control 2, PERIODIC=1
//-----------------------------------------------------
	Wire.write(se);	// 02 Seconds (BCD)
	Wire.write(mi);	// 03 Minutes (BCD)
	Wire.write(ho);	// 04 Hours (BCD)
	Wire.write(da);	// 05 Days (BCD)
	Wire.write(0);	// 06 Weekdays SUN=0
	Wire.write(mo);	// 07 Months
	Wire.write(ye);	// 08 Years
//-----------------------------------------------------
	Wire.write(0x00);	// 09 Minutes Alarm
	Wire.write(0x00);	// 0A Hours Alarm
	Wire.write(0x00);	// 0B Days Alarm
	Wire.write(0x00);	// 0C Weekdays Alarm
	Wire.write(0x00);	// 0D CLKOUT
	Wire.write(0x00);	// 0E Timer control
	Wire.write(0x00);	// 0F Timer preset
	Wire.endTransmission();
}

//-------------------------------------------------
/*
 * SDファイルシステム用に日時を返す関数
 */
void dateTime(uint16_t* date, uint16_t* time)
{
  uint16_t yearF;
  uint8_t monthF, dayF, hourF, minuteF, secondF;

  yearF   = (now.year)+2000;
  monthF  = (now.month);
  dayF    = (now.day);
  hourF   = (now.hour);
  minuteF = (now.minute);
  secondF = (now.sec);

  *date = FAT_DATE(yearF, monthF, dayF);
  *time = FAT_TIME(hourF, minuteF, secondF);
}
//-------------------------------------------------
void writeDataSD()
{
  char  fname[16];
  char  dirname[8];
  char  path[32];
  char  str[80];
  char	*p;
//Serial.println("A");
  // ディレクトリ名
//  snprintf(dirname, sizeof(dirname), "%02d%02d", year % 100, month);
  p = Fmt02d(now.year % 100, dirname);
  p = Fmt02d(now.month, p);
  *p = 0;
  if (!SD.exists(dirname)) {
    PDEBUG(dirname);
    PDEBUGLN(" not found. Create it");
    SD.mkdir(dirname);
  }
  // ファイル名
  //snprintf(fname, sizeof(fname), "%02d%02d%02d.txt", year % 100, month, day);
  p = Fmt02d(ID, fname);
  p = Fmt02d(now.year % 100, p);
  p = Fmt02d(now.month, p);
  p = Fmt02d(now.day, p);
  *p = 0;
  strcat(fname, ".txt");
  // ファイルのフルパス作成
  strcpy(path, dirname);
  strcat(path, "/");
  strcat(path, fname);
//  PDEBUGLN(path);

  // ファイルに書き込むデータを作る
  p = Fmt02d(now.year % 100, str);
  *p++ = '/';
  p = Fmt02d(now.month, p);
  *p++ = '/';
  p = Fmt02d(now.day, p);
  *p++ = ' ';
  p = Fmt02d(now.hour, p);
  *p++ = ':';
  p = Fmt02d(now.minute, p);
  *p++ = ':';
  p = Fmt02d(now.sec, p);
  *p++ = ',';
  p = fmtDouble(temperature1, 2, p); // SHT 温度 degC
  *p++ = ',';
  p = fmtDouble(humidity1, 2, p); // SHT 湿度 %RH
  *p++ = ',';
  p = fmtDouble(pressure, 2, p); // 気圧 hPa
  *p++ = ',';
  p = fmtDouble(tempPress, 2, p); // 気圧センサ温度 degC
  *p++ = ',';
  p = fmtDouble(v_batt, 2, p); // 電源電圧 V
  *p++ = '\r';
  *p++ = '\n';
  *p++ = 0;

  File dataFile = SD.open(path, FILE_WRITE);
  // if the file is available, write to it:
  if (dataFile) {
    dataFile.print(str);
    dataFile.close();
    dataFile.flush();
    // モニタフラグONならば測定値をシリアル出力する
    if (mon_flag) {
      Serial.print(str);
    }
  } else {
    PDEBUG("error opening file ");
    PDEBUGLN(fname);
    DEBUG_SERIAL_FLUSH();
    while(1){ // 失敗、(無限ループ）
      blinkLED(LED_RED,20);
    }
  }
//Serial.println("B");

}
//-------------------------------------------------
/*
 * LED 一定時間ONするだけ
 * OFF時のdelayなし
 */
void blinkLEDoneshot(byte pin, int period)
{
  // ON
  digitalWrite(pin, HIGH);
  delay(period);
  // OFF
  digitalWrite(pin,LOW);
}
//-------------------------------------------------
/*
 * LED 点滅
 * OFF時のdelayもあるので複数回呼ぶ用途に使う
 */
void blinkLED(byte pin, int period)
{
  // ON
  digitalWrite(pin, HIGH);
  delay(period);
  // OFF
  digitalWrite(pin,LOW);
  delay(period*4);
}
//--------------------- I2C -------------------
// I2Cで指定したセンサの指定アドレスから１バイト読み出す
void i2cReadBegin(int deviceAddress, int registerAddress, int numBytes){
  Wire.beginTransmission(deviceAddress);
  Wire.write(registerAddress);
  Wire.endTransmission();
  Wire.requestFrom(deviceAddress, numBytes);
}

// I2Cで指定したセンサの指定アドレスに１バイト書き込む
void i2cWriteByte(int deviceAddress, int registerAddress, int data){
  Wire.beginTransmission(deviceAddress);
  Wire.write(registerAddress);
  Wire.write(data);
  Wire.endTransmission();
}
#define CMD_TIME_SET 'T'   // Header tag for serial time sync message
#define CMD_TIME_GET 'G'    // ASCII bell character requests a time sync message
//#define	CMD_IDLE     'W'
#define	CMD_ID       'I'  // ID SET
#define	CMD_SAMP     'S'  // Sample Interval SET
#define	CMD_MON_SEC  'C'  // Monitor SEC MODE
#define	CMD_MON      'M'  // Monitor MODE
// コマンドバイト数　コマンド文字＋パラメータの文字数
#define	CMD_TIME_SET_LEN   13
#define	CMD_TIME_GET_LEN   1
#define	CMD_ID_LEN         5
#define	CMD_SAMP_LEN       4
#define	CMD_MON_SEC_LEN    1
#define	CMD_MON_LEN        1

// 2文字の10進文字列を1バイトのBCDコードに変換
#define	Str2BCD(p)	(byte)(((byte)((p)[0])-0x30)*16 + ((byte)((p)[1])-0x30))
// 2文字の16進文字列を1バイトの整数に変換
byte HexStr2Val(char *p)
{
  char buf[8];
  buf[0] = '0';
  buf[1] = 'x';
  buf[2] = *p;
  buf[3] = *p++;
  buf[4] = 0;
  return atoi(buf);
}
/*
 * 時刻セットコマンドを解析してRTCに時刻セット
 * フォーマット　'T' + YYMMDDHHNNSS + CR or LF
 */
void cmdTimeSet(char *buf, char len)
{
  byte sec,minute,hour,day,month,year;

  if (len != CMD_TIME_SET_LEN) {
    SERIALLN_PGM("ERR");
    return;
  }
  // 文字列をBCDコードに変換
  year   = Str2BCD(buf+1);
  month  = Str2BCD(buf+3);
  day    = Str2BCD(buf+5);
  hour   = Str2BCD(buf+7);
  minute = Str2BCD(buf+9);
  sec    = Str2BCD(buf+11);
  // RTC SET
  setTime(year, month, day, hour, minute, sec);
  SERIALLN_PGM("OK");
}
/*
 * 時刻ゲットコマンドを受信したので
 * 現在時刻を送信
 */
void cmdTimeGet(char len)
{
  char	str[32];
  char	*p;
  if (len != CMD_TIME_GET_LEN) {
    SERIALLN_PGM("ERR");
    return;
  }
  //
  p = Fmt02d(now.year % 100, str);
  *p++ = '/';
  p = Fmt02d(now.month, p);
  *p++ = '/';
  p = Fmt02d(now.day, p);
  *p++ = ' ';
  p = Fmt02d(now.hour, p);
  *p++ = ':';
  p = Fmt02d(now.minute, p);
  *p++ = ':';
  p = Fmt02d(now.sec, p);
  *p++ = 0;

  Serial.println(str);
  SERIALLN_PGM("OK");
}
/*
 * IDLEコマンドを受信
 * IDLEモードへ
 */
#if 0
void cmdIdle(void)
{
  mode = MODE_IDLE;
  idle_cnt = 0;
  SERIALLN_PGM("IDLE");
}
#endif
/*
 * IDをセット
 */
void cmdIdSet(char *buf, char len)
{
  byte i1, i2;

  if (len != CMD_ID_LEN) {
    SERIALLN_PGM("ERR");
    return;
  }
  // 10進文字列2桁 2setを数値に変換
  buf[5] = 0;
  i2 = atoi(buf+3);
  buf[3] = 0;
  i1 = atoi(buf+1);
  if (i1 != i2) {
    SERIALLN_PGM("ERR");
    return;
  }
  SERIAL_PGM("ID=");
  Serial.println(i1);

  EEPROM.write(EEPROM_ID, i1);
  ID = EEPROM.read(EEPROM_ID);
}
/*
 * サンプル間隔をセット
 */
void cmdSampleSet(char *buf, char len)
{
  byte i;

  if (len != CMD_SAMP_LEN) {
    SERIALLN_PGM("ERR");
    return;
  }
  // 10進文字列x3を数値に変換
  buf[4] = 0;
  i = atoi(buf+1);
  SERIAL_PGM("SAMPLE=");
  Serial.println(i);
  if (i < SAMPLE_MIN || i > SAMPLE_MAX) {
    SERIALLN_PGM("ERR");
    return;
  }
  SERIALLN_PGM("OK");

  EEPROM.write(EEPROM_SAMPLE, i);
  sample = EEPROM.read(EEPROM_SAMPLE);
}
/*
 * 毎秒モニタモード
 */
void cmdMonSec(char len)
{
  if (len != CMD_MON_SEC_LEN) {
    SERIALLN_PGM("ERR");
    return;
  }
  mode = MODE_SLEEP;
  mon_flag = 1;
  sample = 1;
  SERIALLN_PGM("MONITOR SEC");
  SERIALLN_PGM("OK");
  while(Serial.available() > 0){
    char c = Serial.read();
    delay(10);
  }
}
/*
 * モニタモード
 */
void cmdMon(char len)
{
  if (len != CMD_MON_LEN) {
    SERIALLN_PGM("ERR");
    return;
  }
  mode = MODE_SLEEP;
  mon_flag = 1;
  SERIALLN_PGM("MONITOR ON");
  SERIALLN_PGM("OK");
  while(Serial.available() > 0){
    char c = Serial.read();
    delay(10);
  }
}
/*
 * シリアルからコマンドを受信して処理
 */
void processCmd() {
  static char buf[32];
  static char cnt=0;

  while(Serial.available() > 0){
    char c = Serial.read() ;
    if (c == 0x0d || c == 0x0a) {
      if (cnt > 0) {
	buf[cnt] = 0;
	PDEBUG_PGM("RX: ");
	PDEBUGLN(buf);
	if (buf[0] == CMD_TIME_SET) {
	  // 時刻セットコマンド受信
	  cmdTimeSet(buf, cnt);
	} else if (buf[0] == CMD_TIME_GET) {
	  // 時刻ゲットコマンド受信
	  cmdTimeGet(cnt);
	} else if (buf[0] == CMD_ID) {
	  // ID設定コマンド
	  cmdIdSet(buf, cnt);
	} else if (buf[0] == CMD_SAMP) {
	  // サンプル間隔セット
	  cmdSampleSet(buf, cnt);
	} else if (buf[0] == CMD_MON_SEC) {
	  // 毎秒モニタモード
	  cmdMonSec(cnt);
	} else if (buf[0] == CMD_MON) {
	  // モニタモード
	  cmdMon(cnt);
	}
      }
      cnt = 0;
//    } else if (c == CMD_IDLE) {
      // IDLEモードへ
//      cmdIdle();
    } else {
      buf[cnt++]= c;
      if (cnt >= sizeof(buf)) cnt = 0;
    }
    idle_cnt = 0; // IDLEモード継続
    if (mode == MODE_SLEEP) {
      SERIALLN_PGM("IDLE MODE");
      mode = MODE_IDLE;
    }
  }
}

//=================================================================
/*
 * SETUP
 */
void setup()
{
  // LED
  pinMode(LED_BLUE,OUTPUT);
  pinMode(LED_RED,OUTPUT);
  digitalWrite(LED_BLUE,LOW);
  digitalWrite(LED_RED,LOW);

  for (byte i=0; i<2; i++){
    blinkLED(LED_RED,100);
  }
  DEBUG_SERIAL_INIT();
  Wire.begin();
  delay(100);

  // Logger ID 0-99
  ID = EEPROM.read(EEPROM_ID);
  if (ID > ID_MAX) {
    ID = 0;
  }
  // Sample間隔 1-240sec
  sample = EEPROM.read(EEPROM_SAMPLE);
  if (sample == 0 || sample > SAMPLE_MAX) {
    SERIALLN_PGM("Sample Invalid and Init");
    sample = SAMPLE_DEFAULT;
  }
  // 起動メッセージ
  SERIAL_PGM("Ver=");
  Serial.println(VER);
  SERIAL_PGM("ID=");
  Serial.println(ID);
  SERIAL_PGM("Sample=");
  Serial.println(sample);

  // 気圧センサ BMP180 Init
  if (bmp180.begin()) {
    SERIALLN_PGM("BMP180 init success");
  } else {
    SERIALLN_PGM("BMP180 init fail\n\n");
    DEBUG_SERIAL_FLUSH();
    while(1) { // 失敗、(無限ループ）
      blinkLED(LED_BLUE,20);
    }
  }
  // SD card
  pinMode(SD_CS, OUTPUT);// SS(10)ピン出力にする必要があり。
  if (!SD.begin(SD_CS)) {
    SERIALLN_PGM("SD.begin() FAIL!");
    DEBUG_SERIAL_FLUSH();
    while(1){ // 失敗、(無限ループ）
      blinkLED(LED_RED,20);
    }
  }
  SdFile::dateTimeCallback( &dateTime );  // 日付と時刻を返す関数を登録

  // RTC時刻チェック
  getTime(&now);
  if (now.month > 12 || now.month < 1 || now.day > 31 || now.day < 1 ||
  now.hour > 23 || now.hour < 0 || now.minute > 59 || now.minute < 0 || now.sec > 59 || now.sec < 0) {
    setTime(0x14,1,1,0,0,0);
    SERIALLN_PGM("RTC Invalid and Init time");
  }
  getTime(&now);
  SERIAL_PGM("RTC=");
  Serial.print(now.year);
  SERIAL_PGM("/");
  Serial.print(now.month);
  SERIAL_PGM("/");
  Serial.print(now.day);
  SERIAL_PGM(" ");
  Serial.print(now.hour);
  SERIAL_PGM(":");
  Serial.print(now.minute);
  SERIAL_PGM(":");
  Serial.println(now.sec);

  /*
   * CPU SLEEP関係
   */
  pinMode(RTC_INT_PIN,INPUT);               // インタラプトピン設定
  /*
   * RTCの定周期タイマーを設定
   */
#if 1
  // Timer off
  i2cWriteByte(RTC8564_SLAVE_ADRS, 0x0E, 0x00);   // Timer Stop TE->0
  i2cWriteByte(RTC8564_SLAVE_ADRS, 0x01, 0x00);   // TF,TIE->0
  // Timer start
  i2cWriteByte(RTC8564_SLAVE_ADRS, 0x01, 0x11);   // Periodic Timer Interrupt Enable　TI/TP(4)=1 TF(2)=0 TIE(0)=1
//  i2cWriteByte(RTC8564_SLAVE_ADRS, 0x01, 0x01);   // Level Interrupt Enable　TI/TP(4)=0 TF(2)=0 TIE(0)=1
  i2cWriteByte(RTC8564_SLAVE_ADRS, 0x0F, 0x01);   // Timer preset 測定間隔(10s:0a, 30s:1e, 60s:3c)
  i2cWriteByte(RTC8564_SLAVE_ADRS, 0x0E, 0x82);   // Timer start TE=1, Freq = 1Hz
#endif
  rtc_intf = 0;
  mode = MODE_IDLE;
  mon_flag = 0;
  idle_cnt = IDLE_CNT_TIMEOUT - 5;
}
/*
 * SLEEP
 */
void sleepNow()         // here we put the arduino to sleep
{
//  PDEBUGLN("A");
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here
    sleep_enable();          // enables the sleep bit in the mcucr register
                             // so sleep is possible. just a safety pin
    attachInterrupt(0,INT0_ISR, LOW); // use interrupt 0 (pin 2) and run function
                                       // wakeUpNow when pin 2 gets LOW
//  PDEBUGLN("B"); delay(10);
    sleep_mode();            // here the device is actually put to sleep!!
                             // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
    /* SLEEP */
    sleep_disable();         // first thing after waking from sleep:
                             // disable sleep...
    detachInterrupt(0);      // disables interrupt 0 on pin 2 so the
                             // wakeUpNow code will not be executed
                             // during normal running time.
//  PDEBUGLN("C");
}
//=================================================================
/*
 * LOOP
 */

void loop()
{
  rtc_intf = 0;

//  before_sec = now.sec;
  getTime(&now);  // 時間取得
//PDEBUGLN_ARG(now.sec,DEC);
  // SLEEPモード: 時刻を見てサンプルするかどうか決める
  if (((now.minute*60 + now.sec) % sample == 0) && (mode == MODE_SLEEP)) {
    tempSensor1.measure(&temperature1, &humidity1, &dewpoint1);  // SHT-75 温湿度測定
    getPress(&pressure, &tempPress); // BMP180 気圧測定

    int v = analogRead(0); // バッテリモニタ
    v_batt = v*9.9/1024.;	// 1/3に分圧しているので

    // ファイル書き込み
    writeDataSD();

    // サンプル周期でLED点滅パターン変える
    if (sample >= 30) {
      for (byte i=0; i<2; i++){
        blinkLED(LED_BLUE,20);
      }
    } else {
      blinkLEDoneshot(LED_BLUE,20);
    }
  } // 測定・記録終わり
  else {
    delay(10);	// シリアルからのコマンド受信のために少しだけ待つ
  }
  // シリアルからのコマンド処理
  processCmd();
  // Sleepに入る前にシリアルバッファ内容の送信が終わるまで待つ
  DEBUG_SERIAL_FLUSH();

  /*
   * CPU SLEEPする
   */
  if (mode == MODE_SLEEP) {
    // SLEEPモード
    sleepNow();     // sleep function called here
    i2cWriteByte(RTC8564_SLAVE_ADRS, 0x01, 0x11);   // 繰り返し割込み 割り込みフラグTFクリアしてINT信号をHにする　TI/TP(4)=1 TF(2)=0 TIE(0)=1
  } else {
    // IDLEモード
    // 1sec待つ
    before_sec = now.sec;
    while(before_sec == now.sec) {
      delay(100);
      getTime(&now);  // 時間取得
    }
    // IDLEモードの場合はタイムアウト
    if (mode == MODE_IDLE) {
      idle_cnt++;
  //Serial.println(idle_cnt);
      if (idle_cnt > IDLE_CNT_TIMEOUT) {
	mode = MODE_SLEEP;
	SERIALLN_PGM("SLEEP MODE");
      }
    }
  }
}
//=============================================================
void INT0_ISR()
{
  // RTC TFクリアしたいが出来ない　i2cWriteByte()するとハングする
//  i2cWriteByte(RTC8564_SLAVE_ADRS, 0x01, 0x01);   // Level割込み 割り込みフラグTFクリアしてINT信号をHにする　TI/TP(4)=0 TF(2)=0 TIE(0)=1
//  i2cWriteByte(RTC8564_SLAVE_ADRS, 0x01, 0x11);   // TI/TP(4)=1 TF(2)=0 TIE(0)=1

  sleep_disable();
  detachInterrupt(0);  // 割り込み停止
  // 割り込みフラグ
  rtc_intf = 1;
}
