/**
 * @fileOverview LPC1769の、DAコンバータペリフェラル、ピンの制御クラスを定義する。
 */
(function(){
var DEV=LPC1769;
var BCF=DEV._BCF;
var EE=DEV._EE;
var isUndef=MiMicLib.isUndef;
var isArray=MiMicLib.isArray;
var cloneAssoc=MiMicLib.cloneAssoc;
/**
 * LPCXPresso1769.Dac (Dac)クラスのコンストラクタ。
 * MCUに関連付けしたADペリフェラルを生成する。
 * DAペリフェラルは、MCUのDACペリフェラル全体を管理する。
 * #関数は、ADCRレジスタのPDN,BURSTを1にセットする。
 * #DACの設定タイミングの制御はハードウェア依存である。
 * @constructor
 * @name LPC1769.Dac
 * @param {object as LPC1769.Mcu} i_mcu
 * インスタンスを結びつけるMcuオブジェクト。
 * @param {associative array} i_opt
 * #インスタンス生成と同時にsetOpt関数で設定する値。省略時は、{phl:{clock:0}}とみなす。
 * #詳細はsetOpt関数を参照。 
 * @example
 * //create DA (logical)pheripheral
 * var mcu=new LPC1769.Mcu(“192.168.0.39”);
 * var ad=new LPC1769.Dac(mcu); 
 */
DEV.Dac=function Dac(i_mcu,i_opt)
{
	try{
		this._mcu=i_mcu;
		//PHL生成。
		this._phl=new DEV.Peripheral(i_mcu,DEV.PHL.DAC);
		//設定値のロード
		var opt=isUndef(i_opt)?{phl:{}}:
		{//i_optある。
			phl:isUndef(i_opt.phl)?{}:cloneAssoc(i_opt.phl),
		};
		//デフォルト値設定
		if(isUndef(opt.phl.clock)){opt.phl.clock=0;};

		//初期化。
		var bc="";
		var db=new Array();
		bc+=this.BCF_setOpt(opt,db);
		//
		this._mcu.callMiMicWithCheck(bc+BCF.END,db);
		//ペリフェラルをMCUに登録
		this._mcu.registerPhl(this,"DAC");
	}catch(e){
		throw new MiMicException(e);
	}

}
DEV.Dac.prototype=
{
	_DACR:0x4008C000,
	_DACCTRL:0x4008C004,
	_DACCNTVAL:0x4008C008,
	_phl:null,
	_mcu:null,

	BCF_setOpt:function BCF_setOpt(i_opt,i_db)
	{
		try{
			var bc="";
			if(!isUndef(i_opt.phl)){
				bc+=this._phl.BCF_setOpt(i_opt.phl,i_db);
			}
			return bc;
		}catch(e){
			throw new MiMicException(e);
		}
	},
	/**
	 * DACペリフェラルに、i_optのオプション値を設定する。
	 * @name LPC1769.Dac#setOpt
	 * @function
	 * @param {associative array} i_opt
	 * DACペリフェラルのコンフィグレーションパラメタである。必要な値を格納した連想配列で指定する。
	 * 全ての値を省略することは出来ない。連想配列のメンバは以下の通り。
	 * <pre>{i_opt:associative array}</pre>
	 * <ul>
	 * <li>phl - LPC1769.Peripheral#setOpt関数のi_optに渡すパラメタである。</li>
	 * </ul>
	 * @example
	 * //set DA clock param
	 * //create DA (logical)pheripheral
	 * var mcu=new LPC1769.Mcu(“192.168.0.39”);
	 * var da=new LPC1769.Dac(mcu);
	 * da.setOpt(phl:{clock:0});
	 */
	setOpt:function setOpt(i_opt)
	{
		try{
			var db=new Array();
			var bc=this.BCF_setOpt(i_opt,db);
			this._mcu.callMiMicWithCheck(bc+BCF.END,db);
		}catch(e){
			throw new MiMicException(e);
		}
	},	
	/**
	 * DA機能を持つピンを取得する。
	 * ピン識別子で指定されるピンをDAペリフェラルと結合して、DacPinを生成する。
	 * 関数は、DacPinオブジェクトのコンストラクタをコールして、DacPinを生成する。失敗すると、例外をスローする。
	 * 生成ルールについての詳細は、DacPinを参照。
	 * @name LPC1769.Dac#getPin
	 * @function
	 * @param {object as ピン識別子} i_pin
	 * Dac機能を割り当てるPINの識別子である。値は、LPC1769.Pn[m]のメンバ変数である。
	 * @param {associative array} i_opt
	 * DacPinのコンストラクタに渡すオプション値。省略時はundefinedである。詳細はLPC1769.DacPinを参照。
	 * @return {object as LPC1769.DacPin}
	 * LPC1769.DacPinクラスのオブジェクトである。
	 * @example
	 * //create DacPin
	 * var mcu=new LPC1769.Mcu("192.168.0.39");
	 * var dac=new LPC1769.Dac(mcu);
	 * var dapin=dac.getPin(LPC1769.P0[23]);
	 */
	getPin:function getPin(i_pin,i_opt)
	{
		try{
			return new DEV.DacPin(this,i_pin,i_opt);
		}catch(e){
			throw new MiMicException(e);
		}
	},
	/**
	 * DA機能を持つポート(Pin集合)を取得する。
	 * ピン識別子で指定されるピンのセットをDAペリフェラルと結合して、DacPortを生成する。
	 * 関数は、DacPortのコンストラクタをコールする。
	 * 生成ルールについては、DacPort関数を参照すること。
	 * LPC1769はDACピンが1ピンしかないため、LPC1769.DacPinとの差異は無い。
	 * @name LPC1769.Dac#getPort
	 * @function
	 * @param {array[ピン識別子]} i_pin
	 * AD機能を割り当てるPINの識別子の配列である。値は、LPC1769.Pn[m]のメンバ変数である。
	 * @param {associative array} i_opt
	 * AdcPortのコンストラクタに渡すオプション値。省略時はundefinedである。詳細はLPCXpresso1769.DacPortを参照。
	 * @return {object as LPC1769.DacPort}
	 * LPC1769.DacPortクラスのオブジェクトである。
	 * @example
	 * //create DacPort that has 1 pins.
	 * var mcu=new LPC1769.Mcu("192.168.0.39");
	 * var dac=new LPC1769.Dac(mcu);
	 * var port=dac.getPort([LPC1769.P0[23],LPC1769.P0[24]]);
	 */
	getPort:function getPort(i_pins,i_opt)
	{
		try{
			return new DEV.DacPort(this,i_pins,i_opt);
		}catch(e){
			throw new MiMicException(e);
		}
	},
	/**
	 * DACRのBiasフィールドの値を更新するBC
	 * @param i_val
	 * 0 or 1
	 * @private
	 */
	BCF_setBias:function BCF_setBias(i_mask,i_val,i_db)
	{
		try{
			return BCF.setBit(this._DACR,i_mask,i_val*i_mask,0,i_db);
		}catch(e){
			throw new MiMicException(e);
		}
	},
	/**
	 * DACRのVALUEフィールドを更新するBC
	 * @private
	 */
	BCF_setValue:function BCF_setValue(i_val,i_db)
	{
		return BCF.setBit(this._DACR,0x03ff,i_val,6,i_db)
	}
}



/**
 * DA pinからDAInfoを取得
 * @private
 */
function makeDacPinInfoArray(i_pins)
{
	try{
		var ret=new Array();
		for(var i=0;i<i_pins.length;i++){
			//pinの完全な機能名を得る。(得られれば機能がある。)
			var func_name=DEV.completePinFunctionName(i_pins[i],"AOUT");
			//portとbitを得る(AD0だけしか管理しないよ)
			ret.push({
				port:0,
				pin_sel:DEV.getPinSelByFunctionName(i_pins[i],func_name)
			});
		};
		return ret;
	}catch(e){
		throw new MiMicException(e);	
	}
}
/**
 * LPC1769.DacPort (DacPort)クラスのコンストラクタ。複数のDAピンを一括で制御するときに使用する。
 * Dacペリフェラルオブジェクトにピン識別子の配列で指定されたピン集合を関連付けて、DA機能を持つポートを生成する。
 * 関数は、ピン識別子を元に、そのピンがDA機能に接続できるかを調べる。全てのピンにDA機能を割り当てられない場合、例外が発生する。どのピンにDA機能が割り当てられるかは、MCUのスペックシートを参照すること。
 * LPC1769は1つのDAピンのみを持つため、portではなくpinを使うべきである。
 * @constructor
 * @name LPC1769.DacPort
 * @param {object as LPC1769.Dac} i_adc
 * インスタンスを結びつけるAdcオブジェクト。
 * @param {array[pin識別子]} i_pins
 * ピン識別子の配列。指定できるのは、LPC1769.P?[?]である。順番は、このインスタンスの返す値の順序に影響する。
 * @param {associative array} i_opt
 * setOpt関数のi_optに渡すパラメタである。省略可能。省略時は{pin:{sel:undefined},bias:0}を設定する。
 * 詳細はsetOpt関数を参照。 pin.selを省略(undefined)した場合、関数はpin.selの値をPin情報から自動的に決定する。
 * @example
 * //create [AOUT]
 * var mcu=new LPC1769.Mcu(“192.168.0.39”);
 * var adc=new LPC1769.Dac(mcu);
 * var port=new LPC1769.DacPort(dac,[LPC1769.P0[26]]); 
 */
DEV.DacPort=function DacPort(i_adc,i_pins,i_opt)
{
	try{
		this._dac=i_adc;
		//Pin情報配列を生成
		var pininfo=makeDacPinInfoArray(i_pins);
		//ポートの生成
		this._port=new DEV.Port(i_adc._mcu,i_pins);
		//ピンオプションの生成
		var opt={};
		if(isUndef(i_opt)){
			opt.pin=this._port.clonePinOptAssoc({});
			opt.bias=0;
		}else{
			opt.pin =this._port.clonePinOptAssoc(isUndef(i_opt.pin)?{}:i_opt.pin);
			opt.bias=isUndef(i_opt.bias)?0:i_opt.bias;
		};
		//pinselの自動設定
		for(var i=0;i<pininfo.length;i++){
			if(isUndef(opt.pin[i].sel)){
				opt.pin[i].sel=pininfo[i].pin_sel;
			}
		}
		//ピンオプションの設定
		this.setOpt(opt);
	}catch(e){
		throw new MiMicException(e);
	}
}
DEV.DacPort.prototype=
{
	_dac:null,
	_port:null,
	/**
	 * ポートにオプション値を設定する。
	 * 設定可能な値は、LPC1769.DacPin#setOptと同じである。
	 * @name LPC1769.DacPort#setOpt
	 * @function
	 * @param {associative array | array[associative array]} i_opt
	 * DAピンのコンフィグレーションパラメタである。必要な値を格納した連想配列、またはその配列を指定する。
	 * 全てのピンに同じパラメータを指定する場合は、連装配列で指定する。個別に設定する場合は、連装配列を配列にして指定する。
	 * <pre>{i_opt:associative array}</pre>
	 * <ul>
	 * <li>pin(option)</li>
	 * <li>bias(option)</li>
	 * </ul>
	 * パラメータの詳細は、LPC1769.DacPin#setOptを参照。
	 * @example
	 * //ポートを構成する全てのピンに同じパラメータを設定する場合
	 * setOpt({pin:{v1},bias:v1});
	 * //ポートを構成するピンに個々にパラメータを設定する場合
	 * setOpt({pin:[{v1},{v2}],bias:[v1,v2...]});
	 */	
	setOpt:function setOpt(i_opt)
	{
		try{
			var db=new Array();
			//BCの生成
			var bc="";
			//i_optの展開
			if(!isUndef(i_opt.pin)){
				bc+=this._port.BCF_setOpts(i_opt.pin,db);
			}
			//DACR:bit16
			if(!isUndef(i_opt.bias)){
				//DAは1ポートだけなので、固定値
				if(isArray(i_opt.bias)){
					if(this._port.pins.length!=i_opt.bias.length){
						throw new MiMicException(DEV._EE.INVALID_ARG);
					}
					bc+=this._dac.BCF_setBias(0x00010000,i_opt.bias[0],db);
				}else{
					bc+=this._dac.BCF_setBias(0x00010000,i_opt.bias,db);
				}
			}			
			this._dac._mcu.callMiMicWithCheck(bc+BCF.END,db);
			return;
		}catch(e){
			throw new MiMicException(e);
		}
	},
	/**
	 * ポートへ値を出力する。
	 * @name LPC1769.DacPort#setValues
	 * @function
	 * @param {array[int]} i_values
	 * 10bitのDA変換値の配列である。値の意味は、UM10360 Chapter 30: LPC17xx Digital-to-Analog Converter (DAC)を参照。
	 * 値の順番は、コンストラクタで指定したピン配列の順序と同じである。
	 * @example
	 * //set values of AOUT
	 * var mcu=new LPC1769.Mcu("192.168.0.39");
	 * var pin=mcu.getPort("DA",[LPC1769.P0[26]]);
	 * pin.setValues([255]));
	 */	
	setValues:function setValues(i_values)
	{
		try{
			if(this._port.pins.length!=i_values.length){
				throw new MiMicException("Invalid number of values.");
			}
			//メモリへ値設定
			var db=new Array();
			var bc="";
			for(var i=0;i<this._port.pins.length;i++){
				bc+=this._dac.BCF_setValue(i_values[i],db);
			}
			this._dac._mcu.callMiMicWithCheck(bc+BCF.END,db);
			return;
		}catch(e){
			throw new MiMicException(e);
		}
	}
}

/**
 * LPC1769.DacPin (DacPin)クラスのコンストラクタ。
 * Dacペリフェラルオブジェクトにピン識別子で指定されたピンを関連付けて、DA機能を持つピンを生成する。
 * 関数は、ピン識別子を元に、そのピンがDA機能に接続できるかを調べる。ピンにDA機能を割り当てられない場合、例外が発生する。どのピンにDA機能が割り当てられるかは、MCUのスペックシートを参照すること。
 * @constructor
 * @name LPC1769.DacPin
 * @param {object as LPC1769.Dac} i_dac
 * インスタンスを結びつけるDacオブジェクト。
 * @param {object as pin識別子} i_pin
 * ピン識別子。指定できるのは、LPCXpresso1796.P?[?]である。
 * @param {associative array} i_opt
 * setOpt関数のi_optに渡すパラメタである。省略可能。省略時は{pin:{sel:undefined},bias:0}を設定する。
 * 詳細はsetOpt関数を参照。 pin.selを省略(undefined)した場合、関数はpin.selの値をPin情報から自動的に決定する。
 * @example
 * //create AOUT
 * var mcu=new LPC1769.Mcu(“192.168.0.39”);
 * var dac=new LPC1769.Dac(mcu);
 * var dacpin=new  LPC1769.DacPin(dac,LPC1769.P0[26]); 
 */
DEV.DacPin=function DacPin(i_dac,i_pin,i_opt)
{
	try{
		this._port=new DEV.DacPort(i_dac,[i_pin],i_opt);
	}catch(e){
		throw new MiMicException(e);
	}
}

DEV.DacPin.prototype=
{
	_port:null,
	/**
	 * 数値をDA変換してピンに出力する。
	 * @name LPC1769.DacPin#setValue
	 * @function
	 * @return {int}
	 * 10bitのAD変換値。値の意味は、UM10360 Chapter 30: LPC17xx Digital-to-Analog Converter (DAC)を参照。
	 * @example
	 * //set value of DA0 pin
	 * var mcu=new LPC1769.Mcu("192.168.0.39");
	 * var pin=mcu.getPin("AOUT");
	 * pin.setValue(100);
	 */
	setValue:function setValue(i_value)
	{
		try{
			this._port.setValues([i_value]);
		}catch(e){
			throw new MiMicException(e);
		}
	},
	/**
	 * DAピンにオプション値を設定する。
	 * @name LPC1769.DacPin#setOpt
	 * @function
	 * @param {associative array} i_opt
	 * DAピンのコンフィグレーションパラメタである。必要な値を格納した連想配列で指定する。
	 * 全ての値を省略することは出来ない。連想配列のメンバは以下の通り。
	 * <pre>{i_opt:associative array}</pre>
	 * <ul>
	 * <li>pin(option) - Pinパラメータ。詳細は、LPC1769.Pin#setOptを参照。</li>
	 * <li>bias(option) - bias値。0 または1であること。</li>
	 * </ul>
	 * @example
	 * //set value of DA0 pin
	 * var mcu=new LPC1769.Mcu("192.168.0.39");
	 * var pin=mcu.getPin("AOUT");
	 * pin.setOpt({bias:0});
	 */	
	setOpt:function setOpt(i_opt)
	{
		try{
			this._port.setOpt(i_opt);
		}catch(e){
			throw new MiMicException(e);
		}
	}
}
	


}());
