using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;

namespace MiMic.CsApi.LPC1769
{
	public class PeripheralId
	{
		private UInt32?[] reg=new UInt32?[3];
		public PeripheralId(UInt32? r1,UInt32? r2,UInt32? r3)
		{
			this.reg[0]=r1;
			this.reg[1]=r2;
			this.reg[2]=r3;
		}
		public UInt32? this[int i]
		{
			get{return this.reg[i];}
		}
	}
	public class PinId
	{
		public UInt32?[] reg=new UInt32?[4];
		public string[] sel;
		public PinId(UInt32? v1,UInt32? v2,UInt32? v3,UInt32? v4,string s1,string s2,string s3,string s4)
		{
			sel=new string[4];
			reg[0]=v1;reg[1]=v2;reg[2]=v3;reg[3]=v4;
			sel[0]=s1;sel[1]=s2;sel[2]=s3;sel[3]=s4;
		}
	}
	public class LPC1769
	{
		internal static class _BCF
		{
			public static string setBit(UInt32 i_addr,UInt32 i_mask,UInt32 i_val,int i_shl,List<UInt32> i_db)
			{
				i_db.Add(i_addr);
				i_db.Add(~(i_mask<<i_shl));
				i_db.Add((i_mask & i_val) << i_shl);
				return "EA00EA01EA02DB0700AA0701AE0702DF0700";
			}
			public static string setMem(UInt32 i_addr,UInt32 i_val,List<UInt32> i_db)
			{
				i_db.Add(i_addr);
				i_db.Add(i_val);
				return "EA00EA01DF0100";
			}
			public static string getMem(UInt32 i_addr,List<UInt32> i_db)
			{
				i_db.Add(i_addr);
				return "EA00DB0000EE00";
			}
			public const string READMEM="EA00DB0000EE00";
			public const string END="ZZ.E";
		}
		
		public static string[] FUNC_NAME=new string[]{
			"GPIO","AD","DA","PWM"
		};
		public static string[] PHL_NAME=new string[]{
			"GPIO","ADC","DAC","PWM"
		};
		/**
		 * LPCXpressoのPeripheralパラメタを格納したテーブルである。要素はペリフェラル識別子である。
		 * UM10360のChapter 4: LPC17xx Clocking and power controlを元に定義している。
		 * ペリフェラル識別子はペリフェラルのレジスタ番号とビット番号を格納した配列である。
		 * <pre>
		 * PHL:{PHL_NAME:[PCLKSELreg#,PCLKSELbit#,PCONPbit#]}
		 * </pre>
		 * nullはそのビットが無効であることを示す。
		 * @name LPCXpresso1769#PHL
		 * @constant
		 * @field
		 * @example
		 * LPCXpresso1796.PHLADC //ADC peripheral
		 */
		public sealed class PHL{
			public static PeripheralId WDT=new PeripheralId(0,0,null);
			public static PeripheralId TIMER0=new PeripheralId(0,2,1);
			public static PeripheralId TIMER1=new PeripheralId(0,4,2);
			public static PeripheralId UART0=new PeripheralId(0,6,3);
			public static PeripheralId UART1=new PeripheralId(0,8,4);
			public static PeripheralId PWM1=new PeripheralId(0,12,6);
			public static PeripheralId I2C0=new PeripheralId(0,14,7);
			public static PeripheralId SPI=new PeripheralId(0,16,8);
			public static PeripheralId RTC=new PeripheralId(null,null,9);
			public static PeripheralId SSPI1=new PeripheralId(0,20,10);
			public static PeripheralId DAC=new PeripheralId(0,22,null);
			public static PeripheralId ADC=new PeripheralId(0,24,12);
			public static PeripheralId CAN1=new PeripheralId(0,26,13);
			public static PeripheralId CAN2=new PeripheralId(0,28,14);
			public static PeripheralId ACF=new PeripheralId(0,30,null);
			public static PeripheralId QEI=new PeripheralId(1,0,18);
			public static PeripheralId GPIOINT=new PeripheralId(1,2,15);
			public static PeripheralId PCB=new PeripheralId(1,4,null);
			public static PeripheralId I2C1=new PeripheralId(1,6,19);
			public static PeripheralId SSP0=new PeripheralId(1,10,21);
			public static PeripheralId TIMER2=new PeripheralId(1,12,22);
			public static PeripheralId TIMER3=new PeripheralId(1,14,23);
			public static PeripheralId UART2=new PeripheralId(1,16,24);
			public static PeripheralId UART3=new PeripheralId(1,18,25);
			public static PeripheralId I2C2=new PeripheralId(1,20,26);
			public static PeripheralId I2S=new PeripheralId(1,22,27);
			public static PeripheralId RIT=new PeripheralId(1,26,16);
			public static PeripheralId SYSCON=new PeripheralId(1,28,null);
			public static PeripheralId PWM_MC=new PeripheralId(1,30,17);//MC?
			public static PeripheralId GPDMA=new PeripheralId(null,null,29);
			public static PeripheralId ENET=new PeripheralId(null,null,30);
			public static PeripheralId USB=new PeripheralId(null,null,31);
		}
		public static PinId[] P0=new PinId[]{
			new PinId(0,0,0,0,"GPIO0.0","RD1","TXD3","SDA1"),
			new PinId(0,0,0,1,"GPIO0.1","TD1","RXD3","SCL1"),//1
			new PinId(0,0,0,2,"GPIO0.2","TXD0","AD0.7",null),//2
			new PinId(0,0,0,3,"GPIO0.3","RXD0","AD0.6",null),//3
			new PinId(0,0,0,4,"GPIO0.4","I2SRX_CLK","RD2","CAP2.0"),//4
			new PinId(0,0,0,5,"GPIO0.5","I2SRX_WS","TD2","CAP2.1"),//5
			new PinId(0,0,0,6,"GPIO0.6","I2SRX_SDA","SSEL1","MAT2.0"),//6
			new PinId(0,0,0,7,"GPIO0.7","I2STX_CLK","SCK1",	"MAT2.1"),//7
			new PinId(0,0,0,8,"GPIO0.8","I2STX_WS","MISO1","MAT2.2"),//8
			new PinId(0,0,0,9,"GPIO0.9","I2STX_SDA","MOSI1","MAT2.3"),//9
			new PinId(0,0,0,10,"GPIO0.10","TXD2","SDA2","MAT3.0"),//10
			new PinId(0,0,0,11,"GPIO0.11","RXD2","SCL2","MAT3.1"),//11
			null,null,null,//12,13,14
			new PinId(0,0,0,15,"GPIO0.15","TXD1","SCK0","SCK"),//15
			new PinId(1,1,0,16,"GPIO0.16","RXD1","SSEL0","SSEL"),//16
			new PinId(1,1,0,17,"GPIO0.17","CTS1","MISO0","MISO"),//17
			new PinId(1,1,0,18,"GPIO0.18","DCD1","MOSI0","MOSI"),//18
			new PinId(1,1,0,19,"GPIO0.19","DSR1",null,"SDA1"),//19
			new PinId(1,1,0,20,"GPIO0.20","DTR1",null,"SCL1"),//20
			new PinId(1,1,0,21,"GPIO0.21","RI1",null,"RD1"),//21
			new PinId(1,1,0,22,"GPIO0.22","RTS1",null,"TD1"),//22
			new PinId(1,1,0,23,"GPIO0.23","AD0.0","I2SRX_CLK","CAP3.0"),//23
			new PinId(1,1,0,24,"GPIO0.24","AD0.1","I2SRX_WS","CAP3.1"),//24
			new PinId(1,1,0,25,"GPIO0.25","AD0.2","I2SRX_SDA","TXD3"),//25
			new PinId(1,1,0,26,"GPIO0.26","AD0.3","AOUT","RXD3"),//26
			new PinId(1,null,null,22,"GPIO0.27","SDA0",	"USB_SDA",null),//27
			new PinId(1,null,null,24,"GPIO0.28","SCL0",	"USB_SCL",null),//28
			new PinId(1,null,0,29,"GPIO0.29","USB_D+",null,null),//29
			new PinId(1,null,0,30,"GPIO0.30","USB_D-",null,null)//30
		};
		public static PinId[] P1={
			new PinId(2,2,1,0,"GPIO1.0","ENET_TXD0",null,null),//0
			new PinId(2,2,1,1,"GPIO1.1","ENET_TXD1",null,null),//1
			null,null,//2,3
			new PinId(2,2,1,4,"GPIO1.4","ENET_TX_EN",null,null),//4
			null,null,null,//5,6,7
			new PinId(2,2,1,8,"GPIO1.8","ENET_CRS",null,null),//8
			new PinId(2,2,1,9,"GPIO1.9","ENET_RXD0",null,null),//9
			new PinId(2,2,1,10,"GPIO1.10","ENET_RXD1",null,null),//10
			null,null,null,//11,12,13
			new PinId(2,2,1,14,"GPIO1.14","ENET_RX_ER",null,null),//14
			new PinId(2,2,1,15,"GPIO1.15","ENET_REF_CLK",null,null),//15
			new PinId(3,3,1,16,"GPIO1.16","ENET_MDC",null,null),//16
			new PinId(3,3,1,17,"GPIO1.17","ENET_MDIO",null,null),//17
			new PinId(3,3,1,18,"GPIO1.18","USB_UP_LED","PWM1.1","CAP1.0"),//18
			new PinId(3,3,1,19,"GPIO1.19","MCOA0","USB_PPWR","CAP1.1"),//19
			new PinId(3,3,1,20,"GPIO1.20","MCI0","PWM1.2","SCK0"),//20
			new PinId(3,3,1,21,"GPIO1.21","MCABORT","PWM1.3","SSEL0"),//21
			new PinId(3,3,1,22,"GPIO1.22","MCOB0","USB_PWRD","MAT1.0"),//22
			new PinId(3,3,1,23,"GPIO1.23","MCI1","PWM1.4","MISO0"),//23
			new PinId(3,3,1,24,"GPIO1.24","MCI2","PWM1.5","MOSI0"),//24
			new PinId(3,3,1,25,"GPIO1.25","MCOA1",null,"MAT1.1"),//25
			new PinId(3,3,1,26,"GPIO1.26","MCOB1","PWM1.6","CAP0.0"),//26
			new PinId(3,3,1,27,"GPIO1.27","CLKOUT","USB_OVRCR","CAP0.1"),//27
			new PinId(3,3,1,28,"GPIO1.28","MCOA2","PCAP1.0","MAT0.0"),//28
			new PinId(3,3,1,29,"GPIO1.29","MCOB2","PCAP1.1","MAT0.1"),//29
			new PinId(3,3,1,30,"GPIO1.30",null,"VBUS","AD0.4"),//30
			new PinId(3,3,1,31,"GPIO1.31",null,"SCK1","AD0.5")//31
		};
		public static PinId[] P2=new PinId[]{
			new PinId(4,4,2,0,"GPIO2.0","PWM1.1","TXD1",null),//0
			new PinId(4,4,2,1,"GPIO2.1","PWM1.2","RXD1",null),//1
			new PinId(4,4,2,2,"GPIO2.2","PWM1.3","CTS1",null),//2
			new PinId(4,4,2,3,"GPIO2.3","PWM1.4","DCD1",null),//3
			new PinId(4,4,2,4,"GPIO2.4","PWM1.5","DSR1",null),//4
			new PinId(4,4,2,5,"GPIO2.5","PWM1.6","DTR1",null),//5
			new PinId(4,4,2,6,"GPIO2.6","PCAP1.0","RI1",null),//6
			new PinId(4,4,2,7,"GPIO2.7","RD2","RTS1",null),//7
			new PinId(4,4,2,8,"GPIO2.8","TD2","TXD2","ENET_MDC"),//8
			new PinId(4,4,2,9,"GPIO2.9","USB_CONNECT","RXD2","ENET_MDIO"),//9
			new PinId(4,4,2,10,"GPIO2.10","EINT0","NMI",null),//10
			new PinId(4,4,2,11,"GPIO2.11","EINT1",null,"I2STX_CLK"),//11
			new PinId(4,4,2,12,"GPIO2.12","EINT2",null,"I2STX_WS"),//12
			new PinId(4,4,2,13,"GPIO2.13","EINT3",null,"I2STX_SDA")//13
		};
		public static PinId[] P3=new PinId[]{
			null/* 0*/,null/* 1*/,null/* 2*/,null/* 3*/,null/* 4*/,null/* 5*/,null/* 6*/,null/* 7*/,null/* 8*/,null/* 9*/,
			null/*10*/,null/*11*/,null/*12*/,null/*13*/,null/*14*/,null/*15*/,null/*16*/,null/*17*/,null/*18*/,null/*19*/,
			null/*20*/,null/*21*/,null/*22*/,null/*23*/,null/*24*/,
			new PinId(7,7,3,25,"GPIO3.25",null,"MAT0.0","PWM1.2"),//25
			new PinId(7,7,3,26,"GPIO3.26","STCLK","MAT0.1","PWM1.3")//26
		};
		public static PinId[] P4=new PinId[]{
			null/* 0*/,null/* 1*/,null/* 2*/,null/* 3*/,null/* 4*/,null/* 5*/,null/* 6*/,null/* 7*/,null/* 8*/,null/* 9*/,
			null/*10*/,null/*11*/,null/*12*/,null/*13*/,null/*14*/,null/*15*/,null/*16*/,null/*17*/,null/*18*/,null/*19*/,
			null/*20*/,null/*21*/,null/*22*/,null/*23*/,null/*24*/,null/*25*/,null/*26*/,null/*27*/,
			new PinId(9,9,4,28,"GPIO4.28","RX_MCLK","MAT2.0","TXD3"),//28
			new PinId(9,9,4,29,"GPIO4.29","TX_MCLK","MAT2.1","RXD3")//29
		};
		/**
		 * [forSystem]ピン識別子のアクセス関数である。
		 * ピン機能シンボルのプレフィクス（機能シンボル）を、 ピン識別子を元に、完全な名称に変換する。
		 * ピンにFunctionが含まれているか調べることが出来る。
		 * @private
		 */
		public static string completePinFunctionName(PinId i_pin,string i_prefix)
		{
			//配列探索
			for(int i=0;i<i_pin.sel.Length;i++){
				if(i_pin.sel[i].IndexOf(i_prefix)==0){
					//ピン情報の構成
					return i_pin.sel[i];
				}
			}
			throw new MiMicException("The function name '"+i_prefix+"' is not unknown.");
		}
		public class PinRegInfo
		{
			public UInt32? s;
			public UInt32? m;
			public UInt32? o;
			public UInt32? smb;
			public UInt32? ob;
		}
		public const UInt32 UINT32_INVALID=0xffffffff;
		/**
		 * [forSystem]ピン識別子のアクセス関数。
		 * ピン識別値から、Pinレジスタの番号と、ビット位置を取り出す。
		 * @private
		 * @return
		 * {s:pinselのレジスタ番号、m:modeのレジスタ番号、,o:odのレジスタ番号,sbm:mode,selのビット位置,ob:odのビット位置}
		 */
		public static PinRegInfo getPinRegInfo(PinId i_pin)
		{
			PinRegInfo r=new PinRegInfo();
			r.s=i_pin.reg[0];
			r.m=i_pin.reg[1];
			r.o=i_pin.reg[2];
			if(i_pin.reg[3]!=null){
				UInt32? t=(UInt32?)i_pin.reg[3];
				r.smb=(t%16)*2;
				r.ob=t;
			}else{
				r.smb=null;
				r.ob=null;
			}
			return r;
		}
		/**
		 * [forSystem]ピン識別子のアクセス関数。
		 * PIN機能名に一致するPinsel値を取り出す。
		 * @private
		 */
		public static UInt32 getPinSelByFunctionName(PinId i_pin,string i_name)
		{
			for(UInt32 i=0;i<i_pin.sel.Length;i++){
				if(i_pin.sel[i]==i_name){
					//ピン情報の構成
					return i;
				}
			}
			throw new MiMicException("The function name '"+i_name+"' has not function.");
		}
		/**
		 * [forSystem]ピンが、ピン機能シンボルを持つか返す。
		 * @private
		 */
		public static bool hasPinFunctionName(PinId i_pin,string i_name)
		{
			for(int i=0;i<i_pin.sel.Length;i++){
				if(i_pin.sel[i].IndexOf(i_name)==0){
					return true;
				}
			}
			return false;
		}		
	}
}

