<?php
class MiMic_LPC1769_Adc
{
	const _AD0CR=0x40034000;
	private static $_AD0DR=array(0x40034010,0x40034014,0x40034018,0x4003401C,0x40034020,0x40034024,0x40034028,0x4003402C);
	private $_phl=null;
	public $_mcu=null;

	protected function BCF_setOpt($i_opt,&$i_db)
	{
		$bc="";
		if(isset($i_opt['phl'])){
			$bc.=$this->_phl->BCF_setOpt($i_opt['phl'],&$i_db);
		}
		return $bc;
	}

	public function BCF_setSels($i_mask,$i_val,&$i_db)
	{
		return MiMic_LPC1769::BCF_setBit(self::_AD0CR,$i_mask,$i_val*$i_mask,0,$i_db);
	}

	public function BCF_getAD0DR($i_ch,&$i_db)
	{
		$s=MiMic_LPC1769::BCF_getMem(self::$_AD0DR[$i_ch],$i_db);
		return $s;
	}
	/*
		var opt=isUndef(i_opt)?{}:cloneAssoc(i_opt);
		opt.sel=1;//ADxCRの値
		opt.pin=isUndef(opt.pin)?{}:cloneAssoc(opt.pin);
		//設定が無ければ、ピンセレクタを自動に設定
		if(isUndef(opt.pin.sel)){opt.pin.sel=this._PINSEL_AUTO_DETECT;}	 
	 */
	public function __construct($i_mcu,$i_opt=null)
	{
		$this->_mcu=$i_mcu;
		//PHL生成。
		$this->_phl=new MiMic_LPC1769_Peripheral($i_mcu,MiMic_LPC1769::$PHL['ADC'],null);
		//設定値のロード
		$opt=is_null($i_opt)?array():$i_opt;
		$opt['phl']=isset($opt['phl'])?$opt['phl']:array();
		//デフォルト値設定
		if(!isset($opt['phl']['power'])){$opt['phl']['power']=1;};
		//初期化。
		$bc="";
		$db=array();
		$bc.=$this->BCF_setOpt($opt,$db);
		//0x00210000(PDN,BURSTを1)
		$bc.=MiMic_LPC1769::BCF_setMem(self::_AD0CR,0x00200400,$db);
		$bc.=MiMic_LPC1769::BCF_setMem(self::_AD0CR,0x00210400,$db);
		//
		$this->_mcu->callMiMicWithCheck($bc.MiMic_LPC1769::_BCF_END,$db);
		//ペリフェラルをMCUに登録
		$this->_mcu->registerPhl($this,"ADC");
	}
	public function setOpt($i_opt)
	{
		$db=array();
		$bc=$this->BCF_setOpt($i_opt,$db);
		$this->_mcu->callMiMicWithCheck($bc+LPC1769::_BCF_END,$db);
	}

	public function getPin($i_pin,$i_opt=null)
	{
		return new MiMic_LPC1769_AdcPin($this,$i_pin,$i_opt);
	}
	public function getPort($i_pins,$i_opt=null)
	{
		return new MiMic_LPC1769_AdcPort($this,$i_pins,$i_opt);
	}

}





class MiMic_LPC1769_AdcPort

{

	private static function  pin2AdcPinInfo($i_pin)
	{
		//pinの完全な機能名を得る。(得られれば機能がある。)
		$func_name=MiMic_LPC1769::completePinFunctionName($i_pin,'AD');
		//portとbitを得る(AD0だけしか管理しないよ)
		$a=preg_split("/[\s.]+/",substr($fn,2));
		return array('port'=>0,'ch'=>intval($a[1]),'pin_sel'=>MiMic_LPC1769::getPinSelByFunctionName($i_pin,$func_name));
	}
	const _PINSEL_AUTO_DETECT=0x0fffffff;
	private $_pins;
	private $_adc;
	private $_port;
	private $_port_no;
	private $_adcr_mask;
	public function __construct($i_adc,$i_pins,$i_opt=null)
	{
		$this->_adc=$i_adc;
		//ピンセットを取得
		$this->_pins=array();

		//pinに変換する。
		for($i=0;$i<count($i_pins);$i++){
			array_push($this->_pins,self::pin2AdcPinInfo($i_pins[$i]));
		}
		//pinが全て同じポートに所属しているか確認
		$p=$this->_pins[0]['port'];

		for($i=1;$i<count($this->_pins);$i++){
			if($p!=$this->_pins[$i]['port']){
				throw new MiMicException("Invalid pin combination.");
			}
		}

		//ポートの生成
		$this->_port=new MiMic_LPC1769_Port($i_adc->_mcu,$i_pins,null);
		$this->_port_no=$p;

		//AD0CR用のマスクを生成。

		$this->_adcr_mask=0;

		for($i=0;$i<count($this->_pins);$i++){

			$this->_adcr_mask|=(0x1<<$this->_pins[$i]['ch']);

		}

		//ピンオプションの複製
		$opt=is_null($i_opt)?array():$i_opt;
		if(!isset($opt['pin'])){
			$opt['pin']=array();
		}
		$opt['sel']=1;//ADxCRの値
		//設定が無ければ、ピンセレクタを自動に設定
		if(!isset($opt['pin']['sel'])){$opt['pin']['sel']=self::_PINSEL_AUTO_DETECT;}
		//ピンオプションの設定
		$this->setOpt($opt);
	}

	public function setOpt($i_opt)
	{
		$db=array();
		//BCの生成
		$bc="";
		//i_optの展開
		if(isset($i_opt['pin'])){
			$optset=array();
			for($i=0;$i<count($this->_pins);$i++){
				//pinselが_PINSEL_AUTO_DETECTならばauto。そうでなければundefinedも含めて設定
				$s=($i_opt['pin']['sel']==self::_PINSEL_AUTO_DETECT)?$this->_pins[$i]['pin_sel']:$i_opt['pin']['sel'];
				$optset[$i]=array('sel'=>$s,'mode'=>$i_opt['pin']['mode'],'od'=>$i_opt['pin']['od']);
			}
			//portの設定
			$bc.=$this->_port->BCF_setOpts($optset,$db);
		}

		//隠し。ADxCR
		if(isset($i_opt['sel'])){
			$bc.=$this->_adc->BCF_setSels($this->_adcr_mask,$i_opt['sel'],$db);
		}
		$this->_adc->_mcu->callMiMicWithCheck($bc.MiMic_LPC1769::_BCF_END,$db);
		return;
	}

	//
	//GetValues
	//
	private function BCF_getValues(&$i_db)
	{
		//メモリから値取得
		$bc="";
		for($i=0;$i<count($this->_pins);$i++){
			$bc.=$this->_adc->BCF_getAD0DR($this->_pins[$i]['ch'],$i_db);
		}
		return $bc;
	}

	private function PARSE_getValues($i_result)
	{
		
		//値の整形
		$r=array();
		for($i=0;$i<count($this->_pins);$i++){
			$r[$i]=(($i_result->stream[$i]>>4)&0x00000fff);
		}
		return $r;
	}

	public function getValues()
	{
		//メモリから値取得
		$db=array();
		$bc=$this->BCF_getValues($db);
		$ret=$this->_adc->_mcu->callMiMicWithCheck($bc.MiMic_LPC1769::_BCF_END,$db);
		return $this->PARSE_getValues($ret);
	}
}
class MiMic_LPC1769_AdcPin
{
	protected $_aport;
	public function __construct($i_adc,$i_pin,$i_opt=null)
	{
		$this->_aport=new MiMic_LPC1769_AdcPort($i_adc,array($i_pin),$i_opt);
	}
	public function getValue()
	{
		$v=$this->_aport->getValues();
		return $v[0];
	}
	public function setOpt($i_opt)
	{
		$this->_aport->setOpt($i_opt);
	}
}
