<?php
class MiMic_LPC1769_Mcu
{
	private static function array2MimicDb(&$i_array)
	{
		$p="";
		for($i=0;$i<count($i_array);$i++){
			$p.=MiMicLib::hexout($i_array[$i],8);
		}
		return $p;
	}
	private static function getPinByFName($i_pintbl,$i_name)
	{
		for($i=0;i<count($i_pintbl);$i++){
			if($i_pintbl[$i]==null){
				continue;
			}
			if(MiMic_LPCXpresso1769::hasPinFunctionName($i_pintbl[$i],$i_name)){
				return $i_pintbl[$i];
			}
		}
		return null;
	}
	private static function getPinByFuncName($i_name)
	{
		$tbl=array(MiMic_LPCXpresso1769::P0,MiMic_LPCXpresso1769::P1,MiMic_LPCXpresso1769::P2,MiMic_LPCXpresso1769::P3,MiMic_LPCXpresso1769::P4);
		for($i=0;i<count($tbl);$i++){
			$pin=$this->getPinByFName($tbl[i],$i_name);
			if($pin!=null){
				return $pin;
			}
		}
		throw new MiMicException("pin function '".$i_name."' not found");
	}

	/**

	* PIN機能名から使用するペリフェラルシンボルを推定する。

	@private

	*/

	private static function pinFuncName2PhlName($i_pinfuncname)
	{
		//Pin function nameプレフィクスとペリフェラル名の対比表
		$TBL=array(
				'GPIO'=>'GPIO',
				'AD'=>'ADC',
				'DA'=>'DAC',
				'PWM'=>'PWM'
				);
		foreach ($TBL as $key => $value)
		{
			if($i_pinfuncname==$key){
				return $value;
			}
		}
		//見つからぬ。
		throw new MiMicException("Peripheral for ".$i_pinfuncname." not found.");
	}
	private $_mif=null;

	public function __construct($i_mimic_addr,$i_is_activate=true)
	{	
		$this->_Mcu_1($i_mimic_addr,$i_is_activate);
	}
	private function _Mcu_1($i_mimic_addr,$i_is_activate)
	{	
		//メンバの初期化.
		//リモートインタフェイスの取得.
		$this->_mif=new MiMicRemoteMcuInterface($i_mimic_addr);
		if($i_is_activate){
			$this->activate();
		}
	}
	public function isActive()
	{
		return $this->_mif->isConnected();
	}
	public function getClockInfo()
	{
		//CCLCK値(RemoteMCU側と合わせること。将来的にはactivateの時に決定する。).
		return array('cclk'=>100*1000*1000);
	}
	public function activate()
	{
		//既にアクティブならエラー。
		if($this->isActive()){
			throw new MiMicException("Already activated!");
		}
		//接続.
		$this->_mif->connect(this.callOnActivateChanged);
	}
	public function deactivate()
	{
		if(!$this->isActive()){
			throw new MiMicException("Already activated!");
		}
		$this->_mif->disconnect();
	}
	public function periodicUpdate()
	{
		$this->_mif->periodicUpdate();
	}

	public function callMiMic($i_bc,$i_db=null)
	{
		if(is_null($i_db)){
			return $this->_mif->execBc($i_bc);
		}else{
			return $this->_mif->execBc($i_bc.self::array2MimicDb($i_db));
		}
	}


	public function callMiMicWithCheck($i_bc,$i_db=null)
	{
		if(is_null($i_db)){
			$h=$this->callMiMic($i_bc);
			if((!isset($h))|| $h->result!=0x0){
				throw new MiMicException("Result=");
			}
		}else{
			
			$h=$this->callMiMic($i_bc,$i_db);
			if((!isset($h))|| $h->result!=0x0){
				throw new MiMicException("Result=");
			}
		}
		return $h;
	}


	private $_phl_holder=array();

	public function getPin($i_pin_id,$i_pin_function=null)
	{
		
		if(is_null($i_pin_function)){
			$i_pin_function=$i_pin_id;
			//pin_functionを持ってるPINを探す。
			$pin=self::getPinByFuncName($i_pin_function);
			//function名からペリフェラル名を得る。
			$phl_name=pinFuncName2PhlName($i_pin_function);
			//ピンコンストラクタとペリフェラルを使ってピンを生成。
			return $this->getPeripheral($phl_name,null)->getPin($pin,null);
		}else{
			//function名からペリフェラル名を得る。(PINシンボル変換を流用)
			$phl_name=self::pinFuncName2PhlName($i_pin_function);
			return $this->getPeripheral($phl_name,null)->getPin($i_pin_id,null);
		}
	}
	public function getPort($i_pins,$i_function_name)
	{
		//function名からペリフェラル名を得る。(PINシンボル変換を流用)
		$phl_name=self::pinFuncName2PhlName($i_function_name);
		return $this->getPeripheral($phl_name,null)->getPort($i_pins,null);
	}
	/**
	 *
	 * @param hash array[]
	 */
	public function getPeripheral($i_phl_symbol,$i_opt=null)
	{
		//ペリフェラルアイテムが生成済か確認
		if(!array_key_exists($i_phl_symbol,$this->_phl_holder))
		{
			
			//存在しなければPhlを生成。
			switch($i_phl_symbol){
				case 'GPIO':new MiMic_LPC1769_Gpio($this,$i_opt);break;
				case "ADC":new MiMic_LPC1769_Adc($this,$i_opt);break;
				case "PWM":new MiMic_LPC1769_Pwm($this,$i_opt);break;
				default:
					throw new MiMicException('Unknown peripheral symbol '.$i_phl_symbol);
			}
		}else{
			//2回目以降でi_optが設定されている？それはだめだよ。
			if($i_opt!=null){
				throw new MiMicException();
			}
		}

		//phlからregisterのコールバックがかかるはず。
		return $this->_phl_holder[$i_phl_symbol];
	}







	/**
	 * [forSystem]システム関数。MCU依存のペリフェラルオブジェクトを登録する。
	 @private
	 */
	public function registerPhl($i_phl,$i_symbol)
	{
		//登録済みのシンボルは登録できない。
		if(array_key_exists($i_symbol,$this->_phl_holder)){
			throw new MiMicException('Peripheral symbol '.$i_symbol.' is already exist on mcu.');
		}
		$this->_phl_holder[$i_symbol]=$i_phl;
		return;
	}
}

