/**
 * @fileOverview LPC1769のポート(ピンセット)を制御するクラスを定義する。
 */

(function(){
var DEV=LPC1769;
var BCF=DEV._BCF;
var EE=DEV._EE;
var isUndef=MiMicLib.isUndef;

/**
 * @private
 * レジスタの内容
 */
var REG={
	_PINSEL:[0x4002C000,0x4002C004,0x4002C008,0x4002C00C,0x4002C010,null,null,0x4002C0C0,null,0x4002C024,0x4002C028],
	_PINMODE:[0x4002C040,0x4002C044,0x4002C048,0x4002C04C,0x4002C050,0x4002C054,0x4002C058,0x4002C05C,null,0x4002C064],
	_PINMODE_OD:[0x4002C068,0x4002C06C,0x4002C070,0x4002C074,0x4002C078],
};
/**
 * LPCXPresso1769.Port (Port)クラスのコンストラクタ。
 * ピン識別子を元に、MCUに関連付けたPortインスタンスを生成する。
 * Portクラスは、複数の物理ピンをまとめて、操作インタフェイスを定義する。
 * PINSEL,PINMODE,PINMODE_ODレジスタを管理する。
 * @name LPC1769.Port
 * @constructor
 * @param {object as LPC1769.Mcu} i_mcu
 * インスタンスを結びつけるMcuオブジェクト。
 * @param {array[object as ピン識別子]} i_pin
 * ポートを構成するピンの配列。
 * @param {array[object as associative array]} i_opt
 * インスタンス生成と同時にsetOpt関数で設定する値。省略時は無視する。
 * 詳細はsetOpt関数を参照。
 * このクラスは、上位クラスへピンの基本的な操作機能を提供する為のものであり、ユーザが直接使用することは（あまり）ない。
 * この関数は、MiMicの管理しているピン（ENET_?）も操作することが出来るが、操作してしまうとMiMicRemoteMcuとのコネクションが破壊されるので、注意すること。
 * @example
 * //create pin instance at P0[0]
 * var mcu=new LPC1769.Mcu(“192.168.0.39”);
 * var port=new LPC1769.Port(mcu,[LPCXpresso.P0[0]]);
 */
DEV.Port=function Port(i_mcu,i_pins,i_opts)
{
	try{
		this._mcu=i_mcu;
		this._pininfo=new Array();
		//ピン情報に変換
		for(var i=0;i<i_pins.length;i++){
			this._pininfo.push(DEV.getPinRegInfo(i_pins[i]));
		}
		if(!isUndef(i_opts)){
			this.setOpts(i_opts);
		}
	}catch(e){
		throw new MiMicException(e);
	}		
}

DEV.Port.prototype=
{
	_mcu:null,
	/**
	 * 複数のピン設定をレジスタごとにまとめたBCを生成する。
	 @private
	 */
	BCF_setOpts:function BCF_setOpts(i_opts,i_db)
	{
		try{
			//10/5レジスタ分のワーク領域を作る。
			var d={
				selr:[0,0,0,0,0,0,0,0,0,0],
				selr_mask:[0,0,0,0,0,0,0,0,0,0],
				modr:[0,0,0,0,0,0,0,0,0,0],
				modr_mask:[0,0,0,0,0,0,0,0,0,0],
				odr:[0,0,0,0,0],
				odr_mask:[0,0,0,0,0]};
	
			//pinsとoptsの数は同じだよね？
			if(this._pininfo.length!=i_opts.length){
				throw new MiMicException();
			}
			
			//レジスタ値、マスクの生成
			for(var i=0;i<i_opts.length;i++)
			{
				var pi=this._pininfo[i];
				var opt=i_opts[i];
				if(!isUndef(opt.sel))
				{
					d.selr[pi.s]|=(opt.sel<<pi.smb);
					d.selr_mask[pi.s]|=(0x3<<pi.smb);
				}
				if(!isUndef(opt.mode))
				{
					d.modr[pi.m]|=(opt.mode<<pi.smb);
					d.modr_mask[pi.m]|=(0x3<<pi.smb);
				}
				if(!isUndef(opt.od))
				{
					d.odr[pi.o]|=(opt.od<<pi.ob);
					d.odr_mask[pi.o]|=(0x1<<pi.ob);
				}
			}
			//BCFを生成
			var bc="";
			for(var i=0;i<10;i++){
				if(d.selr_mask[i]!=0x0){
					bc+=BCF.setBit(REG._PINSEL[i],d.selr_mask[i],d.selr[i],0,i_db);
				}
				if(d.modr_mask[i]!=0x0){
					bc+=BCF.setBit(REG._PINMODE[i],d.modr_mask[i],d.modr[i],0,i_db);
				}
			}
			for(var i=0;i<5;i++){
				if(d.odr_mask[i]!=0x0){
					bc+=BCF.setBit(REG._PINMODE_OD[i],d.odr_mask[i],d.odr[i],0,i_db);
				}
			}
			return bc;
		}catch(e){
			throw new MiMicException(e);
		}
	},
	/**
	 * ポートにオプションパラメータをセットする。
	 * 関数は、ポートを構成するピンに、ピンオプション配列の値を個別に設定する。
	 * @name LPC1769.Port#setOpts
	 * @function
	 * @param {array[object as associative array]} i_opts
	 * ピンコンフィグレーションのパラメタの配列である。個々の要素は、ピンオプションである。ピンオプションの構造は、Pin#setOptを参照。
	 * 配列の要素数は、ポートを構成するピンの数と同じでなければならない。
	 * @example
	 * //set GPIO,mode=1,open drain=0
	 * var mcu=new LPC1769.Mcu(“192.168.0.39”);
	 * var port=new LPC1769.Port(mcu,[LPCXpresso.P2[3],LPCXpresso.P2[4]]);
	 * port.setOpts([{sel:0,mode:1,od:0},{sel:0,mode:1,od:0}]);	
	 */	
	setOpts:function setOpts(i_opts)
	{
		try{
			var db=new Array();
			var bc=this.BCF_setOpts(i_opts,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;
	}	
}

}());