#include <nds.h>
#include <stdarg.h>

void rx_wait(u32 n,void *buf){
	u32 i;
	for(i=0;i<n;i++){
		for(;;){
			if(*((vu8 *)0x0A000001) & 1){
				*((u8 *)buf+i)=*((vu8 *)0x0A000000);
				break;
			}
		}
	}
}

static void tx_wait(u32 n,void *buf){
	u32 i;
	for(i=0;i<n;i++){
		for(;;){
			if((*((vu8 *)0x0A000001) & 2)==0){
				*((vu8 *)0x0A000000)=*((u8 *)buf+i);
				break;
			}
		}
	}
}

void arm9own(){	//only call from arm9
	WAIT_CR &= ~BIT(7);//GBA cart
}

void arm7own(){	//only call from arm7
	WAIT_CR |= BIT(7);	//GBA & NDS cart
}

s32 PcOpen(s8 *filename,s32 mode){
	u32 i;
	u8 buf[64];
	u32 len;
	
	buf[0]=0xa1;
	for(len=0;;len++) if(filename[len]==0) break;
	buf[1]=len;
	
	for(i=0;i<len;i++){
		buf[2+i]=filename[i];
	}
	buf[2+len]=mode;
	buf[3+len]=mode>>8;
	tx_wait(4+len,buf);
	rx_wait(4,&len);
	return(len);
}

s32 PcClose(s32 fh){
	u8 buf[5];
	buf[0]=0xa2;
	buf[1]=fh;
	buf[2]=fh>>8;
	buf[3]=fh>>16;
	buf[4]=fh>>24;
	tx_wait(5,buf);
	return(0);
}

s32 PcRead(s32 fh,void *buffer,s32 size){
	s32 len;
	s32 zan,ofs;
	u8 buf[257];
	buf[0]=0xa3;
	buf[1]=fh;
	buf[2]=fh>>8;
	buf[3]=fh>>16;
	buf[4]=fh>>24;
	buf[5]=size;
	buf[6]=size>>8;
	buf[7]=size>>16;
	buf[8]=size>>24;
	tx_wait(9,buf);
	rx_wait(4,&size);
	if(size>0){
		zan=size;
		ofs=0;
		for(;;){
			if(zan>256){
				len=256;
			}
			else{
				len=zan;
			}
			rx_wait(len,buf);
			memcpy((u8 *)buffer+ofs,buf,len);
			ofs+=len;
			zan-=len;
			if(zan==0) break;
		}
	}
	return(size);
}

s32 PcWrite(s32 fh,void *buffer,s32 size){
	u8 buf[256];
	s32 len,zan,ofs;
	zan=size;
	ofs=0;
	for(;;){
		if(zan>256){
			len=256;
		}
		else{
			len=zan;
		}
		buf[0]=0xa4;
		buf[1]=fh;
		buf[2]=fh>>8;
		buf[3]=fh>>16;
		buf[4]=fh>>24;
		buf[5]=len;
		buf[6]=len>>8;
		buf[7]=len>>16;
		buf[8]=len>>24;
		tx_wait(9,buf);
		memcpy(buf,(u8 *)buffer+ofs,len);
		tx_wait(len,buf);
		ofs+=len;
		zan-=len;
		if(zan==0) break;
	}
	return(size);
}

s32 PcLseek(s32 fh,s32 offset,s32 where){
	u32 buf[13];
	buf[0]=0xa5;
	buf[1]=fh;
	buf[2]=fh>>8;
	buf[3]=fh>>16;
	buf[4]=fh>>24;
	buf[5]=offset;
	buf[6]=offset>>8;
	buf[7]=offset>>16;
	buf[8]=offset>>24;
	buf[9]=where;
	buf[10]=where>>8;
	buf[11]=where>>16;
	buf[12]=where>>24;
	tx_wait(13,buf);
	rx_wait(4,buf);
	return(*((u32 *)buf));
}

s32 PcBRead(s32 fh,void *buffer,s32 size){//一度に読めるのは0x100000(1M)まで
	u32 i;
	u8 buf[257];
	buf[0]=0xa6;
	buf[1]=fh;
	buf[2]=fh>>8;
	buf[3]=fh>>16;
	buf[4]=fh>>24;
	buf[5]=size;
	buf[6]=size>>8;
	buf[7]=size>>16;
	buf[8]=size>>24;
	tx_wait(9,buf);
	rx_wait(4,&size);
	for(i=0;i<size;i++){
		*((u8 *)buffer+i)=*((u8 *)0x08000000+i);
	}
	return(size);
}

s32 PcBWrite(s32 fh,void *buffer,s32 size){//一度に書けるのは0x100000(1M)まで
	u32 i;
	u8 buf[10];
	buf[0]=0xa7;
	buf[1]=fh;
	buf[2]=fh>>8;
	buf[3]=fh>>16;
	buf[4]=fh>>24;
	buf[5]=size;
	buf[6]=size>>8;
	buf[7]=size>>16;
	buf[8]=size>>24;
	for(i=0;i<(size+3)/4;i++){
		*((u32 *)0x08000000+i)=*((u32 *)buffer+i);
	}
	tx_wait(9,buf);
	rx_wait(1,buf);	//RAM切り替え待ち
	return(size);
}

static s32 _udeci(u32 u,s8 *s,s32 i){
	u32 div,flg;
	div=1000000000;
	flg=0;
	for(;;){
		if(u/div){
			s[i++]='0'+(u/div);
			flg=1;
			u-=(u/div)*div;
		}
		else if(flg || (div==1)){
			s[i++]='0';
		}
		div=div/10;
		if(div==0) break;
	}
	return(i);
}

const static s8 hexchar[16]={
'0','1','2','3','4','5','6','7',
'8','9','A','B','C','D','E','F'
};

static s32 _hex(u32 u,s8 *s,s32 i,s32 keta){
	u32 div,flg,k;
	div=28;
	flg=0;
	for(k=8;k>0;k--){
		if(u>>div){
			s[i++]=hexchar[u>>div];
			flg=1;
			u-=(u>>div)<<div;
		}
		else if(flg || (div==0) || (keta>=k)){
			s[i++]='0';
		}
		div=div-4;
	}
	return(i);
}

//	%d:符号あり１０進数
//	%u:符号なし１０進数
//	%[n]x:１６進数（オプションでn(0-8)桁表示）
//	%s:文字列
//	%c:文字
//	\n:改行

s32 PcPrintf(char *fmt, ... ){
	va_list args;
	s32 i,d,keta;
	u32 u;
	s8 *ss;
	s8 *s;
	s8 buf[1+1+255];
	char chr;

	buf[0]=0xa0;
	s=(s8 *)(buf+2);
	va_start(args,fmt);
	for(i=0;;){
		chr = *fmt++;
		if(chr=='%'){
			keta=0;
again:
			chr = *fmt++;
			switch(chr){
			case 'd':		//	%d:符号あり１０進数
				d=va_arg(args,s32);
				if(d<0){
					s[i++]='-';
					u=-d;
				}
				else{
					u=d;
				}
				i=_udeci(u,s,i);
				break;
			case 'u':		//	%u:符号なし１０進数
				u=va_arg(args,u32);
				i=_udeci(u,s,i);
				break;
			case 'X':
			case 'x':		//	%x:１６進数
				u=va_arg(args,u32);
				i=_hex(u,s,i,keta);
				break;
			case 's':		//	%s:文字列
				ss=va_arg(args,s8 *);
				for(d=0;;d++){
					if(ss[d]==0) break;
					s[i++]=ss[d];
				}
				break;
			case 'c':		//	%c:文字
				d=va_arg(args,s32);
				s[i++]=d;
				break;
			default:
				if((chr>='0')&&(chr<='9'))
				{
					keta = keta * 10 + chr-'0';
					goto again;
				}
				// direct
				s[i++]=chr;
			}
		}
		else{
			if((i>240)||(chr==0)){
				s[i++]=0;
				break;
			}
			s[i++]=chr;
		}
	}
	va_end(args);
	buf[1]=i;
	tx_wait(2+i,buf);
	return(0);
}
