/**
 * @fileOverview LPCXpresso1769の、GPIOペリフェラル、ピンの制御クラスを定義する。
 */

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

/**
 * LPCXPresso1769.Gpio (Gpio)クラスのコンストラクタ。
 * MCUに関連付けしたGpioペリフェラルを生成する。
 * GPIOペリフェラルは、物理的には存在しない仮想ペリフェラルである。GPIOを集中管理するために定義している。
 * @name LPCXpresso1769.Gpio
 * @constructor
 * @param {object as LPCXpresso1769.Mcu} i_mcu
 * インスタンスを結びつけるMcuオブジェクト。
 * @param {oject as associative array} i_opt
 * 常に無視する。省略すること。
 * @example
 * //create GPIO (logical)pheripheral
 * var mcu=new LPCXpresso1769.Mcu(“192.168.0.39”);
 * var gpio=new LPCXpresso1769.Gpio(mcu);
 */
DEV.Gpio=function Gpio(i_mcu,i_opt)
{
	try{
		this._mcu=i_mcu;
		i_mcu.registerPhl(this,"GPIO");
	}catch(e){
		throw new MiMicException(e);
	}
}
DEV.Gpio.prototype={
	_FIO_DIR :[0x2009C000,0x2009C020,0x2009C040,0x2009C060,0x2009C080],
	_FIO_PIN :[0x2009C014,0x2009C034,0x2009C054,0x2009C074,0x2009C094],
	_FIO_SET :[0x2009C018,0x2009C038,0x2009C058,0x2009C078,0x2009C098],
	_FIO_CLR :[0x2009C01C,0x2009C03C,0x2009C05C,0x2009C07C,0x2009C09C],
	_FIO_MASK:[0x2009C010,0x2009C030,0x2009C050,0x2009C070,0x2009C090],
	_mcu:null,
	/**
	 * ピン用のBCF生成関数
	 * @private
	 */
	BCF_setDir:function BCF_setDir(i_ch,i_bit,i_dir,i_db)
	{
		try{
			return BCF.setBit(this._FIO_DIR[i_ch],0x00000001,i_dir,i_bit,i_db);
		}catch(e){
			throw new MiMicException(e);
		}
	},
	BCF_setValue:function BCF_setValue(i_ch,i_bit,i_val,i_db)
	{
		/**
		 * GPIOレジスタにセットするBC
		SGET #0;//GPIOの値レジスタアドレス
		SGET #1;//GPIOのMASKレジスタアドレス
		SGET #2;//MASKレジスタの値
		MPUT #2,#1;//MASK設定
		LD #2,0xffffffff
		MPUT #2,#0;//値セット
		* @private
		*/
		try{
			if(i_val){
				i_db.push(this._FIO_SET[i_ch],this._FIO_MASK[i_ch],~(0x00000001<<i_bit));
			}else{
				i_db.push(this._FIO_CLR[i_ch],this._FIO_MASK[i_ch],~(0x00000001<<i_bit));
			}
			return "EA00EA01EA02DF0201FB02ffffffffDF0200";
		}catch(e){
			throw new MiMicException(e);
		}
	},
	/**
	 * @private
	 */
	BCF_getValue:function BCF_getValue(i_ch,i_bit,i_db)
	{
		/*GPIOレジスタからとってくるBC
		SGET #0;//GPIOの値レジスタアドレス
		SGET #1;//GPIOのMASKレジスタアドレス
		SGET #2;//MASKレジスタの値
		MSET #2,#1;//MASK設定
		MGET #3,#0;//値取得
		SPUT #3;//SPUT
		 */
		try{
			i_db.push(this._FIO_PIN[i_ch],this._FIO_MASK[i_ch],~(0x00000001<<i_bit));
			return "EA00EA01EA02DF0201DB0300EE03";
		}catch(e){
			throw new MiMicException(e);
		}		
	},
	/**
	 * GPIO機能を持つピンを取得する。
	 * ピン識別子で指定されるピンをGPIOペリフェラルと結合して、GpioPinを生成する。
	 * 関数は、LPCXpresso1769.GpioPinクラスのコンストラクタをコールして、GpioPinを生成する。失敗すると、例外をスローする。
	 * 生成ルールについての詳細は、LPCXpresso1769.GpioPinを参照。
	 * @name LPCXpresso1769.Gpio.getPin
	 * @function
	 * @param {object as ピン識別子} i_pin
	 * GPIO機能を割り当てるPINの識別子である。
	 * @param {object as associative array} i_opt
	 * GpioPinのコンストラクタに渡すオプション値を指定する。省略可能。省略時はundefinedとみなす。詳細はGpioPinのコンストラクタを参照。
	 * @return {object as GpioPin}
	 * GpioPinクラスのオブジェクトである。
	 * @example
	 * //create GpioPin direction=out
	 * var mcu=new LPCXpresso1769.Mcu("192.168.0.39");
	 * var gpio=new LPCXpresso1769.Gpio(mcu);
	 * var pin=gpio.getPin(LPCXpresso1769.P0[0],{dir:1});
	 */
	getPin:function getPin(i_pin,i_opt)
	{
		try{
			return new DEV.GpioPin(this,i_pin,i_opt);
		}catch(e){
			throw new MiMicException(e);
		}
	}

}

/**
 * LPCXPresso1769.GpioPin (GpioPin)クラスのコンストラクタ。
 * Gpioペリフェラルオブジェクトにピン識別子で指定されたピンを関連付けて、GPIO機能を持つピンを生成する。
 * 関数は、ピン識別子を元に、そのピンがGPIO機能に接続できるかを調べる。ピンにGPIO機能を割り当てられない場合、例外が発生する。どのピンにGPIO機能が割り当てられるかは、MCUのスペックシートを参照すること。
 * ピンがGPIO機能を持たない場合、例外が発生する。
 * @name LPCXpresso1769.GpioPin
 * @constructor
 * @param i_gpio
 * インスタンスを結びつけるGpioオブジェクト。
 * @param {object as pin識別子} i_pin
 * ピン識別子。指定できるのは、LPCXpresso1796.P?[?]である。
 * @param i_opt
 * setOpt関数のi_optに渡すパラメタ。省略可能。
 * 省略時は、{pin:{sel:auto}}を使用する。autoは関数が自動的に決定PINSEL値である。
 * 詳細はsetOpt関数を参照。
 * @example
 * //create GPIO Port 0.0 dir=out
 * var mcu=new LPCXpresso1769.Mcu(“192.168.0.39”);
 * var gpio=new LPCXpresso1769.Gpio(mcu);
 * var pin=new  LPCXpresso1769.GpioPin(gpio,P0[0],{dir:1}); 
 */
DEV.GpioPin=function GpioPin(i_gpio,i_pin,i_opt)
{
	try{
		//PINを作る。
		this._gpio=i_gpio;
		this._pin=new DEV.Pin(i_gpio._mcu,i_pin);
		//pinからGPIOに関するピン情報を計算。
		this._gpioinfo=function(i_pin)
		{
			//pinの完全な機能名を得る。(得られれば機能がある。)
			var func_name=DEV.completePinFunctionName(i_pin,"GPIO");
			//pin名からポートとビットを得る。
			var a=func_name.substring(4).split(".");
			//pin情報を構成。
			var r={port:parseInt(a[0]),bit:parseInt(a[1]),pin_sel:DEV.getPinSelByFunctionName(i_pin,func_name)};
			if(!isNaN(r.port) && !isNaN(r.bit)){
				return r;
			}
			throw new MiMicException(EE.INVALID_CFG,"The pin has not GPIO fuction.");
		}(i_pin);
		//optの構成
		var opt=isUndef(i_opt)?{pin:{}}:
		{
			dir:i_opt.dir,
			pin:isUndef(i_opt.pin)?{}:cloneAssoc(i_opt.pin)
		}
		//デフォルト値
		if(isUndef(opt.pin.sel)){opt.pin.sel=this._gpioinfo.pin_sel;}
		//Pinのコンフィギュレーション
		this.setOpt(opt);
	}catch(e){
		throw new MiMicException(e);
	}
}
DEV.GpioPin.prototype=
{
	_gpio:null,
	_pin:null,//LPCXpressoのpin
	_gpioinfo:null,//GPIOの情報{port,bit,pin_sel}
	/**
	 * ADピンにオプション値を設定する。
	 * @name LPCXpresso1769.GpioPin#setOpt
	 * @function
	 * @param {object as associative array} i_opt
	 * GPIOピンのコンフィグレーションパラメタである。必要な値を格納した連想配列で指定する。
	 * 全ての値を省略することは出来ない。連想配列のメンバは以下の通り。
	 * <pre>{dir:int,pin:object as associative array}</pre>
	 * <ul>
	 * <li>dir - ピンのIN/OUTを指定する1bitの値。1=out,0=in</li>
	 * <li>pin - LPCXpresso1769.Pin#setOpt関数のi_optに渡すパラメタである。</li>
	 * </ul>
	 * @example
	 * //set P0[0] to output  GPIO and mode=repeter and open drain=1
	 * var mcu=new LPCXpresso1769.Mcu("192.168.0.39");
	 * var gpiopin=mcu.getPin(LPCXpresso1769.P0[0],"GPIO");
	 * gpiopin.setOpt({dir:1,pin:{mode:1,od:0}});
	 * gpiopin.setValue(1);	 
	 */	
	setOpt:function setOpt(i_opt)
	{
		try{
			var bc="";
			var db=new Array();
			//dirの設定
			if(!isUndef(i_opt.dir)){
				bc+=this._gpio.BCF_setDir(this._gpioinfo.port,this._gpioinfo.bit,i_opt.dir,db);
			}
			//pinselの値
			if(!isUndef(i_opt.pin)){
				bc+=this._pin.BCF_setOpt(i_opt.pin,db);
			}
			//MiMicBCを生成して実行
			this._gpio._mcu.callMiMicWithCheck(bc+BCF.END,db);
		}catch(e){
			throw new MiMicException(e);
		}
	},
	/**
	 * ピンの出力状態を設定する。
	 * この関数は、directionを1(output)に設定したピンで使用できる。inputに設定したピンには使用できない。
	 * @name LPCXpresso1769.GpioPin#setValue
	 * @function
	 * @param {int} i_val
	 * 1ビットの出力値。
	 * @example
	 * //set P0[0] pin to “on”. If LED was connected pin it will turn on.
	 * var mcu=new LPCXpresso1769.Mcu("192.168.0.39");
	 * var gpiopin=mcu.getPin(LPCXpresso1769.P0[0],"GPIO");
	 * gpiopin.setOpt({dir:1,pin:{mode:1,od:0}});
	 * gpiopin.setValue(1);	 
	 */
	setValue:function setValue(i_val)
	{
		try{
			var bc="";
			var db=new Array();
			bc+=this._gpio.BCF_setValue(this._gpioinfo.port,this._gpioinfo.bit,i_val,db);
			this._gpio._mcu.callMiMicWithCheck(bc+BCF.END,db);
		}catch(e){
			throw new MiMicException(e);
		}
	},	
	/**
	 * ピンの入力状態を1/0で返す。
	 * この関数は、directionを0(input)に設定したピンで使用できる。outputに設定したピンには使用できない。
	 * @function
	 * @return {int}
	 * 1,又は0
	 * @name LPCXpresso1769.GpioPin#getValue
	 * @example
	 * //show P0[0] value
	 * var mcu=new LPCXpresso1769.Mcu("192.168.0.39");
	 * var gpiopin=mcu.getPin(LPCXpresso1769.P0[0],"GPIO");
	 * gpiopin.setOpt({dir:0,pin:{mode:0,od:0}});
	 * alert(gpiopin.getValue());	 
	 */
	getValue:function getValue()
	{

		try{
			var bc="";
			var db=new Array();
			bc+=this._gpio.BCF_getValue(this._gpioinfo.port,this._gpioinfo.bit,db);
			var ret=this._gpio._mcu.callMiMicWithCheck(bc+BCF.END,db);
			return (ret.stream[0]>>this._gpioinfo.bit)&0x01;
		}catch(e){
			throw new MiMicException(e);
		}
	},
	/**
	 * 直列化されたビットパターンを出力する。
	 *　単純なビットパターンをピンに出力するときに使用する。
	 * 出力速度はMCU依存であり、コントロールできない。
	 * この関数は、directionを1(output)に設定したピンで使用できる。inputに設定したピンには使用できない。
	 * @name LPCXpresso1769.GpioPin#outPatt
	 * @function
	 * @param {array[int]} i_val_array
	 * ビットパターンの配列。1ビットの値(0 or 1)の配列を指定する。最大数は20である。
	 * [0,1,0,1]の場合、0,1,0,1の順に、パターンを出力します。
	 * @example
	 * //output  0101010100001010 to P0[0]
	 * var mcu=new LPCXpresso1769.Mcu("192.168.0.39");
	 * var gpiopin=mcu.getPin(LPCXpresso1769.P0[0],"GPIO");
	 * gpiopin.setOpt({dir:1,pin:{mode:1,od:0}});
	 * gpiopin.outPatt([0,1,0,1,0,1,0,1,0,0,0,0,1,0,1,0]);
	 */
	outPatt:function outPatt(i_val_array)
	{
		try{
			var bc="";
			var db=new Array();
			for(var i=0;i<i_val_array.length;i++){
				bc+=this._gpio.BCF_setValue(this._gpioinfo.port,this._gpioinfo.bit,i_val_array[i],db);
			}
			this._gpio._mcu.callMiMicWithCheck(bc+BCF.END,db);
		}catch(e){
			throw new MiMicException(e);
		}
	},
	
}

}());
