//////////////////////////////////////////////////
//Title    : fsm_test.c
//Auhtor   : Liu Wei
//Desc     : sccp fsm testing   
//Created  : 2007-05-25
//Revision :
//
//Revision :
//
//////////////////////////////////////////////////

#include "../../src/include/sccp.h"
#include "../../src/include/sccp_pub.h"
#include "../../src/include/scoc_if.h"

extern unsigned long spLogDebug_mask ;
extern  BYTE sccpFilterIndex ;
extern BYTE mtp_asciin_buf[80];

#ifdef _WXC_FSM_TEST
#define spLogFsm printf
#else 
#define spLogFsm
#endif 

typedef enum UL_ORG_STATE
{
    ORG_IDLE = 1, 
    ORG_CR,                     //CM LU
    ORG_CC,                     //CC
    ORG_LUR,                    //lu reject
    ORG_CLCD,                   //clean command
    ORG_CLCE,                   //clean complete
    ORG_DISCONN,
    ORG_SEND_UDT,               //PRN
    ORG_RECV_UDT,               //PRN ack
}
UL_OrgState;

typedef enum UL_DST_STATE
{
    DST_IDLE = 1,
    DST_CR,                     //CM LU
    DST_CC,                     //CC
    DST_LUR,                    //lu reject
    DST_CLCD,                   //clean command
    DST_CLCE,                   //clean complete
    DST_DISCONN,
    DST_RECV_UDT,               //PRN
    DST_SEND_UDT,               //PRN ack
}
UL_DstState;

typedef struct SCCP_UL
{
    u8  uUlSide;
    u8  uUlState;
    u32 uUlTestStartTimer;
    u32 uUlStateInterval;
    u32 uWaitTimer;
    u32 wConnId;
    int nPort;
    int nRemoteIP;
    int nSock;
}
SP_UL;

SP_UL tUl;

#define aifprn_udt_msg_len 0x52

static u8 aifprn_udt_msg[] = {
                              0x51, 0x62, 0x4f,
0x48, 0x04, 0x01, 0x62, 0x00, 0x35, 0x6b, 0x1e,
0x28, 0x1c, 0x06, 0x07, 0x00, 0x11, 0x86, 0x05,
0x01, 0x01, 0x01, 0xa0, 0x11, 0x60, 0x0f, 0x80,
0x02, 0x07, 0x80, 0xa1, 0x09, 0x06, 0x07, 0x04,
0x00, 0x00, 0x01, 0x00, 0x03, 0x02, 0x6c, 0x27,
0xa1, 0x25, 0x02, 0x01, 0x80, 0x02, 0x01, 0x04,
0x30, 0x1d, 0x80, 0x08, 0x64, 0x00, 0x92, 0x00,
0x00, 0x00, 0x83, 0xf4, 0x81, 0x08, 0x91, 0x44,
0x57, 0x55, 0x06, 0x00, 0x00, 0xf0, 0x82, 0x07,
0x91, 0x68, 0x57, 0x95, 0x00, 0x83, 0xf4, 
};

#define aifprnak_udt_msg_len 0x4b

static u8 aifprnak_udt_msg[] = {
                              0x4a, 0x64, 0x48,
0x49, 0x04, 0x01, 0x62, 0x00, 0x35, 0x6b, 0x2a, 
0x28, 0x28, 0x06, 0x07, 0x00, 0x11, 0x86, 0x05,
0x01, 0x01, 0x01, 0xa0, 0x1d, 0x61, 0x1b, 0x80, 
0x02, 0x07, 0x80, 0xa1, 0x09, 0x06, 0x07, 0x04,
0x00, 0x00, 0x01, 0x00, 0x03, 0x02, 0xa2, 0x03, 
0x02, 0x01, 0x00, 0xa3, 0x05, 0xa1, 0x03, 0x02,
0x01, 0x00, 0x6c, 0x14, 0xa2, 0x12, 0x02, 0x01, 
0x80, 0x30, 0x0d, 0x02, 0x01, 0x04, 0x04, 0x08,
0x91, 0x44, 0x57, 0x25, 0x31, 0x06, 0x00, 0xf6
};

#define aiflu_cr_msg_len 0x25

static u8 aiflu_cr_msg[] = {
                  0x0f, 0x23, 0x00, 0x21, 0x57, 
0x05, 0x08, 0x00, 0x57, 0xf0, 0x10, 0x0b, 0xb9,
0x0a, 0xfb, 0x17, 0x12, 0x05, 0x08, 0x70, 0x45,
0xf0, 0x10, 0x00, 0x01, 0x30, 0x08, 0x59, 0x04, 
0x10, 0x25, 0x00, 0x20, 0x30, 0x62, 0x21, 0x01,
};

#define aifcc_dt1_msg_len 0x00 

static u8 aifcc_dt1_msg[] = {
    
};

#define aiflurj_dt1_msg_len 0x07

static u8 aiflurj_dt1_msg[] = {
  0x06, 0x01, 0x00 , 0x03, 0x05, 0x04, 0x0b                   
};

#define aifclcd_dt1_msg_len 0x07

static u8 aifclcd_dt1_msg[] = {
  0x06, 0x00, 0x04 , 0x20, 0x04, 0x01, 0x09
};

#define aifclce_dt1_msg_len 0x05

static u8 aifclce_dt1_msg[] = {
 0x03, 0x00, 0x01 , 0x21, 0x00   
};

#define aiflu_rlsd_msg_len 0x00

static u8 aiflu_rlsd_msg[] = {
    
};

#define aiflu_rlc_msg_len 0x00

static u8 aiflu_rlc_msg[] = {
   
};

int get_socket(u_int32_t ip, int port)
{
     int  sock;
     int  on = 1;
     DWORD cmdarg = 1;
     struct sockaddr_in sin_addr;

     sin_addr.sin_family = AF_INET;
     sin_addr.sin_port = htons(port);
     sin_addr.sin_addr.s_addr = htonl(INADDR_ANY);

     if(!(sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
          perror("Get socket");
     setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
     if(bind(sock, (struct sockaddr *)&sin_addr, sizeof(struct sockaddr_in)) != 0)
     {
          perror("bind");
          return 0;
     }
     ioctl(sock, FIONBIO, &cmdarg);
     return (sock);
}

int ulRecv( u8 *pBuff )
{
	struct sockaddr_in sin_addr;
	int  addr_len;
	 
	return recvfrom(tUl.nSock, (char *)pBuff, 256, 0, (struct sockaddr *)&sin_addr, &addr_len);
}

void ulSend( u8 *pBuff ,  u8 uLen )
{
	 struct sockaddr_in sin_addr;
	
	 WxcAssert( uLen < 255 , "ulSend too long msg");
	 sin_addr.sin_family = AF_INET;
     sin_addr.sin_port = htons(tUl.nPort);
     sin_addr.sin_addr.s_addr = tUl.nRemoteIP;
     
     sendto(tUl.nSock, (char *)pBuff, 256, 0, (struct sockaddr *)&sin_addr, sizeof(struct sockaddr));
}

int ulSpecPeer()
{
	 char msg[256];

     memset(msg, 0, 256);
     ulRecv(msg);
     if( msg[0] )
     {
     	printf("Recv test msg: %s\r\n", msg);
        if( !strcmp(msg, "SCCP_TEST")  )
        {
        	tUl.uUlSide = 0;
        	printf("slave mode\r\n");
        	ulSend("SCCP_OK" , 7);       	
            tUl.uUlStateInterval=0;
            return 1;
        }
        else if( !strcmp(msg, "SCCP_OK")  )
        {
        	tUl.uUlSide = 1;
        	printf("master mode\r\n");          
            tUl.uUlStateInterval=0;
            return 1;
        }
        
     }
     if( tUl.uUlStateInterval++ % 200 )
     {     	 
     	ulSend("SCCP_TEST" , 9);   
     
     }
     return 0;
}

void ulInit()
{
	 int ip;
	 struct in_addr sin_addr;
	

     sin_addr.s_addr = tUl.nRemoteIP;
     
     memset(&tUl, 0, sizeof(SP_UL));
     tUl.uUlSide = 1;
     tUl.nPort = 6999;

     ip = GetLocalIP();
     tUl.nRemoteIP = ( ip ^ 0x00010000 );
     
     tUl.uWaitTimer = 20;
     memcpy( &sin_addr , &tUl.nRemoteIP , 4);
     printf("Remote ip : %s Start timer :%d \n" , inet_ntoa(sin_addr) ,tUl.uWaitTimer );
     tUl.nSock = get_socket(tUl.nRemoteIP, tUl.nPort);
     printf("get sock :%d \r\n",tUl.nSock);
     register_ssn ( 0xfe, 3 ); 
     mtp_asciin_buf[0] = 1;
     
     strcpy( &mtp_asciin_buf[1] , "log all" ); 
     printf("sizeof[sizeof(CO_ConnSection)* 4096]=%d\n", sizeof(CO_ConnSection)* 4096); 
     
}

void ulLogMsg ( SP_UiPriPara * pSpPri, u8 uDirection , SP_UD *pUD )
{
	char *pStr;
		 
    spGetUlPrimitiveStr ( pSpPri->uUiPri, pStr );
    
    if( uDirection )
    {
        spLogDebug ( SCCPDB_AIF , "UL=>SP : %s ", pStr );
    }
    else
    {
        spLogDebug ( SCCPDB_AIF , "UL<=SP : %s ", pStr );
    }
    if( NULL != pUD )
    {
    	spShowBCD ( 1, pUD->aUserData, pUD->uDataLen );
    }
}

extern void spLog ( char *info );

void ulLogState ( u8 uSide , u8 *pStr )
{
   char aStr[256];
    if( uSide )
    	sprintf(aStr ,"]Org Node[: %s state \n" , pStr);
    else
    	sprintf(aStr ,"]Dst Node[: %s state \n" , pStr); 	

    spLog(aStr);
}

void ul_sccp_addr( SCCP_ADDR *pAddr )
{
	memset( pAddr , 0 , sizeof(SCCP_ADDR) );
	
    pAddr->ip    = tUl.nRemoteIP;
    pAddr->DPC   = 40;
    pAddr->NetID = 2;
    pAddr->SSN   = 254;
    pAddr->RI    = RI_SSN;
    pAddr->GTI   = 0;
    pAddr->AI    = 3;
    
	return;
}

void ulSapFsm (  )
{
    SP_UiPriPara tSpPri;
    SP_UiPriUnion *pUPri;
    
    pUPri = &tSpPri.tPriUnion;
    
    if( !tUl.uUlState )
	{
	   if( ulSpecPeer() )
	   {
	   	  printf("----------------------OK------------------\r\n");
	   	  tUl.uUlState++;
	   }else
	   {
	   	  return;
	   }	
	}

    sccpFilterIndex = 0;
    spLogDebug_mask = 0xFFFFFFFF;
    
    //printf("Side : %d state : %d \n",tUl.uUlSide ,tUl.uUlState );
    if( tUl.uUlSide )
    {
        switch ( tUl.uUlState )
        {
        case ORG_IDLE:
            
            break;
        case ORG_SEND_UDT:     //PRN
            tSpPri.uUiPri = N_UNITDATA_REQ;
            ul_sccp_addr ( &pUPri->tPriNUDataReq.tCDA );
            ul_sccp_addr ( &pUPri->tPriNUDataReq.tCGA );
            pUPri->tPriNUDataReq.tRO.uRO = 1;
            pUPri->tPriNUDataReq.tUD.uDataLen = aifprn_udt_msg_len;
            memcpy ( &pUPri->tPriNUDataReq.tUD.aUserData, aifprn_udt_msg, pUPri->tPriNUDataReq.tUD.uDataLen );
            ulLogMsg ( &tSpPri, 1 , &pUPri->tPriNUDataReq.tUD);
            WxcAssert ( PostSp ( &tSpPri ), "ul post pri error while ORG_SEND_UDT state" );
            ulLogState( tUl.uUlSide ,"ORG_SEND_UDT" );
            tUl.uUlState++;
            tUl.uUlStateInterval = 0;
            return;
        case ORG_RECV_UDT:     //PRN ack
            if( SpSubmit ( &tSpPri  , 3) )
            {
                WxcAssert ( tSpPri.uUiPri == N_UNITDATA_IND, "ul recv pri error while ORG_RECV_UDT state" );
                ulLogMsg ( &tSpPri, 0 ,  &pUPri->tPriNUDataInd.tUD);
                tUl.uUlState++;
                tUl.uUlStateInterval = 0;
                ulLogState( tUl.uUlSide ,"ORG_RECV_UDT" );
                return ;
            }
            break;
        case ORG_CR:           //CM LU
            tSpPri.uUiPri = N_CONNECT_REQ;
            ul_sccp_addr ( &pUPri->tPriNConnReq.tCDA );
            pUPri->tPriNConnReq.uOptFlag = 0x08;

            pUPri->tPriNConnReq.tUD.uDataLen = aiflu_cr_msg_len;
            memcpy ( &pUPri->tPriNConnReq.tUD.aUserData, aiflu_cr_msg, pUPri->tPriNConnReq.tUD.uDataLen );
            ulLogMsg ( &tSpPri, 1 , &pUPri->tPriNConnReq.tUD);
            WxcAssert ( PostSp ( &tSpPri ), "ul post pri error while ORG_CR state" );
            tUl.wConnId = tSpPri.wConnId;
            WxcAssert ( tUl.wConnId < CO_CS_MPORT, "wConnId error " );
            tUl.uUlState++;
            tUl.uUlStateInterval = 0;
            ulLogState( tUl.uUlSide ,"ORG_CR" );
            return;
        case ORG_CC:           //CC
            if( SpSubmit ( &tSpPri  , 3) )
            {
                WxcAssert ( tSpPri.uUiPri == N_CONNECT_CFM, "ul recv pri error while ORG_CC state" );
                ulLogMsg ( &tSpPri, 0 ,  &pUPri->tPriNConnCfm.tUD);
                tUl.uUlState++;
                tUl.uUlStateInterval = 0;
                ulLogState( tUl.uUlSide ,"ORG_CC" );
                return ;
            }
            break;
        case ORG_LUR:          //lu reject
            if( SpSubmit ( &tSpPri  , 3) )
            {
                WxcAssert ( tSpPri.uUiPri == N_DATA_IND, "ul recv pri error while ORG_LUR state" );
                ulLogMsg ( &tSpPri, 0 ,  &pUPri->tPriNDataInd.tUD);
                tUl.uUlState++;
                tUl.uUlStateInterval = 0;
                ulLogState( tUl.uUlSide ,"ORG_LUR" );
                return ;
            }
            break;
        case ORG_CLCD:         //clean command
            if( SpSubmit ( &tSpPri  , 3) )
            {
                WxcAssert ( tSpPri.uUiPri == N_DATA_IND, "ul recv pri error while ORG_CLCD state" );
                ulLogMsg ( &tSpPri, 0 ,  &pUPri->tPriNDataInd.tUD);
                tUl.uUlState++;
                tUl.uUlStateInterval = 0;
                ulLogState( tUl.uUlSide ,"ORG_CLCD" );
                return ;
            }
            break;
        case ORG_CLCE:         //clean complete
            tSpPri.uUiPri = N_DATA_REQ;

            pUPri->tPriNDataReq.tUD.uDataLen = aifclce_dt1_msg_len;
            memcpy ( &pUPri->tPriNDataReq.tUD.aUserData, aifclce_dt1_msg, pUPri->tPriNDataReq.tUD.uDataLen );
            ulLogMsg ( &tSpPri, 1 , &pUPri->tPriNDataReq.tUD);
            WxcAssert ( PostSp ( &tSpPri ), "ul post pri error while ORG_CLCE state" );
            tUl.uUlState++;
            tUl.uUlStateInterval = 0;
            ulLogState( tUl.uUlSide ,"ORG_CLCE" );
            return;
        case ORG_DISCONN:
            if( SpSubmit ( &tSpPri  , 3) )
            {
                WxcAssert ( tSpPri.uUiPri == N_DISCONNECT_IND, "ul recv pri error while ORG_RLSD state" );
                ulLogMsg ( &tSpPri, 0  , NULL );
                tUl.uUlState++;
                tUl.uUlStateInterval = 0;
                ulLogState( tUl.uUlSide ,"ORG_CLCE" );
                return ;
            }
            break;
        default:
            printf ( "\n\n\n======================SP Org Test End=================\n\n\n" );
            exit(1);
            break;
        }
        if( ORG_IDLE == tUl.uUlState )
        {
            if( tUl.uUlTestStartTimer++ >= tUl.uWaitTimer )
            {
                printf ( "\n\n\n======================SP Org Test Start=================\n\n\n" );
                tUl.uUlState++;
                
            }
        }
        else
        {
            if( tUl.uUlStateInterval++ >= 200 )
            {
                //WxcAssert ( tUl.uUlState != ORG_RECV_UDT, "ORG_RECV_UDT state timer out" );
                //WxcAssert ( tUl.uUlState != ORG_CC, "ORG_CC state timer out" );
                //WxcAssert ( tUl.uUlState != ORG_LUR, "ORG_LUR state timer out" );
                //WxcAssert ( tUl.uUlState != ORG_CLCD, "ORG_CLCD state timer out" );
                //WxcAssert ( tUl.uUlState != ORG_DISCONN, "ORG_DISCONN state timer out" );
                tUl.uUlStateInterval = 0;
            }
        }
    }
    else
    {
       switch ( tUl.uUlState )
        {
        case DST_IDLE:

            break;
        case DST_RECV_UDT:     //PRN
        	if( SpSubmit ( &tSpPri  , 3) )
            {
                WxcAssert ( tSpPri.uUiPri == N_UNITDATA_IND, "ul recv pri error while DST_RECV_UDT state" );
                ulLogMsg ( &tSpPri, 0 ,&pUPri->tPriNUDataInd.tUD);
                tUl.uUlState++;
                tUl.uUlStateInterval = 0;
                ulLogState( tUl.uUlSide ,"DST_RECV_UDT" );
                return ;
            }
            break;
        case DST_SEND_UDT:     //PRN ack
            tSpPri.uUiPri = N_UNITDATA_REQ;
            ul_sccp_addr ( &pUPri->tPriNUDataReq.tCDA );
            ul_sccp_addr ( &pUPri->tPriNUDataReq.tCGA );
            pUPri->tPriNUDataReq.tRO.uRO = 1;
            pUPri->tPriNUDataReq.tUD.uDataLen = aifprnak_udt_msg_len;
            memcpy ( &pUPri->tPriNUDataReq.tUD.aUserData, aifprnak_udt_msg, pUPri->tPriNUDataReq.tUD.uDataLen );
            ulLogMsg ( &tSpPri, 1 , &pUPri->tPriNUDataReq.tUD);
            WxcAssert ( PostSp ( &tSpPri ), "ul post pri error while DST_SEND_UDT state" );
            tUl.uUlState++;
            tUl.uUlStateInterval = 0;
            ulLogState( tUl.uUlSide ,"DST_SEND_UDT" );
            return;
        case DST_CR:           //CM LU
        	if( SpSubmit ( &tSpPri  , 3) )
            {
                WxcAssert ( (tSpPri.uUiPri == N_CONNECT_IND), "ul recv pri error while DST_CR state" );
                ulLogMsg ( &tSpPri, 0 , &pUPri->tPriNConnInd.tUD);
                tUl.uUlState++;
                tUl.uUlStateInterval = 0;
                ulLogState( tUl.uUlSide ,"DST_CR" );
                return ;
            }
            break;
        case DST_CC:           //CC
            tSpPri.uUiPri = N_CONNECT_RSP;
            tSpPri.wConnId = tUl.wConnId;
            pUPri->tPriNConnRsp.tUD.uDataLen = aifcc_dt1_msg_len;
            pUPri->tPriNConnRsp.uOptFlag = 0x00;
            ulLogMsg ( &tSpPri, 1 , &pUPri->tPriNConnRsp.tUD );
            WxcAssert ( PostSp ( &tSpPri ), "ul post pri error while DST_CC state" );
            WxcAssert ( tUl.wConnId < CO_CS_MPORT, "wConnId error " );
            tUl.uUlState++;
            tUl.uUlStateInterval = 0;
            ulLogState( tUl.uUlSide ,"DST_CC" );
            return;
        case DST_LUR:          //lu reject
            tSpPri.uUiPri = N_DATA_REQ;
            tSpPri.wConnId = tUl.wConnId;
            pUPri->tPriNDataReq.tUD.uDataLen = aiflurj_dt1_msg_len;
            memcpy ( &pUPri->tPriNDataReq.tUD.aUserData, aiflurj_dt1_msg, pUPri->tPriNDataReq.tUD.uDataLen );
            ulLogMsg ( &tSpPri, 1 , &pUPri->tPriNDataReq.tUD);
            WxcAssert ( PostSp ( &tSpPri ), "ul post pri error while DST_LUR state" );
            tUl.uUlState++;
            tUl.uUlStateInterval = 0;
            ulLogState( tUl.uUlSide ,"DST_LUR" );
            return;
        case DST_CLCD:         //clean command
            tSpPri.uUiPri = N_DATA_REQ;
            tSpPri.wConnId = tUl.wConnId;
            pUPri->tPriNDataReq.tUD.uDataLen = aifclcd_dt1_msg_len;
            memcpy ( &pUPri->tPriNDataReq.tUD.aUserData, aifclcd_dt1_msg, pUPri->tPriNDataReq.tUD.uDataLen );
            ulLogMsg ( &tSpPri, 1 ,&pUPri->tPriNDataReq.tUD);
            WxcAssert ( PostSp ( &tSpPri ), "ul post pri error while DST_CLCD state" );
            tUl.uUlState++;
            tUl.uUlStateInterval = 0;
            ulLogState( tUl.uUlSide ,"DST_CLCD" );
            return;
        case DST_CLCE:         //clean complete
        	if( SpSubmit ( &tSpPri  , 3) )
            {
                WxcAssert ( tSpPri.uUiPri == N_DATA_IND, "ul recv pri error while DST_CLCE state" );
                ulLogMsg ( &tSpPri, 0 , &pUPri->tPriNDataInd.tUD);
                tUl.uUlState++;
                tUl.uUlStateInterval = 0;
                ulLogState( tUl.uUlSide ,"DST_CLCE" );
                return ;
            }
            break;
        case DST_DISCONN:
            tSpPri.uUiPri = N_DISCONNECT_REQ;
            tSpPri.wConnId = tUl.wConnId;

            pUPri->tPriNDisconnReq.eREA = REA_UDISC_EUF;
            pUPri->tPriNDisconnReq.tUD.uDataLen = aiflu_rlsd_msg_len;
            pUPri->tPriNDisconnReq.uOptFlag = 0x00;
            ulLogMsg ( &tSpPri, 1  , NULL);
            WxcAssert ( PostSp ( &tSpPri ), "ul post pri error while DST_DISCONN state" );
            tUl.uUlState++;
            tUl.uUlStateInterval = 0;
            ulLogState( tUl.uUlSide ,"DST_DISCONN" );
            return;
        default: 
            printf ( "\n\n\n======================SP Dst Test End=================\n\n\n" );
            exit(1);
            break;
        }
        if( DST_IDLE == tUl.uUlState )
        {
            if( tUl.uUlTestStartTimer++ >= tUl.uWaitTimer )
            {
                printf ( "\n\n\n======================SP Dst Test Start=================\n\n\n" );
                tUl.uUlState++;
                tUl.uUlStateInterval = 0;
            }
        }
        else
        {
            if( tUl.uUlStateInterval++ >= 200 )
            {
                //WxcAssert ( tUl.uUlState != DST_RECV_UDT, "DST_RECV_UDT state timer out" );
                //WxcAssert ( tUl.uUlState != DST_CR, "DST_CR state timer out" );
                //WxcAssert ( tUl.uUlState != DST_CLCE, "DST_CLCE state timer out" );
                tUl.uUlStateInterval = 0;
            }
        }
    }
}

void ll_cr (  )
{

}

void ll_cc (  )
{

}

void ll_cref (  )
{

}

void ll_rlsd (  )
{

}

void ll_rlc (  )
{

}

void ll_udt (  )
{

}

void ll_dt1 (  )
{

}

void ll_sap (  )
{

}
