/**
 * @fileOverview LPC1769の物理ペリフェラルを制御するクラスを定義する。
 */
(function(){
var DEV=LPC1769;
var BCF=DEV._BCF;
var EE=DEV._EE;
var isUndef=MiMicLib.isUndef;
/**
 * LPC1769.Peripheral (Peripheral)クラスのコンストラクタ。
 * ペリフェラル識別子を元に、MCUに関連付けしたPeripheral インスタンスを生成する。
 * Peripheralクラスは、物理Peripheral（主に電源/クロックブロック単位）単位に操作インタフェイスを定義する。
 * PCLKSEL,PCONPレジスタを管理する。
 * このクラスは、抽象ペリフェラルクラスへ物理ペリフェラルの基本的な操作機能を提供する為のものであり、ユーザが直接使用することは（あまり）ない。
 * 関数はMiMicの管理しているペリフェラル（ENET）も操作することが出来るが、操作してしまうとMiMicRemoteMcuとのコネクションが破壊されるので、注意すること。
 * @name LPC1769.Peripheral
 * @constructor
 * @param {object as LPC1769.Mcu} i_mcu
 * インスタンスを結びつけるMcuオブジェクト。
 * @param {object as ペリフェラル識別子} i_phl
 * 生成するペリフェラルのペリフェラル識別子。この値は、LPC1769.PHLの要素である。
 * @param {object as associative array} i_opt
 * インスタンス生成と同時にsetOpt関数で設定する値。省略時は無視する。
 * 詳細はsetOpt関数を参照。
 * @example
 * //create GPIO peripheral
 * var mcu=new LPC1769.Mcu(“192.168.0.39”);
 * var phl=new LPC1769.Pheripheral(mcu,LPC1769.PHL.GPIO); 
 */
DEV.Peripheral=function(i_mcu,i_phl,i_opt)
{
	try{
		if(isUndef(i_phl)){
			throw new MiMicException(EE.INVALID_PHL);
		}
		this._mcu=i_mcu;
		this._phl=i_phl;
		//オプション設定するならする。
		if(!isUndef(i_opt)){
			this.setOpt(i_opt);
		}
	}catch(e){
		throw new MiMicException(e);
	}	
}
DEV.Peripheral.prototype=
{
	_PCLKSEL:[0x400FC1A8,0x400FC1AC],
	_PCONP:0x400FC0C4,
	_phl:null,
	_mcu:null,
	_cache:{
		pclk:0
	},
	/**
	 * BCフラグメントを生成して、_cacheを更新します。
	 * @private
	 */
	BCF_setOpt:function BCF_setOpt(i_opt,i_db)
	{
		try{
			var bc="";
			//pconp
			if(!isUndef(i_opt.power)){
				if(this._phl[2]==null){
					throw new MiMicException(EE.INVALID_CFG,"The pin does not support PCONP.");
				}
				//pinselAddrを得る
				bc+=BCF.setBit(this._PCONP,0x00000001,i_opt.power,this._phl[2],i_db);
			}
			//clock
			if(!isUndef(i_opt.clock)){
				if(this._phl[0]==null){
					throw new MiMicException(EE.INVALID_CFG,"The pin does not support PCLKSEL.");
				}
				//キャッシュ更新
				this._cache.pclk=i_opt.clock;
				bc+=BCF.setBit(this._PCLKSEL[this._phl[0]],0x00000003,i_opt.clock,this._phl[1],i_db);
			}
			return bc;
		}catch(e){
			throw new MiMicException(e);
		}		
	},
	/**
	 * ペリフェラルにオプションパラメータをセットする。
	 * 関数は、物理ペリフェラルのレジスタに、i_optで与えられる値を設定する。
	 * 関数は、レジスタの位置に合わせてパラメータ値を自動的にシフトする。	 
	 * @name LPC1769.Peripheral#setOpt
	 * @function
	 * @param {object} i_opt
	 * ペリフェラルピンコンフィグレーションのパラメタである。必要な値を格納した連想配列で指定する。
	 * 全ての値を省略することは出来ない。連想配列のメンバは以下の通り。
	 * <pre>{power:int,clock:int}</pre>
	 * <ul>
	 * <li>power:int -
	 * 1bitのint値。 PCONP? レジスタに指定する値。Chapter 4: LPC17xx Clocking and power controlを参照。
	 * </li>
	 * <li>clock:int - 
	 * 2bitのint値。PCLKSEL? レジスタに指定する値。Chapter 4: LPC17xx Clocking and power controlを参照。
	 * </li>
	 * @example 
	 * //set DAC power on
	 * var mcu=new LPC1769.Mcu(“192.168.0.39”);
	 * var phl=new LPC1769.Peripheral(mcu,LPCXpresso.PHL.ADC);
	 * phl.setOpt({power:1});	 
	 */
	setOpt:function setOpt(i_opt)
	{
		try{
			var db=new Array();
			var bc=this.BCF_setOpt(i_opt,db);
			if(bc.length==0){
				throw new MiMicException("i_opt is empty or invalid.");
			}
			//MiMicBCを生成して実行
			this._mcu.callMiMicWithCheck(bc+BCF.END,db);

		}catch(e){
			throw new MiMicException(e);
		}
		return;		
	},
	/**
	 * ペリフェラルのクロックを[Hz]単位で返す。
	 * クロックは、Table 42. Peripheral Clock Selection register bit valuesと、MCUのクロック(LPC1769.Mcuの提供する値)から計算する。
	 * 動作中のPLL0の変更には対応していない。注意すること。
	 * @name LPC1769.Peripheral#getPCLK
	 * @function
	 * @return {int}
	 * Hz単位のペリフェラルクロック
	 * @example
	 * var mcu=new LPC1769.Mcu(“192.168.0.39”);
	 * var phl=new LPC1769.Peripheral(mcu,LPCXpresso.PHL.PWM);
	 * alert(phl.getPCLK());
	 */
	getPCLK:function getPCLK()
	{
		try{
			//倍率変換テーブル
			var m=[4,1,2,0];
			var t=m[this._cache.pclk];
			var r;
			if(t==0){
				if(this._phl===DEV.PHL.CAN1 || this._phl===DEV.PHL.CAN2){
					r=this._mcu.getClockInfo().cclk/6;
				}else{
					r=this._mcu.getClockInfo().cclk/8;
				}
			}else{
				r=this._mcu.getClockInfo().cclk/t;
			}
			return Math.round(r);
		}catch(e){
			throw new MiMicException(e);
		}
	}
}

}());