/*
 * Digital HanaHotaru
 *
 *  Author: akira noda
 */


#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#define false 0
#define true -1
#include <avr/wdt.h>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)<(y)?(x):(y))

volatile  char sleepFlag;
ISR(WDT_vect){}//センサークランプ待ち用WDT割り込み
ISR(TIM0_CAPT_vect){//センサー用タイマ割り込み(積分時間計測
	sleepFlag=false;
}
ISR(INT0_vect){} //充電完了割り込み(起動)
 
static int16_t thresh;
int32_t old;
static int16_t getCount();
static void ledOn(){
	PORTB |= _BV(PORTB0);//HIGH
}
static void ledOff(){
	PORTB &= ~_BV(PORTB0);//LOW
}


int main(void)
{

	CCP=0xD8;  // 128kHz wdt オシレータ
	CLKMSR=1;
	CCP=0xD8;
	CLKPSR=0;
  
	DIDR0=0x09;//   1001 PB1,PB2以外は入力ピンなし（省電力)
	DDRB=_BV(PORTB0); //LED
	PUEB=0x00;// no pull up
	PRR=0x02;//ADC stop
	ACSR=0x80;//comparetor off
	//Timmer 125kHz
  	sleep_enable();
	#define RA 16
	#define THRESH_RATE 1
	old= getCount();
	thresh=0;
	char ledState=0;
	int16_t diff=0;
	char skipCount=0;

	while(1)
	{
		int16_t now=getCount();
		if(skipCount){
			skipCount--;
			old=now;
		}else{
			diff=(now-old)+((RA-1)*diff+RA/2)/RA;
			old=now;
			if(ledState){
				thresh=max(diff-THRESH_RATE*RA,thresh);
				if(diff<thresh){
					thresh+=2*THRESH_RATE*RA;
					ledState=0;
					diff=0;
					skipCount=3;
					ledOn();
				}
			}else{
				thresh=min(diff+THRESH_RATE*RA,thresh);
				if(diff>thresh){
					thresh-=2*THRESH_RATE*RA;
					ledState=1;
					ledOff();
					diff=0;
					skipCount=3;
				}
			}
		}
		//充電器に繋がれたので Power off
		if(PINB & _BV(PORTB2)){
			ledOff();
			cli();//割り込み関係なしに起きてくれるのでseiしない
			//7ISC0=0x00;
			EICRA=0;EIMSK=0x01;//enable INT0
			set_sleep_mode(SLEEP_MODE_PWR_DOWN);
			sleep_enable();
			sei();
			//Power Down sleep の前にINT0割り込み掛かるとINT0解除されて厄介
			//SEIとSLEEPの間に別命令が入らない事を保証する
			/*__asm__ __volatile__ ( \
				"SEI" "\n\t" \
				"SLEEP" "\n\t" \
				:: );
				*/
			sleep_cpu();
			EIMSK=0x00;//seep解除されても割り込みが走らない場合がある（マニュアルより）
		   
			sleep_disable();
			//充電器から外された(10Mプルダウン)か充電完了（0V直結）かをプルアップ抵抗で判定		   
			PUEB = _BV(PORTB2);
			while((PINB & _BV(PORTB2)) == 0 ){//pull up しても0と言う事は引き込みがある。
				ledOn();
			}
			//引き込みがないので、充電装置から外された
			PUEB = 0;
		}
	}
}

static void clampP(){
	DDRB|=_BV(PORTB1);//output
	PORTB &= ~_BV(PORTB1);//Low
}
static void freeP(void){
	DDRB &= ~ _BV(PORTB1);//input
}

static void countStart(){
	cli();
	GTCCR=0x81;//stop
	TCCR0B=0;
	TCNT0=0;
	TIFR0|=0x27;
	TIMSK0=_BV(ICIE0);//enable input caputre interrupt
	sleepFlag=true;
	sei();
	//ノイズキャンセルON 立ち上がりエッジ プリスケーラ:1 タイマーON
	TCCR0A=0;
	TCCR0C=0;
	TCCR0B=0xC1; // 0b1100 0001
	GTCCR=0x00;//start

}
static void countStop(){
	cli();
	TIMSK0=0;
	GTCCR=0x81;//stop
	TCCR0B=0x00; //timer stop
}
 
static void waitStart(){
	wdt_reset();
	sei();
	CCP=0xD8;
	WDTCSR=0xC1; //32ms
	set_sleep_mode(SLEEP_MODE_PWR_DOWN);
	sleep_enable();
	sleep_cpu();
	cli();
	//	wdt_disable(); 
	CCP=0xD8;
	WDTCSR=0x00; 
	sleep_disable();
}

 

static int16_t getCount(){
	clampP();
	waitStart();  
	freeP();
	countStart();
	set_sleep_mode(SLEEP_MODE_IDLE);
	while(sleepFlag)sleep_mode();
	countStop();
	return ICR0;
}