using UnityEngine;
using System.Collections;
using System;
using MiMic.CsApi;
using MiMic.CsApi.LPC1769;

public class TestAllBlockScript : MonoBehaviour
{
	private Mcu _mcu;
	// Use this for initialization
	void Start ()
	{
		this.setGuiProc(this.onGuiInit);
	}
	public delegate void GuiProc();
	public GuiProc _gui_proc;
	public int _gui_proc_tc;
	/**
	 * MiMic Event callback
	 */
	public void _mcuCallback()
	{
		//call the periodic proc here.
		this._mcu.periodicProc();
	}
	/**
	 * GRI switch
	 */
	private void setGuiProc(GuiProc i_proc)
	{
		this._gui_proc=i_proc;
		this._gui_proc_tc=0;
	}
	void OnGUI()
	{
		this._gui_proc();
	}
	//
	// Properties
	//
	private string _mcu_ip_addr="192.168.128.39";
	
	/**
	 * show the connection box.
	 */ 
	void onGuiInit()
	{
		GUI.BeginGroup (new Rect (Screen.width / 2 - 100, Screen.height / 2 - 100, 200, 100));
		GUI.Box(new Rect (0,0,200,100), "Input your MiMic IP Address");
		string ts=GUI.TextField (new Rect (20,40,160,20), this._mcu_ip_addr,19);
		if(ts!=this._mcu_ip_addr){
			this._mcu_ip_addr=ts;
		}
		if(GUI.Button (new Rect (100-40,65,80,30), "Connect")){
			//change state
			this.setGuiProc(this.onGuiTryConnection);
		}
		GUI.EndGroup ();
	}
	/**
	 * Try to connection with synchronized call.
	 */
	void onGuiTryConnection()
	{
		switch(this._gui_proc_tc){
		case 0:
			GUI.Box(new Rect (Screen.width / 2 - 100, Screen.height / 2 - 100,200,50), "Connect to "+this._mcu_ip_addr+" ...");
			this._gui_proc_tc++;
			break;
		case 1:
			try{
				GUI.Box(new Rect (Screen.width / 2 - 100, Screen.height / 2 - 100,200,50), "Connect to "+this._mcu_ip_addr+" ...");
				//The constructor throw an exception when failed.
				this._mcu=new Mcu(this,"_mcuCallback",this._mcu_ip_addr,true);
				this.setGuiProc(onGuiTest);
			}catch(Exception e){
				this.setGuiProc(this.onGuiReturnInit);
			}
			break;
		default:
			break;
		}
	}
	/**
	 * show return dialog box.
	 * This window is shown when the connection was disconnected. etc.
	 */
	void onGuiReturnInit()
	{
		GUI.BeginGroup (new Rect (Screen.width / 2 - 100, Screen.height / 2 - 100, 200, 100));
		GUI.Box(new Rect (0,0,200,100), "Can not connect to "+this._mcu_ip_addr);
		if(GUI.Button (new Rect (100-40,65,80,30), "Return")){
			//change state
			this.setGuiProc(this.onGuiInit);
		}
		GUI.EndGroup ();		
	}
	/**
	 * Gpio test case
	 */
	class GpioTest
	{
		private int tc=0;
		private GpioPin gpiopin;
		private GpioPort gpioport;
		public UInt32 pinv=0;
		public UInt32 portv=0;
		public GpioTest(Mcu i_mcu)
		{
			//Create a gpio pin, 4 bit gpio port.
			this.gpiopin=(GpioPin)i_mcu.getPin(LPCXpresso1769.P0[22],"GPIO");
			this.gpiopin.setOpt(new GpioPin.Option(1,new Pin.Option(null,1,0)));
			this.gpioport=(GpioPort)i_mcu.getPort(
				new PinId[]{LPCXpresso1769.P0[0],LPCXpresso1769.P0[1],LPCXpresso1769.P0[18],LPCXpresso1769.P0[17]},"GPIO");
			this.gpioport.setOpt(new GpioPin.Option(1,new Pin.Option(null,1,0)));			
		}
		public void update()
		{
			GUI.Label(new Rect(0,Screen.height-100,200,100),
				"GPIO output test.\n"+
			    "Pin:  P0[22](LED):"+this.pinv+" \n"+
			    "Port: P0[0],P0[1],P0[18],P0[17]:"+this.portv+"\n");
			if(this.tc%30==0){
				this.gpiopin.setValue((UInt32)(this.tc/30)%2);
				this.gpioport.setValue((UInt32)this.tc/30);
				this.pinv=this.gpiopin.getValue();
				this.portv=this.gpioport.getValue();
			}
			this.tc++;
		}
	}
	/**
	 * Adc test case
	 */
	class AdcTest
	{
		private int tc=0;
		private AdcPin adcpin;
		private AdcPort adcport;
		public UInt32 pinv;
		public UInt32[] portv=new UInt32[2];
		public AdcTest(Mcu i_mcu)
		{
			this.adcpin=(AdcPin)i_mcu.getPin(LPCXpresso1769.P0[23],"AD");
			this.adcport=(AdcPort)i_mcu.getPort(new PinId[]{LPCXpresso1769.P0[24],LPCXpresso1769.P0[25]},"AD");
		}
		public void update()
		{
			GUI.Label(new Rect(0,Screen.height-100,200,100),
				"AD input test.\n"+
			    "Pin:  P0[23] P0[24]"+this.portv[0]+","+this.portv[1]);
			if(this.tc%30==0){
				this.pinv=this.adcpin.getValue();
				this.portv=this.adcport.getValues();
			}
			this.tc++;
		}		
	}
	/**
	 * Pwm test case
	 */
	class PwmTest
	{
		private int tc=0;
		private float pwm1=0f;
		private float pwm2=0f;
		private PwmPin pwmpin;
		private PwmPort pwmport;
		public PwmTest(Mcu i_mcu)
		{
			Pwm pwm=(Pwm)i_mcu.getPeripheral("PWM",new Pwm.Option(100,null));
//			this.pwmpin =pwm.getPin(LPCXpresso1769.P2[0],null);
			this.pwmport=pwm.getPort(new PinId[]{LPCXpresso1769.P2[0],LPCXpresso1769.P2[1]},null);
		}
		public void update()
		{
			GUI.Label(new Rect(0,Screen.height-100,200,100),
				"Pwm output test.\n"+
			    "Pin:  P2[0] P2[1]");
			this.pwm1=GUI.HorizontalScrollbar(new Rect (200,80,200,30), this.pwm1,0.1f, 0.0f,1.0f);
			this.pwm2=GUI.HorizontalScrollbar (new Rect (200,120,200,30), this.pwm2,0.1f, 0.0f,1.0f);
			GUI.Label(new Rect (80,80,120,40),"PWM1:"+this.pwm1);
			GUI.Label(new Rect (80,120,120,40),"PWM2:"+this.pwm2);
			if(this.tc%30==0){
//				this.pwmpin.setDuty(this.pwm1);
				this.pwmport.setDutys(new float?[]{this.pwm1,this.pwm2});
			}			
			this.tc++;
		}		
	}
	class NiTest
	{
		private UInt32 ret1;
		private UInt32 ret2;
		private int tc=0;
		private Ni ni;
		public NiTest(Mcu i_mcu)
		{
			this.ni=new Ni(i_mcu);
		}
		public void update()
		{
			if(this.tc%30==0){
				//1
				//set stream input, accept stream output.
				UInt32[] os=new UInt32[1];
				this.ni.call(0x39000000,null,new UInt32[]{39},null,os);
				this.ret1=os[0];
				//2
				//set wm input, accept wm output.
				Ni.WM ow=new Ni.WM(Ni.WM.PH,null,null,null,null,null,null,null);
				this.ni.call(
					0x39000001,
				    new Ni.WM(33,null,null,null,null,null,null,null),null,
				    ow,null);
				this.ret2=(UInt32)ow.reg[0];
			}
			GUI.Label(new Rect(0,Screen.height-100,200,100),
				"Ni test.\n"+
			    "Result[0]: "+this.ret1+"\n"+
			    "Result[1]: "+this.ret2+"\n");
			this.tc++;
		}		
	}
	class MemTest
	{
		private UInt32[] ret1=null;
		private UInt32[] ret2=null;
		private UInt32[] ret3=null;
		private int tc=0;
		private Memory mem;
		public MemTest(Mcu i_mcu)
		{
			this.mem=new Memory(i_mcu,0);
		}
		public void update()
		{
			if(this.tc%30==0)
			{
				this.mem.write32(0x20080000,139);
				this.mem.write32(new UInt32[]{0x20080020,0x20080024},new UInt32[]{239,339});
				this.mem.write32(0x20080008,new UInt32[]{439,539,639});
				ret1=this.mem.read32(0x20080000);
				ret2=this.mem.read32(0x20080020,8);
				ret3=this.mem.read32(new UInt32[]{0x20080008,0x20080010,0x2008000c});
			}
			if(ret1!=null && ret2!=null && ret3!=null){
				GUI.Label(new Rect(0,Screen.height-100,200,100),
					"Memory test.\n"+
				    "Result[0]: "+this.ret1[0]+"\n"+
				    "Result[1]: "+this.ret2[0]+","+this.ret2[1]+"\n"+
				    "Result[2]: "+this.ret3[0]+","+this.ret3[1]+","+this.ret3[2]+"\n");
			}
			this.tc++;
		}		
	}	

	MemTest memt;
	NiTest nit;
	GpioTest gpiot;
	AdcTest adct;
	PwmTest pwmt;
	int test_mode=0;

	void onGuiTest()
	{
		if(this._gui_proc_tc==0){
			this.memt=new MemTest(this._mcu);
			this.nit=new NiTest(this._mcu);
			this.gpiot=new GpioTest(this._mcu);
			this.adct=new AdcTest(this._mcu);
			this.pwmt=new PwmTest(this._mcu);
		}
		if(GUILayout.Button("GPIO PIN/PORT")){
			test_mode=1;
		}
		if(GUILayout.Button("AD PIN")){
			test_mode=2;
		}
		if(GUILayout.Button("PWM PIN")){
			test_mode=3;
		}
		if(GUILayout.Button("MEMORY")){
			test_mode=4;
		}
		if(GUILayout.Button("NI")){
			test_mode=5;
		}
		switch(this.test_mode){
		case 1:
			this.gpiot.update();
			break;
		case 2:
			this.adct.update();
			break;
		case 3:
			this.pwmt.update();
			break;
		case 4:
			this.memt.update();
			break;
		case 5:
			this.nit.update();
			break;
		}
		this._gui_proc_tc++;

	}
}
