/**
 * @fileOverview LPC1769における、ネイティブ関数コールインタフェイスを定義する。
  */
(function(){
var DEV=LPC1769;
var BCF=DEV._BCF;
var EE=DEV._EE;
var isUndef=MiMicLib.isUndef;



/**
 * LPC1769.Ni (NativeInterface)クラスのコンストラクタ。
 * MCUに関連付けしたネイティブインタフェイスを生成する。
 * クラスは、MiMicVMのCALL命令を使用した、ネイティブ関数コール機能を提供する。
 * @constructor
 * @name LPC1769.Ni
 * @param {object as LPC1769.Mcu} i_mcu
 * インスタンスを結びつけるMcuオブジェクト。
 * @example
 */
DEV.Ni=function Ni(i_mcu)
{
	try{
		this._mcu=i_mcu;
	}catch(e){
		throw new MiMicException(e);
	}

}
DEV.Ni.prototype=
{
	/**
	 * この関数は、CALLインストラクションを使ったネイティブファンクションコールを実行する。
	 * MiMicRemoteMCUに定義されているネイティブ関数から、ファンクションIDに一致するものを検索して、実行する。
	 * ネイティブ関数は、native_function.cのnaitive_function_tableに定義されている。
	 * 引き渡すパラメータは、SPUTによるストリーム値と、VMのレジスタ(WM)値である。得られる返却値は、ネイティブ関数実行後のVMレジスタ(WM)と、ストリームである。
	 * @name LPC1769.Ni#call
	 * @function
	 * @param {int} i_id
	 * ファンクションID。ファンクションIDは、呼び出す関数を識別するidである。
	 * @param {object as associative array} i_in
	 * 入力パラメータである。必要な値を格納した連想配列で指定する。省略が可能である。
	 * 連想配列のメンバは以下の通り。
	 * <pre>{wm?:int,stream:array[int]}</pre>
	 *
	 * <ul>
	 * <li>wm? - WMレジスタにセットする値である。wm0～wm7まで、最大8個の値を指定できる。</li>
	 * <li>stream - ストリームに出力する値である。長さに制限は無いが、100個程度が上限である。</li>
	 * </ul>
	 * @param {object as associative array} o_out
	 * 出力パラメータを受け取る変数である。戻り値として取得したい値を格納した連想配列を指定する。省略が可能である。
	 * 各メンバ変数は関数が割り当てるので、nullを設定しておくこと。
	 * 連想配列のメンバは以下の通り。
	 * <pre>{wm?:null,stream:null}</pre>
	 * <ul>
	 * <li>wm? - 取得するWMレジスタのプレースホルダ。戻り値としてwmレジスタの値を取得する時に指定する。取得したいWMを指定する。</li>
	 * <li>stream - 取得するストリームのプレースホルダ。戻り値としてネイティブ関数が出力したストリームを取得する時に指定する。純粋な返却streamから、wmの返却分を差し引いたint array値である。</li>
	 * </ul>
	 * @return {boolean}
	 * 関数コールが成功するとtrueである。
	 * @example
	 * var mcu=new LPC1769.Mcu("192.168.128.39",true);
	 * var ni=new LPC1769.Ni(mcu);
	 * //This function calls the function number 1. wm1=1,wm2=3 are set to WM before calling. And puts [12] to input stream.
	 * //Out values are consist of wm4,wm5 and output stream values.
	 * var r1={wm4:null,wm5:null};
	 * ni.call(0,{wm1:1,wm2:3,stream:[12]},r1);
	 *
	 * //sample2 no parameter, returns.
	 * ni.call(0);
	 * 
	 * //sample 3 stream only.
	 * var r2={stream:null};
	 * ni.call(0,{stream:[]},r2);
	 *
	 * //call sample echo back native function.
	 * var r3={stream:null};
	 * ni.call(0x39000000,{stream:[0x2525]},r3);
	 * alert(r3[0]);
	 *
	 * // set/get all work register and stream.
	 * var r4={stream:null,wm0:null,wm1:null,wm2:null,wm3:null,wm4:null,wm5:null,wm6:null,wm7:null};
	 * ni.call(0x39000000,{stream:[0x39],wm0:7,wm1:6,wm2:5,wm3:4,wm4:3,wm5:2,wm6:1,wm7:0},r4);
	 *
	 */
	call:function call(i_id,i_in,o_out)
	{
		/*
		 * .DBは、WM設定値(あれば),idx番号,stream値の順で格納。
		 * 命令は、
		 * WM初期化部(LD配列)
		 * LD #0;WM初期化(あれば)
		 * :
		 * SGET 
		 */
		var bc="";
		var db=new Array();
		//WM初期化命令
		if(!isUndef(i_in)){
			//wmがあれば、初期化命令を追加。
			//LD命令を直書き
			for(var i=0;i<8;i++){
				var hash="wm"+i;
				if(!isUndef(i_in[hash])){
					bc+="FB"+MiMicLib.hexout(i,2)+MiMicLib.hexout(i_in[hash],8);
				}
			}
			//streamをセット
			if(!isUndef(i_in.stream)){
				for(var i=0;i<i_in.stream.length;i++){
					db.push(i_in.stream[i]);
				}
			}
		}
		//CALL命令を直書き
		bc+="ZF"+MiMicLib.hexout(i_id,8);
		//
		var num_of_wm=0;
		if(!isUndef(o_out)){
			//o_out.wmxがあれば、回収用命令を追記
			//SGET命令を直書き
			for(var i=0;i<8;i++){
				if(!isUndef(o_out["wm"+i])){
					bc+="EE"+MiMicLib.hexout(i,2);
					num_of_wm++;
				}
			}
		}
		//実行
		var ret=this._mcu.callMiMic(bc+BCF.END,db);
		if(ret.result!=0x00){
			//失敗.理由はresultの内容。
			return false;
		}
		//streamから値を回収
		//streamは、関数の返したストリーム+WMの返却値
		if(!isUndef(o_out)){
			//WM回収のためにSGET命令を直書き
			var offset=ret.stream.length-num_of_wm;
			for(var i=0;i<8;i++){
				var hash="wm"+i;
				if(!isUndef(o_out[hash])){
					o_out[hash]=ret.stream[offset];
					offset++;
				}
			}
			//o_out.streamがあれば、値を回収。
			if(!isUndef(o_out.stream)){
				o_out.stream=ret.stream.slice(0,ret.stream.length-num_of_wm);
			}
		}
		return false;
	}
}




}());
