/**
 * 同時に8接続まで出来るtelnetサーバ。
 * 23番ポートでListenして、受信データをエコーバックします。
 */
#include "boot/sketch.h"
#include "NyLPC_net.h"
#include "../netif/mimicip/NyLPC_cMiMicIpNetIf.h"

//イーサネット用の初期化情報
const struct NyLPC_TEthAddr ethaddr=NyLPC_TEthAddr_pack(0x02,0x01,0x02,0x03,0x04,0x05);
const struct NyLPC_TIPv4Addr ipaddr=NyLPC_TIPv4Addr_pack(192,168,128,201);
const struct NyLPC_TIPv4Addr netmask=NyLPC_TIPv4Addr_pack(255,255,255,0);
const struct NyLPC_TIPv4Addr gateway=NyLPC_TIPv4Addr_pack(192,168,128,254);



#define NUM_OF_TH 8
struct TProc{
	NyLPC_TcThread_t th;
	NyLPC_TiTcpSocket_t* socket;
}proc[NUM_OF_TH];

const struct NyLPC_TiNetInterface_Interface* netif;
void setup(void)
{
	int i;
	//uipサービス初期化。いろいろ利用可能に。
	netif=NyLPC_cMiMicIpNetIf_getNetInterface();
	NyLPC_cNet_initialize(netif);

	//TCPスレッドの準備
	for(i=0;i<NUM_OF_TH;i++){
		NyLPC_cThread_initialize(&(proc[i].th),160,NyLPC_TcThread_PRIORITY_IDLE);
		proc[i].socket=NyLPC_cNet_createTcpSocketEx(NyLPC_TSocketType_UDP_NORMAL);
	}
}

/**
 * サーバプロセス。
 * 接続済のソケットを処理します。
 */
int server(void* p)
{
	struct TProc* proc=(struct TProc*)p;
	NyLPC_TInt32 s;
	const char* buf;
	const char* src;
	NyLPC_TInt16 sent;


	if(!NyLPC_iTcpSocket_accept(proc->socket,3000)){
		return -1;
	}
	//接続中は送信する。
	s=NyLPC_iTcpSocket_precv(proc->socket,(const void**)&buf,1000);
	while(s>=0){
		if(s>0){
			//受信した内容をそのまま送信。
			src=buf;
			while(s>0){
				sent=NyLPC_iTcpSocket_send(proc->socket,src,s,30000);
				if(sent<=0){
					NyLPC_iTcpSocket_close(proc->socket,10000);
					return -1;
				}
				//読み出し位置を調整
				src+=sent;
				s-=sent;
				NyLPC_iTcpSocket_pseek(proc->socket,sent);
			}
		}
		s=NyLPC_iTcpSocket_precv(proc->socket,(const void**)&buf,1000);
	}
	NyLPC_iTcpSocket_close(proc->socket,10000);
	return 1;
}



void loop(void)
{
	NyLPC_TcIPv4Config_t config;
	NyLPC_TiTcpListener_t* listener;
	int i;


	NyLPC_cIPv4Config_initialzeForEthernet(&config,&ethaddr,1480);
	NyLPC_cIPv4Config_setDefaultRoute(&config,&gateway);
	NyLPC_cIPv4Config_setIp(&config,&ipaddr,&netmask);


	listener=NyLPC_cNet_createTcpListenerEx(23);
	NyLPC_cNet_start(&config);
	for(;;){
		//ターミネイト状態のタスクを検索
		for(i=0;i<NUM_OF_TH;i++){
			if(NyLPC_cThread_isTerminated(&(proc[i].th))){
				//リスニング
				if(!NyLPC_iTcpListener_listen(listener,proc[i].socket,10000)){
					continue;
				}
				//タスク起動
				NyLPC_cThread_start(&(proc[i].th),server,&(proc[i]));
			}
		}
	}
	for(;;){}
}
