/**
 * @fileOverview LPC1769のメモリアクセスクラスを定義する。
 */

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

function checkAlign(v){
	if(v%4!=0){
		throw new MiMicException(EE.INVALID_ARG,"An alignment is not 32bit unit.");
	}
}

/**
 * LPC1769.Memory (Memory)クラスのコンストラクタ。
 * Memoryクラスは、MCUのメモリ空間へアクセスする手段を提供する。
 * このクラスは、メモリアクセス対してなんら保護機能を持たない。MCUのメモリマップに十分に注意する必要がある。
 * @name LPC1769.Memory
 * @constructor
 * @param {object as LPC1769.Mcu} i_mcu
 * インスタンスを結びつけるMcuオブジェクト。
 * @param {int} i_base
 * メモリにアクセスするときのベースアドレス。省略可能である。省略時は0x0とみなす。4バイト境界でなければならない。クラスの提供する関数でアドレスを指定した時には、全てこの値が加算される。
 * @example
 * //create a controlable MCU via network.
 * var mcu=new LPC1769.Mcu(“192.168.0.39”);
 * var memory=new LPC1769.Memory(mcu); 
 */
DEV.Memory=function Memory(i_mcu,i_base)
{
	if(!isUndef(i_base)){
		this._base=i_base;
	}
	this._mcu=i_mcu;
}
DEV.Memory.prototype=
{
	_base:0x00000000,
	_mcu:null,
	/**
	 * 指定したアドレスの32ビット値を取得する。
	 * @name LPC1769.Memory#read32^2
	 * @function
	 * @param {int} i_offset
	 * コンストラクタで指定したアドレスからのオフセット位置を指定する。4バイト境界でなければならない。
	 * @return {int}
	 * 1個のint値。
	 * @example
	 * var　mcu=new LPC1769.Mcu("192.168.0.39");
	 * var mem=new LPC1769.Memory(mcu);　//create instance
	 * alert(mem.read32(0x00000000)); //show 1 value 
	 */
	/**
	 * 指定したオフセットから、i_sizeバイトのメモリに格納した値を、それぞれ32ビット単位で値を取得する。i_offsetの位置から、32bit単位でi_size/4個の値を取得することになる。シーケンシャルアクセスに使用する。
	 * @name LPC1769.Memory#read32^3
	 * @function
	 * @param {int} i_offset
	 * コンストラクタで指定したアドレスからのオフセット位置を指定する。4バイト境界でなければならない。
	 * @param {int} i_size
	 * 取得するバイト数を指定する。4バイト単位でなければならない。	 
	 * @return {Array[int]}
	 * 取得する値の個数は、i_size/4個である。
	 * @example
	 * var　mcu=new LPC1769.Mcu("192.168.0.39");
	 * var mem=new LPC1769.Memory(mcu);　//create instance
	 * mem.read32(0x0,8); //return 2 values.
	 */
	/**
	 * オフセットの配列要素に対応した値を、それぞれ32ビット単位で取得する。
	 * ランダムアクセスに使用する。
	 * @name LPC1769.Memory#read32^4
	 * @function
	 * @param {array[int]} i_offsets
	 * オフセットアドレスの配列。それぞれ4バイト境界でなければならない。
	 * @return {int or Array[int]}
	 * 返却される値の個数は、i_offsetの長さと同じになる。
	 * @example
	 * var　mcu=new LPC1769.Mcu("192.168.0.39");
	 * var mem=new LPC1769.Memory(mcu);　//create instance
	 * mem.read32([0x0,0x14,0x08]); //return 3 values by specified order.
	 */
	/**
	 * メモリから値を読み出して、値セットの配列、又は値を返す。
	 * 関数は4バイト単位のアライメントでメモリにアクセスする。メモリアドレス、取得サイズは4バイト境界に一致させなければならない。
	 * 引数の違いにより、数種類の呼び出し方がある。
	 * @name LPC1769.Memory#read32^1
	 * @function
	 * @param ...
	 * 詳細は、read32^nを参照。
	 * @return {int or Array[int]}
	 * 返却値の数により、型が異なる。1個の場合はint値、複数の場合はint型の配列である。
	 */
	read32:function read32(/*arguments*/)
	{
		try{
			var is_ret_array=true;
			var bc="";
			var ar=new Array();
			var offset=arguments[0];
			switch(arguments.length){
			case 1:
				if(!isNaN(offset)){
					//read32(i_offset:int)
					checkAlign(offset);
					bc=BCF.READMEM;
					ar.push(this._base+offset);
					is_ret_array=false;
				}else{
					//read32(i_offsets:array)
					for(var i=0;i<offset.length;i++){
						checkAlign(offset[i]);
						bc+=BCF.getMem(this._base+offset[i],ar);
					}
				}
				break;
			case 2:
				//read32(i_offset:int,i_size:int)
				checkAlign(offset);
				checkAlign(arguments[1]);
				var l=arguments[1]/4;
				for(var i=0;i<l;i++){
					bc+=BCF.READMEM;
					ar.push(this._base+offset+i*4);
				}
				break;
			default:
				break;
			}
			var ret=this._mcu.callMiMicWithCheck(bc+BCF.END,ar).stream;
			return is_ret_array?ret:ret[0];
		}catch(e){
			throw new MiMicException(e);
		}
	},
	/**
	 * 指定したアドレスに32ビット値を書き込む。
	 * @name LPC1769.Memory#write32^2
	 * @function
	 * @param {int} i_offset
	 * コンストラクタで指定したアドレスからのオフセット位置を指定する。4バイト境界でなければならない。
	 * @param {int} i_value
	 * 1個のint値。
	 * @example
	 * var　mcu=new LPC1769.Mcu("192.168.0.39");
	 * var mem=new LPC1769.Memory(mcu);　//create instance
	 * mem.write32(0x20080000,139);
	 */
	/**
	 * 指定したオフセットから、n個の32bit値を書き込む。シーケンシャルアクセスに使用する。
	 * @name LPC1769.Memory#write32^3
	 * @function
	 * @param {int} i_offset
	 * コンストラクタで指定したアドレスからのオフセット位置を指定する。4バイト境界でなければならない。
	 * @param {array[int]} i_values
	 * 書きこむバイト数を指定する。4バイト単位でなければならない。	 
	 * @example
	 * var　mcu=new LPC1769.Mcu("192.168.0.39");
	 * var mem=new LPC1769.Memory(mcu);　//create instance
	 * mem.write32(0x20080008,[439,539,639]);
	 */
	/**
	 * オフセットの配列要素に対応した値を、それぞれ32ビット単位で書きこむ。
	 * ランダムアクセスに使用する。
	 * @name LPC1769.Memory#write32^4
	 * @function
	 * @param {array[int]} i_offsets
	 * オフセットアドレスの配列。それぞれ4バイト境界でなければならない。
	 * @param {array[int]} i_values
	 * セットする値。個数は、i_offsetsと一致していなければならない。
	 * @example
	 * var　mcu=new LPC1769.Mcu("192.168.0.39");
	 * var mem=new LPC1769.Memory(mcu);　//create instance
	 * mem.write32([0x20080020,0x20080024],[239,339]);
	 */
	/**
	 * メモリアドレスを指定して、値を書き込む。
	 * 関数は4バイト単位のアライメントでメモリにアクセスする。メモリアドレス、取得サイズは4バイト境界に一致させなければならない。
	 * 引数の違いにより、数種類の呼び出し方がある。
	 * @name LPC1769.Memory#write32^1
	 * @function
	 * @param ...
	 * 詳細は、write32^nを参照。
	 */
	write32:function write32(/*arguments*/)
	{
		try{
			var bc="";
			var ar=new Array();
			var offset=arguments[0];
			switch(arguments.length){
			case 2:
				if((!isNaN(offset))){
					if(!isNaN(arguments[1])){
						//write32(i_offset:int,i_value:int)
						checkAlign(offset);
						bc+=BCF.setMem(this._base+offset,arguments[1],ar);
					}else if(arguments[1].length>0){
						//read32(i_offset:int,i_value:array)
						checkAlign(offset);
						var l=arguments[1].length;
						for(var i=0;i<l;i++){
							bc+=BCF.setMem(this._base+offset+i*4,arguments[1][i],ar);
						}
					}else{
						throw new MiMicException();
					}
				}else if(offset.length==arguments[1].length){
					//write32(i_offsets:array,i_value:array)
					for(var i=0;i<offset.length;i++){
						checkAlign(offset[i]);
						bc+=BCF.setMem(this._base+offset[i],arguments[1][i],ar);
						
					}
				}else{
					throw new MiMicException();
				}
				break;
			default:
				break;
			}
			this._mcu.callMiMicWithCheck(bc+BCF.END,ar).stream;
			return;
		}catch(e){
			throw new MiMicException(e);
		}
	}	
}

}());