/***********************************************************
Copyright (C), LGC Wireless.
File Name:		isdn_fsm.c
Description:	ISDN FSM
Version:		v9.0.0
Author:			Gengxin Chen
Create Date:	2008-2-19
History:
	<author>	<date>		<version>		<desc>
	
************************************************************/

#include "./include/isdn_const.h"
#include "./include/isdn_rm.h"
#include "./include/isdn_debug.h"
#include "./include/isdn_ext.h"
#include "./include/isdn_inc.h"


#define USR	0x00
#define LN	0x02
#define TN	0x03
#define RLN	0x04
#define DF	RLN
u8 cause_to_loc[128]={
    	DF,	LN,	LN,	LN,	DF,	DF,	LN,	LN,	DF,	DF,	
    	DF,	DF,	DF,	DF,	DF,	DF, USR,USR,RLN,RLN,
    	DF,	USR,LN,	DF,	DF,	RLN,LN,	RLN,RLN,RLN,
    	LN,	RLN,DF,	DF,	RLN,DF,	DF,	DF,	USR,DF,	
    	DF,	RLN,RLN,LN,	LN,	DF,	DF,	USR,DF,	DF,	
    	RLN,DF,	DF,	DF,	DF,	RLN,DF,	LN,	LN,	DF,	
    	DF,	DF,	DF,	LN,	DF,	LN,	DF,	DF,	DF,	RLN,
    	DF,	DF,	DF,	DF,	DF,	DF,	DF,	DF,	DF,	DF,
    	DF,	LN,	DF,	LN,	LN,	LN,	LN,	RLN,USR,DF,	
    	DF,	LN,	DF,	DF,	DF,	LN,	LN,	RLN,LN,	RLN,
    	LN,	LN,	RLN,DF,	DF,	DF,	DF,	DF,	DF,	DF,	
    	DF,	RLN,DF,	DF,	DF,	DF,	DF,	DF,	DF,	DF,		
    	DF,	DF,	DF,	DF,	DF,	DF,	DF,	DF
};

u16 cr_start[ISDN_MAX_CG] = {0};
u8 cr_state[4096] = {0};

void isdn_cpc_proc(u32 pid);
int isdn_event_handle(u32 pid, u8 primitive);//, u8 eventType)
static int isdn_cc_nt(u32 pid);
static int isdn_cc_lt(u32 pid);
extern int isdn_send_msg(u32 pid, u8 msg_type);
extern int isdn_send_maintenance_msg(u32 pid, u8 msg_type);


/*************************************************************
Function:		cr_sel
Description:	according to port id, selection the idle call reference
Input:		pid:port id, indicate the cic of the IUA link
Return:		ISDN_CM_OK:success
			ISDN_CM_FAILED:failed
*************************************************************/
int cr_sel(u32 pid)
{
	u16 tmp_cr, i, byte_offset, circuit_id, cg_id;
	u8 bit_offset, key;
	const pal_circuit_struct *circuit_ptr = NULL;
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];
	
	circuit_id = pid / ISDN_CIRCUIT_CIC;
	circuit_ptr = pal_circuit_ptr(circuit_id);
	if(circuit_ptr == NULL)
		return ISDN_CM_FAILED;
	
	cg_id = circuit_ptr->cg_id;	
	tmp_cr = (cr_start[cg_id] & 0x3FFF);
	
	for(i = 0; i < 0x3FFF; i++)
	{ 
		tmp_cr++;
		tmp_cr &= 0x3FFF;
		if(tmp_cr != 0)
		{
			tmp_cr = (tmp_cr | ((circuit_ptr->attrib.plat_id & 0x01) << 14));
			byte_offset = tmp_cr / 8;
			bit_offset = tmp_cr % 8;
			key = ((cr_state[byte_offset] >> bit_offset) & 0x01);
			if(key == 0)
			{
				pPort->call_ref = (tmp_cr | 0x8000);	//call_ref[pid] 
				cr_start[cg_id] = tmp_cr;
				cr_state[byte_offset] = (cr_state[byte_offset] | (0x01 << bit_offset));
				return ISDN_CM_OK;
			}
		}
	}
	
	return ISDN_CM_FAILED;
}

/*************************************************************
Function:		rel_cr
Description:	release the call reference
Input:		pid:port id
Return:		ISDN_CM_OK:success
*************************************************************/
int rel_cr(u32 pid)
{
	u16 tmp_cr, byte_offset;
	u8 bit_offset;
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];
	
	tmp_cr = (pPort->call_ref & 0x7FFF);
	
	if(pPort->call_ref & 0x8000)	
	{
		byte_offset = tmp_cr / 8;
		bit_offset = tmp_cr % 8;
		cr_state[byte_offset] = (cr_state[byte_offset] ^ (0x01 << bit_offset));
	}
	pPort->call_ref = 0;
	pPort->callout_fg = 0;
	//msg_cref[pid] = 0;

	return ISDN_CM_OK;
}

/*************************************************************
Function:		rel_B_chnl
Description:	release B-channel link
Input:		pid:port id
Return:		ISDN_CM_OK:success
*************************************************************/
int rel_B_chnl(u32 pid)
{
	u8 flag;
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];
	
	flag = pPort->enable;
	if (flag != 0)
	{
		pPort->enable = 0;
		pPort->su_proc_id = 0;
		pPort->cic_val = 0;
		pPort->pre_send_msg = 0;
	}

	return ISDN_CM_OK;
}

/*************************************************************
Function:		isdn_cpc_clear
Description:	clearing the  interrelated state of the call at call processing control
Output:		pPort:port structure pointer
Return:		NULL
*************************************************************/
inline void isdn_cpc_clear(ISDN_Port_struct *pPort)
{
	pPort->timer_flag = 0;
	pPort->cic_state.call_state = IDLE_FLAG;
	pPort->fsm_state.cpc_state = NULL_STATE;
}

/*************************************************************
Function:		isdn_rel_proc
Description:	release isdn module process, include rel_B_chnl() and rel_cr()
Input:		pid:port id, cause:release reason value
Return:		ISDN_CM_OK:success
*************************************************************/
int isdn_rel_proc(u32 pid, u32 cause)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	isdn_event_handle(pid, ISDN_RELEASE_IND);
	pPort->w_time = 0;
	rel_B_chnl(pid);
	isdn_send_msg(pid, MSG_REL_COMP);
	rel_cr(pid);
	isdn_cpc_clear(pPort);
	return ISDN_CM_OK;
}

/*************************************************************
Function:		nr_proc
Description:	processing nr, nr is the interval state identifier in the SDL diagrams
Input:		pid:port id
Return:		if LT side, successfully enter the state u19
			if NT side, successfully enter the state n19
*************************************************************/
int nr_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	pPort->w_time = 0;	//start t308
	pPort->timeout_fg = 0;
	isdn_send_msg(pid, MSG_REL);
	return REL_REQ_STATE;
}

/*************************************************************
Function:		nd_proc
Description:	processing nd, nd is the interval state identifier in the SDL diagrams
Input:		pid:port id
Return:		if LT side, successfully enter the state u12
			if NT side, successfully enter the state n11
*************************************************************/
int nd_proc(u32 pid)
{
	int circuit_id;
	const pal_circuit_struct *circuit_ptr = NULL;
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	circuit_id = pid / ISDN_CIRCUIT_CIC;
	circuit_ptr = pal_circuit_ptr(circuit_id);
	if(circuit_ptr == NULL)
	{
		isdn_log_err(pid, "nd_proc err!circuit_id %d can't find circuit_ptr", circuit_id);
		return ISDN_CM_FAILED;
	}
	
	/*disconnect B-channel*/
	pPort->w_time = 0;	//stop all
	isdn_event_handle(pid, ISDN_DISCONNECT_IND);
	if(circuit_ptr->attrib.user_network_if)
		return DISC_IND_STATE;
	else
		return DISC_REQ_STATE;
}

/*************************************************************
Function:		nc_proc
Description:	processing nc, nc is the interval state identifier in the SDL diagrams
Input:		pid:port id
Return:		if LT side, successfully enter the state u11
			if NT side, successfully enter the state n12
*************************************************************/
int nc_proc(u32 pid)
{
	int circuit_id;
	const pal_circuit_struct *circuit_ptr = NULL;
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	circuit_id = pid / ISDN_CIRCUIT_CIC;
	circuit_ptr = pal_circuit_ptr(circuit_id);
	if(circuit_ptr == NULL)
	{
		isdn_log_err(pid, "nc_proc err!circuit_id %d can't find circuit_ptr", circuit_id);
		return ISDN_CM_FAILED;
	}

	/*disconnect B-channel*/
	pPort->w_time = 0;	//stop all and start t305
	isdn_send_msg(pid, MSG_DISC);
	if(circuit_ptr->attrib.user_network_if)
		return DISC_REQ_STATE;
	else
		return DISC_IND_STATE;
}

/*************************************************************
Function:		isdn_set_cause
Description:	set the reason value, and keep into cause_ptr
Input:		val:reason value
Output:		cause_ptr:cause structure pointer
Return:		NULL
*************************************************************/
void isdn_set_cause(CauseStr *cause_ptr, u8 val)
{
	cause_ptr->pres = 1;
	cause_ptr->ext_flag = 0x0;
	cause_ptr->b3.has_ext_a = 1;
	cause_ptr->b3.code_stan = 0x0;	//CCITT standardized coding
	cause_ptr->b3.loc = cause_to_loc[val];	
	cause_ptr->cause_val = val;
}

/*************************************************************
Function:		isdn_set_status
Description:	set the call state, and keep into status_ptr
Input:		state:call state, cause_val:reason value
Output:		status_ptr:status structure pointer
Return:		NULL
*************************************************************/
void isdn_set_status(IsdnStatus *status_ptr, u8 state, u8 cause_val)
{
	isdn_set_cause(&status_ptr->cause, cause_val);
	status_ptr->call_stat.code_stan = 0x0;
	status_ptr->call_stat.stat_val = (state & 0x3F);
}


/*************************************************************
Function:		n0_proc
Description:	Null State, no call exists. 
				Handling the process and entering into next call state
Input:		pid:port id
Return:		state value:success
			-1:failed
*************************************************************/
int n0_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];
	
	if(pPort->primitive_cmd == ISDN_SETUP_REQ)
	{
		pPort->primitive_cmd = 0;
		if(cr_sel(pid) != 1)
		{
			isdn_log_err(pid, "cr_sel error!\r\n");
			return NULL_STATE;
		}
		isdn_send_msg(pid, MSG_SETUP);
		pPort->timer_flag = CALLIN_FLAG;
		pPort->w_time = 0;	//start t303
		pPort->timeout_fg = 0;
		return CALL_PRE_STATE;
	}
	else if(pPort->msg_cmd == MSG_SETUP)
	{
		pPort->msg_cmd = 0;
		//pPort->call_ref = msg_cref[pid];
		isdn_event_handle(pid, ISDN_SETUP_IND);
		return CALL_INIT_STATE;
	}
	//MSG_REL, MSG_REL_COMP, MSG_STATUS, and MSG_STAT_ENQ  are doing in n0_ext_proc()
	
	return -1;
}

/*************************************************************
Function:		n1_proc
Description:	Call initiated state, this state exists for an outgoing call 
				when the network has received a call establishment request 
				but has not yet responded.
				Handling the process and entering into next call state.
Input:		pid:port id
Return:		state value:success
			-1:failed
*************************************************************/
int n1_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->primitive_cmd == ISDN_PROC_REQ)
	{
		pPort->primitive_cmd = 0;
		/*Connect B-channel*/
		isdn_send_msg(pid, MSG_CALL_PROC);
		return OUT_CALL_PROC_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_MORE_INFO_REQ)
	{
		pPort->primitive_cmd = 0;
		pPort->w_time = 0;	//start t302
		/*Connect B-channel*/
		isdn_send_msg(pid, MSG_SETUP_ACK);	
		return OVERLAP_SD_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_REJECT_REQ)
	{
		pPort->primitive_cmd = 0;
		rel_B_chnl(pid);
		isdn_send_msg(pid, MSG_REL_COMP);
		rel_cr(pid);
		return NULL_STATE;
	}

	return -1;
}

/*************************************************************
Function:		n2_proc
Description:	Overlap sending state, this state exists for an outgoing call 
				when the network has acknowledged the call establishment request 
				and is prepared to receive additional call information (if any) 
				in overlap mode.  
				Handling the process and entering into next call state.
Input:		pid:port id
Return:		state value:success
			-1:failed
*************************************************************/
int n2_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->primitive_cmd == ISDN_PROC_REQ)
	{
		pPort->primitive_cmd = 0;
		pPort->w_time = 0;	//stop t302
		isdn_send_msg(pid, MSG_CALL_PROC);
		return OUT_CALL_PROC_STATE;
	}
	else if(pPort->msg_cmd == MSG_INFORMATION)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//start or restart t302
		isdn_event_handle(pid, ISDN_INFO_IND);
		return OVERLAP_SD_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_ALERT_REQ)
	{
		pPort->primitive_cmd = 0;
		pPort->w_time = 0;	//stop t302
		isdn_send_msg(pid, MSG_ALERT);
		return CALL_DV_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_SETUP_RSP)
	{
		pPort->primitive_cmd = 0;
		pPort->w_time = 0;	//stop t302
		/* Connect Backwards B-channel Here */
		isdn_send_msg(pid, MSG_CONN);
		return ACTIVE_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_PROG_REQ)
	{
		pPort->primitive_cmd = 0;
		pPort->w_time = 0;	//stop t302
		isdn_send_msg(pid, MSG_PROG);
		return OVERLAP_SD_STATE;
	}

	return -1;
}

/*************************************************************
Function:		n3_proc
Description:	Outgoing call proceeding state, this state exists for an outgoing call 
				when the network has sent acknowledgement that the network has received 
				all call information necessary to effect call establishment.
				Handling the process and entering into next call state.
Input:		pid:port id
Return:		state value:success
			-1:failed
*************************************************************/
int n3_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->primitive_cmd == ISDN_ALERT_REQ)
	{
		pPort->primitive_cmd = 0;
		isdn_send_msg(pid, MSG_ALERT);
		return CALL_DV_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_SETUP_RSP)
	{
		pPort->primitive_cmd = 0;		
		/* Connect Backwards B-channel Here */
		isdn_send_msg(pid, MSG_CONN);
		return ACTIVE_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_PROG_REQ)
	{
		pPort->primitive_cmd = 0;
		isdn_send_msg(pid, MSG_PROG);
		return OUT_CALL_PROC_STATE;
	}

	return -1;
}

/*************************************************************
Function:		n4_proc
Description:	Call delivered state, this state exists for an outgoing call 
				when the network has indicated that remote user alerting 
				has been initiated.
				Handling the process and entering into next call state.
Input:		pid:port id
Return:		state value:success
			-1:failed
*************************************************************/
int n4_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->primitive_cmd == ISDN_SETUP_RSP)
	{
		pPort->primitive_cmd = 0;
		/* Connect Backwards B-channel Here */
		isdn_send_msg(pid, MSG_CONN);
		return ACTIVE_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_PROG_REQ)
	{
		pPort->primitive_cmd = 0;
		isdn_send_msg(pid, MSG_PROG);
		return CALL_DV_STATE;
	}

	return -1;
}

/*************************************************************
Function:		n6_proc
Description:	Call present state, this state exists for an incoming call 
				when the network has sent a call establishment request 
				but has not yet received a satisfactory response.
				Handling the process and entering into next call state.
Input:		pid:port id
Return:		state value:success
			-1:failed
*************************************************************/
int n6_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->msg_cmd == MSG_CALL_PROC)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t303 and start t310
		isdn_event_handle(pid, ISDN_PROC_IND);
		return IN_CALL_PROC_STATE;
	}
	else if(pPort->msg_cmd == MSG_ALERT)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t303 and start t301
		isdn_event_handle(pid, ISDN_ALERT_IND);
		return CALL_RV_STATE;
	}
	else if(pPort->msg_cmd == MSG_CONN)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t303
		pPort->primitive_cmd = ISDN_SETUP_CNF;	//msc does not provide ISDN_SETUP_COMP_REQ to isdn
		isdn_event_handle(pid, ISDN_SETUP_CNF);
		return CONN_REQ_STATE;
	}
	else if(pPort->msg_cmd == MSG_SETUP_ACK)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t303 and start t304
		isdn_event_handle(pid, ISDN_MORE_INFO_IND);
		return OVERLAP_RV_STATE;
	}
	else if(pPort->msg_cmd == MSG_REL_COMP)	//do it temporarily in isdn_comm_ctrl()
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t303
//		isdn_event_handle(pid, ISDN_REJ_IND);
		rel_B_chnl(pid);
		rel_cr(pid);
		return NULL_STATE;
	}

	return -1;
}

/*************************************************************
Function:		n7_proc
Description:	Call received state, this state exists for an incoming call 
				when the network has received an indication that the user is alerting 
				but has not yet received an answer.
				Handling the process and entering into next call state.
Input:		pid:port id
Return:		state value:success
			-1:failed
*************************************************************/
int n7_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->msg_cmd == MSG_CONN)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t301
		pPort->primitive_cmd = ISDN_SETUP_CNF;	//msc does not provide ISDN_SETUP_COMP_REQ to isdn
		isdn_event_handle(pid, ISDN_SETUP_CNF);
		return CONN_REQ_STATE;
	}	
	else if(pPort->msg_cmd == MSG_PROG)	//support U04_09
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t310
		isdn_event_handle(pid, ISDN_PROG_IND);
		return CALL_DV_STATE;
	}

	return -1;
}

/*************************************************************
Function:		n8_proc
Description:	Connect request state, this state exists for an incoming call 
				when the network has received an answer but the network has not yet 
				awarded the call.
				Handling the process and entering into next call state.
Input:		pid:port id
Return:		state value:success
			-1:failed
*************************************************************/
int n8_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->primitive_cmd == ISDN_SETUP_COMP_REQ)
	{
		pPort->primitive_cmd = 0;
		/* Connect Backwards B-channel Here */
		isdn_send_msg(pid, MSG_CONNACK);
		return ACTIVE_STATE;
	}

	return -1;
}

/*************************************************************
Function:		n9_proc
Description:	Incoming call proceeding state, this state exists for an incoming call 
				when the network has received acknowledgement that the user has received 
				all call information necessary to effect call establishment.
				Handling the process and entering into next call state.
Input:		pid:port id
Return:		state value:success
			-1:failed
*************************************************************/
int n9_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->msg_cmd == MSG_ALERT)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t310 and start t301
		isdn_event_handle(pid, ISDN_ALERT_IND);
		return CALL_RV_STATE;
	}
	else if(pPort->msg_cmd == MSG_CONN)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t310
		pPort->primitive_cmd = ISDN_SETUP_CNF;	//msc does not provide ISDN_SETUP_COMP_REQ to isdn
		isdn_event_handle(pid, ISDN_SETUP_CNF);
		return CONN_REQ_STATE;
	}
	else if(pPort->msg_cmd == MSG_PROG)
	{
		pPort->msg_cmd = 0;
		isdn_event_handle(pid, ISDN_PROG_IND);
		return IN_CALL_PROC_STATE;
	}

	return -1;
}

/*************************************************************
Function:		n10_proc
Description:	Active state, this state exists for an incoming call 
				when the network has awarded the call to the called user, and 
				this state exists for an outgoing call when the network has indicated 
				that the remote user has answered the call.
				Handling the process and entering into next call state.
Input:		pid:port id
Return:		state value:success
			-1:failed
*************************************************************/
int n10_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->msg_cmd == MSG_CONNACK)
	{
		pPort->msg_cmd = 0;
		return ACTIVE_STATE;
	}
	else if(pPort->msg_cmd == MSG_NOTI)
	{
		pPort->msg_cmd = 0;
		isdn_event_handle(pid, ISDN_NOTI_IND);
		return ACTIVE_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_NOTI_REQ)
	{
		pPort->primitive_cmd = 0;
		isdn_send_msg(pid, MSG_NOTI);
		return ACTIVE_STATE;
	}

	return -1;
}

/*************************************************************
Function:		n11_proc
Description:	Disconnect request state, this state exists when the network has received 
				a request from the user to clear the end-to-end connection (if any).
				Handling the process and entering into next call state.
Input:		pid:port id
Return:		state value:success
			-1:failed
*************************************************************/
int n11_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->primitive_cmd == ISDN_RELEASE_REQ)
	{
		pPort->primitive_cmd = 0;
		return nr_proc(pid);		//REL_REQ_STATE;
	}
	else if(pPort->msg_cmd == MSG_REL) 
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop all
		memcpy(&isdn_sd_msg.msg_list.relComp.cause, &isdn_rv_msg.msg_list.rel.cause, sizeof(CauseStr));
		isdn_event_handle(pid, ISDN_RELEASE_CNF);
		rel_B_chnl(pid);
		isdn_send_msg(pid, MSG_REL_COMP);
		rel_cr(pid);
		isdn_cpc_clear(pPort);
		return NULL_STATE;
	}

	return -1;
}

/*************************************************************
Function:		n12_proc
Description:	Disconnect indication state, this state exists when the network has 
				disconnected the end-to-end connection (if any) and has sent an 
				invitation to disconnect the user-network connection.
				Handling the process and entering into next call state.
Input:		pid:port id
Return:		state value:success
			-1:failed
*************************************************************/
int n12_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->msg_cmd == MSG_DISC)
	{
		pPort->msg_cmd = 0;
		memcpy(&isdn_sd_msg.msg_list.rel.cause, &isdn_rv_msg.msg_list.disc.cause, sizeof(CauseStr));
		return nr_proc(pid);		//REL_REQ_STATE
	}
	else if(pPort->msg_cmd == MSG_REL)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t305 or t306
		memcpy(&isdn_sd_msg.msg_list.relComp.cause, &isdn_rv_msg.msg_list.rel.cause, sizeof(CauseStr));
//		isdn_event_handle(pid, ISDN_RELEASE_IND);
		isdn_event_handle(pid, ISDN_RELEASE_CNF);
		rel_B_chnl(pid);
		isdn_send_msg(pid, MSG_REL_COMP);
		rel_cr(pid);
		isdn_cpc_clear(pPort);
		return NULL_STATE;
	}

	return -1;
}

/*************************************************************
Function:		n19_proc
Description:	Release request state, this state exists when the network has 
				requested the user to release and is waiting for a response.
				Handling the process and entering into next call state.
Input:		pid:port id
Return:		state value:success
			-1:failed
*************************************************************/
int n19_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if((pPort->msg_cmd == MSG_REL_COMP)
	   || (pPort->msg_cmd == MSG_REL))
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t308
		isdn_event_handle(pid, ISDN_RELEASE_CNF);
		rel_B_chnl(pid);
		rel_cr(pid);
		isdn_cpc_clear(pPort);
		return NULL_STATE;
	}
	else if(pPort->msg_cmd == MSG_STATUS)
	{
		pPort->msg_cmd = 0;
		if(isdn_rv_msg.msg_list.status.call_stat.stat_val != 0)
			return REL_REQ_STATE;
		pPort->w_time = 0;	//stop t308
		isdn_event_handle(pid, ISDN_STAT_IND);
		rel_B_chnl(pid);
		rel_cr(pid);
		isdn_cpc_clear(pPort);
		return NULL_STATE;
	}

	return -1;
}

/*************************************************************
Function:		n25_proc
Description:	Overlap receiving state, this state exists for an incoming call 
				when the network has received acknowledgement of the call 
				establishment request which permits the network to send 
				additional call information (if any) in the overlap mode
				Handling the process and entering into next call state.
Input:		pid:port id
Return:		state value:success
			-1:failed
*************************************************************/
int n25_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->primitive_cmd == ISDN_INFO_REQ)	//ISDN_MORE_INFO_REQ
	{
		pPort->primitive_cmd = 0;
		pPort->w_time = 0;	//start or restart t304
		isdn_send_msg(pid, MSG_INFORMATION);
		return OVERLAP_RV_STATE;
	}
	else if(pPort->msg_cmd == MSG_ALERT)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t304 and start t301
		isdn_event_handle(pid, ISDN_ALERT_IND);
		return CALL_RV_STATE;
	}
	else if(pPort->msg_cmd == MSG_CONN)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t304
		pPort->primitive_cmd = ISDN_SETUP_CNF;	//msc does not provide ISDN_SETUP_COMP_REQ to isdn
		isdn_event_handle(pid, ISDN_SETUP_CNF);
		return CONN_REQ_STATE;
	}
	else if(pPort->msg_cmd == MSG_CALL_PROC)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t304 and start t310
		isdn_event_handle(pid, ISDN_PROC_IND);
		return IN_CALL_PROC_STATE;
	}
	else if(pPort->msg_cmd == MSG_PROG)
	{
		pPort->msg_cmd = 0;
		isdn_event_handle(pid, ISDN_PROG_IND);
		return OVERLAP_RV_STATE;
	}

	return -1;
}


/*user side state processing*/
int u0_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];
	
	if(pPort->primitive_cmd == ISDN_SETUP_REQ)
	{
		pPort->primitive_cmd = 0;
		if(cr_sel(pid) != 1)
		{
			isdn_log_err(pid, "cr_sel error!\r\n");
			return NULL_STATE;
		}
		isdn_send_msg(pid, MSG_SETUP);
		pPort->timer_flag = CALLOUT_FLAG;
		pPort->w_time = 0;	//start t303
		pPort->timeout_fg = 0;
		return CALL_INIT_STATE;
	}
	else if(pPort->msg_cmd == MSG_SETUP)
	{
		pPort->msg_cmd = 0;
		//pPort->call_ref = msg_cref[pid];
		isdn_event_handle(pid, ISDN_SETUP_IND);
		return CALL_PRE_STATE;
	}

	return -1;
}

int u1_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->msg_cmd == MSG_SETUP_ACK)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t303 and start t304
		isdn_event_handle(pid, ISDN_MORE_INFO_IND);
		return OVERLAP_SD_STATE;
	}
	else if(pPort->msg_cmd == MSG_CALL_PROC)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t303 and start t310
		isdn_event_handle(pid, ISDN_PROC_IND);
		return OUT_CALL_PROC_STATE;
	}
	else if(pPort->msg_cmd == MSG_ALERT)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t303
		isdn_event_handle(pid, ISDN_ALERT_IND);
		return CALL_DV_STATE;
	}
	else if(pPort->msg_cmd == MSG_CONN)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t303
		isdn_event_handle(pid, ISDN_SETUP_CNF);
		isdn_send_msg(pid, MSG_CONNACK);
		return ACTIVE_STATE;
	}
	else if(pPort->msg_cmd == MSG_REL_COMP)	//do it temporarily in isdn_comm_ctrl()
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t303
		//isdn_event_handle(pid, ISDN_REJ_IND);
		rel_cr(pid);
		return NULL_STATE;
	}
	
	return -1;
}

int u2_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->msg_cmd == MSG_CALL_PROC)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t304 and start t310
		isdn_event_handle(pid, ISDN_PROC_IND);
		return OUT_CALL_PROC_STATE;
	}
	else if(pPort->msg_cmd == MSG_ALERT)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t304
		isdn_event_handle(pid, ISDN_ALERT_IND);
		return CALL_DV_STATE;
	}
	else if(pPort->msg_cmd == MSG_CONN)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t304
		isdn_event_handle(pid, ISDN_SETUP_CNF);
		isdn_send_msg(pid, MSG_CONNACK);
		return ACTIVE_STATE;
	}
	else if(pPort->msg_cmd == MSG_PROG)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t304
		isdn_event_handle(pid, ISDN_PROG_IND);
		return OVERLAP_SD_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_INFO_REQ)
	{
		pPort->primitive_cmd = 0;
		pPort->w_time = 0;	//start or restart t304
		isdn_send_msg(pid, MSG_INFORMATION);
		return OVERLAP_SD_STATE;
	}

	return -1;
}

int u3_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->msg_cmd == MSG_ALERT)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t310 and start t301
		isdn_event_handle(pid, ISDN_ALERT_IND);
		return CALL_DV_STATE;
	}
	else if(pPort->msg_cmd == MSG_CONN)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t310
		isdn_event_handle(pid, ISDN_SETUP_CNF);
		isdn_send_msg(pid, MSG_CONNACK);
		return ACTIVE_STATE;
	}
	else if(pPort->msg_cmd == MSG_PROG)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t310
		isdn_event_handle(pid, ISDN_PROG_IND);
		return OUT_CALL_PROC_STATE;
	}

	return -1;
}

int u4_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->msg_cmd == MSG_CONN)
	{
		pPort->msg_cmd = 0;
		isdn_event_handle(pid, ISDN_SETUP_CNF);
		isdn_send_msg(pid, MSG_CONNACK);
		return ACTIVE_STATE;
	}
	else if(pPort->msg_cmd == MSG_PROG)	//support U04_09
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t310
		isdn_event_handle(pid, ISDN_PROG_IND);
		return CALL_DV_STATE;
	}

	return -1;
}

int u6_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->primitive_cmd == ISDN_MORE_INFO_REQ)
	{
		pPort->primitive_cmd = 0;
		pPort->w_time = 0;	//start t302
		isdn_send_msg(pid, MSG_SETUP_ACK);
		return OVERLAP_RV_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_PROC_REQ)
	{
		pPort->primitive_cmd = 0;
		isdn_send_msg(pid, MSG_CALL_PROC);
		return IN_CALL_PROC_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_ALERT_REQ)
	{
		pPort->primitive_cmd = 0;
		isdn_send_msg(pid, MSG_ALERT);
		return CALL_RV_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_SETUP_RSP)
	{
		pPort->primitive_cmd = 0;
		pPort->w_time = 0;	//start t313
		isdn_send_msg(pid, MSG_CONN);
		return CONN_REQ_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_REJECT_REQ)
	{
		pPort->primitive_cmd = 0;
		rel_B_chnl(pid);
		isdn_send_msg(pid, MSG_REL_COMP);
		rel_cr(pid);
		return NULL_STATE;
	}

	return -1;
}

int u7_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->primitive_cmd == ISDN_SETUP_RSP)
	{
		pPort->primitive_cmd = 0;
		pPort->w_time = 0;	//start t313
		isdn_send_msg(pid, MSG_CONN);
		return CONN_REQ_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_PROG_REQ)
	{
		pPort->primitive_cmd = 0;
		isdn_send_msg(pid, MSG_PROG);
		return CALL_DV_STATE;
	}

	return -1;
}

int u8_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->msg_cmd == MSG_CONNACK)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t313
		isdn_event_handle(pid, ISDN_SETUP_COMP_IND);
		return ACTIVE_STATE;
	}

	return -1;
}

int u9_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->primitive_cmd == ISDN_ALERT_REQ)
	{
		pPort->primitive_cmd = 0;
		isdn_send_msg(pid, MSG_ALERT);
		return CALL_RV_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_SETUP_RSP)
	{
		pPort->primitive_cmd = 0;
		pPort->w_time = 0;	//start t313
		isdn_send_msg(pid, MSG_CONN);
		return CONN_REQ_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_PROG_REQ)
	{
		pPort->primitive_cmd = 0;
		isdn_send_msg(pid, MSG_PROG);
		return IN_CALL_PROC_STATE;
	}

	return -1;
}

int u10_proc(u32 pid)   //??  add by gengxin
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->msg_cmd == MSG_NOTI)
	{
		pPort->msg_cmd = 0;
		isdn_event_handle(pid, ISDN_NOTI_IND);
		return ACTIVE_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_NOTI_REQ)
	{
		pPort->primitive_cmd = 0;
		isdn_send_msg(pid, MSG_NOTI);
		return ACTIVE_STATE;
	}
	
	return -1;
}

int u11_proc(u32 pid)   //0911
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->msg_cmd == MSG_DISC)
	{
		pPort->msg_cmd = 0;
		memcpy(&isdn_sd_msg.msg_list.rel.cause, &isdn_rv_msg.msg_list.disc.cause, sizeof(CauseStr));
		return nr_proc(pid);
	}
	else if(pPort->msg_cmd == MSG_REL) 
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t305
		memcpy(&isdn_sd_msg.msg_list.relComp.cause, &isdn_rv_msg.msg_list.rel.cause, sizeof(CauseStr));
//		isdn_event_handle(pid, ISDN_RELEASE_IND);
		isdn_event_handle(pid, ISDN_RELEASE_CNF);
		rel_B_chnl(pid);	
		isdn_send_msg(pid, MSG_REL_COMP);
		rel_cr(pid);
		isdn_cpc_clear(pPort);
		return NULL_STATE;
	}

	return -1;
}

int u12_proc(u32 pid)  //0911
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->msg_cmd == MSG_REL)
	{
		pPort->msg_cmd = 0;
		memcpy(&isdn_sd_msg.msg_list.relComp.cause, &isdn_rv_msg.msg_list.rel.cause, sizeof(CauseStr));
//		isdn_event_handle(pid, ISDN_RELEASE_IND);
		isdn_event_handle(pid, ISDN_RELEASE_CNF);
		rel_B_chnl(pid);
		isdn_send_msg(pid, MSG_REL_COMP);
		rel_cr(pid);
		isdn_cpc_clear(pPort);
		return NULL_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_RELEASE_REQ)
	{
		pPort->primitive_cmd = 0;
		return nr_proc(pid);
	}
	
	return -1;
}

int u19_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if((pPort->msg_cmd == MSG_REL_COMP) || 
		(pPort->msg_cmd == MSG_REL))
	{
		pPort->msg_cmd = 0;
		isdn_event_handle(pid, ISDN_RELEASE_CNF);
		rel_B_chnl(pid);
		rel_cr(pid);
		isdn_cpc_clear(pPort);
		return NULL_STATE;
	}
	else if(pPort->msg_cmd == MSG_STATUS)
	{
		pPort->msg_cmd = 0;
		if(isdn_rv_msg.msg_list.status.call_stat.stat_val != 0)
			return REL_REQ_STATE;
		isdn_event_handle(pid, ISDN_STAT_IND);
		rel_B_chnl(pid);
		rel_cr(pid);
		isdn_cpc_clear(pPort);
		return NULL_STATE;
	}
	
	return -1;
}

int u25_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->msg_cmd == MSG_INFORMATION)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//start t302
		isdn_event_handle(pid, ISDN_INFO_IND);
		return OVERLAP_RV_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_PROC_REQ)
	{
		pPort->primitive_cmd = 0;
		pPort->w_time = 0;	//stop t302
		isdn_send_msg(pid, MSG_CALL_PROC);
		return IN_CALL_PROC_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_ALERT_REQ)
	{
		pPort->primitive_cmd = 0;
		pPort->w_time = 0;	//stop t302
		isdn_send_msg(pid, MSG_ALERT);
		return CALL_RV_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_SETUP_RSP)
	{
		pPort->primitive_cmd = 0;
		pPort->w_time = 0;	//stop t302 and start t313
		isdn_send_msg(pid, MSG_CONN);
		return CONN_REQ_STATE;
	}
	else if(pPort->primitive_cmd == ISDN_PROG_REQ)
	{
		pPort->primitive_cmd = 0;
		isdn_send_msg(pid, MSG_PROG);
		return OVERLAP_RV_STATE;
	}

	return -1;
}


/* Global Call Reference Procedures */
/*************************************************************
Function:		trans_callref_sd_rest_req
Description:	
Input:			
Output:			
Return:			
*************************************************************/
int trans_callref_sd_rest_req(u32 pid, u8 g_pri_cmd)		//isdn_restart_req()
{
	int i, link_id, cic_range;
	u16 circuit_id;
	const pal_circuit_struct *circuit_ptr = NULL;
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	circuit_id = pid / ISDN_CIRCUIT_CIC;
	circuit_ptr = pal_circuit_ptr(circuit_id);
	if(circuit_ptr == NULL)
		return ISDN_CM_FAILED;

	link_id = circuit_ptr->attrib.link_id;
	cic_range = circuit_ptr->attrib.cic_range;
	if(cic_range == 24)	//T1
		cic_range++;
	if(isdn_rs.link_pond[link_id].restart_clas == 0)	//indicated channels
	{
		if(pPort->cic_val != 0)
		{
			pid = find_port_by_cic(pPort->cic_val, circuit_id);
			pPort = &isdn_rs.port_pond[pid];
			if(g_pri_cmd == ISDN_RESTART_REQ)
			{
				pPort->g_pri_cmd = ISDN_RESTART_REQ;
				isdn_cpc_proc(pid);
				if(pPort->g_pri_cmd != 0 && pPort->g_pri_cmd != ISDN_RESTART_CNF)
				{
					isdn_trace_func(pid, "[waring]primitive cmd discard.(cmd=%d)\r\n", pPort->primitive_cmd);
					pPort->g_pri_cmd = 0;
				}
				return circuit_ptr->attrib.cic_range;
			}
			else if(g_pri_cmd == ISDN_RESTART_CNF)
			{
				if(pPort->g_pri_cmd != g_pri_cmd)
				{
					pPort->g_pri_cmd = 0;
					isdn_trace_func(pid, "[waring]primitive cmd is not ISDN_RESTART_CNF.(cmd=%d)\r\n", pPort->primitive_cmd);
					return ISDN_CM_FAILED;
				}
				pPort->g_pri_cmd = 0;
				return circuit_ptr->attrib.cic_range;
			}
		}
	}
	else if(isdn_rs.link_pond[link_id].restart_clas == 6)	//single interface
	{
		for(i = 1; i < cic_range; i++)
		{
			pid = circuit_id * ISDN_CIRCUIT_CIC + i;
			pPort = &isdn_rs.port_pond[pid];
			if(pPort->enable != 0)
			{
				if(g_pri_cmd == ISDN_RESTART_REQ)
				{
					pPort->g_pri_cmd = ISDN_RESTART_REQ;
					isdn_cpc_proc(pid);
					if(pPort->g_pri_cmd != 0 && pPort->g_pri_cmd != ISDN_RESTART_CNF)
					{
						isdn_trace_func(pid, "[waring]primitive cmd discard.(cmd=%d)\r\n", pPort->primitive_cmd);
						pPort->g_pri_cmd = 0;
					}
				}
				else if(g_pri_cmd == ISDN_RESTART_CNF)
				{
					if(pPort->g_pri_cmd != g_pri_cmd)
					{
						pPort->g_pri_cmd = 0;
						isdn_trace_func(pid, "[waring]primitive cmd is not ISDN_RESTART_CNF.(cmd=%d)\r\n", pPort->primitive_cmd);
						return ISDN_CM_FAILED;
					}
					pPort->g_pri_cmd = 0;
				}
			}
		}
//		isdn_rs.link_pond[link_id].restart_clas = 0;
		return circuit_ptr->attrib.cic_range;
	}

	return ISDN_CM_FAILED;
}

static inline void restart_clear(u32 pid)
{
	int i, link_id, cic_range;
	u16 circuit_id = pid / ISDN_CIRCUIT_CIC;
	const pal_circuit_struct *circuit_ptr = pal_circuit_ptr(circuit_id);
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];
 	if(circuit_ptr == NULL)
		return;

	link_id = circuit_ptr->attrib.link_id;
	cic_range = circuit_ptr->attrib.cic_range;
	if(cic_range == 24)	//T1
		cic_range++;
	if(isdn_rs.link_pond[link_id].restart_clas == 0)	//indicated channels
	{
		pid = find_port_by_cic(pPort->cic_val, circuit_id);
		pPort->cic_val = 0;
		rel_B_chnl(pid);
		isdn_cpc_clear(pPort);
	}
	else
	{
		isdn_rs.link_pond[link_id].restart_clas = 0;
		for(i = 1; i < cic_range; i++)
		{
			pid = circuit_id * ISDN_CIRCUIT_CIC + i;
			pPort = &isdn_rs.port_pond[pid];
			if(pPort->enable != 0)
			{
				rel_B_chnl(pid);
				isdn_cpc_clear(pPort);
			}
		}
	}
}

int rest0_proc(u32 pid, IsdnRestart *restart)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->msg_cmd == MSG_RESTART)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//start t317
		memcpy(restart, &isdn_rv_msg.msg_list.restart, sizeof(IsdnRestart));
		trans_callref_sd_rest_req(pid, ISDN_RESTART_REQ);
		return GLOBAL_RESTART_STATE;
	}
	else if(pPort->g_pri_cmd == ISDN_M_RESTART_REQ)
	{
		pPort->g_pri_cmd = 0;
		pPort->timeout_fg = 0;
		pPort->w_time = 0;	//start t316
		isdn_send_msg(pid, MSG_RESTART);
		trans_callref_sd_rest_req(pid, ISDN_RESTART_REQ);
		return GLOBAL_RESTART_REQ_STATE;
	}

	return -1;
}

int rest1_proc(u32 pid)
{
	static int rest_resp_on = 0;	//??
	static int rest_ack_on = 0;
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];
	
	if(pPort->msg_cmd == MSG_REST_ACK)
	{
		pPort->msg_cmd = 0;
		pPort->w_time = 0;	//stop t316
		if(rest_resp_on)
		{
			rest_resp_on = 0;
			restart_clear(pid);
			return GLOBAL_NULL_STATE;
		}
		else
			rest_ack_on = 1;
	}
	else if(pPort->g_pri_cmd == ISDN_RESTART_CNF)
	{
		pPort->g_pri_cmd = 0;
		if(rest_ack_on)
		{
			rest_ack_on = 0;
			restart_clear(pid);
			return GLOBAL_NULL_STATE;
		}
		else
			rest_resp_on = 1;
	}
	else if(pPort->msg_cmd == MSG_RESTART)
	{
		pPort->msg_cmd = 0;
		trans_callref_sd_rest_req(pid, ISDN_RESTART_REQ);
		return GLOBAL_RESTART_STATE;
	}

	return -1;
}

int rest2_proc(u32 pid, IsdnRestart restart)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	if(pPort->g_pri_cmd == ISDN_RESTART_CNF)
	{
		pPort->g_pri_cmd = 0;
		pPort->w_time = 0;
		memcpy(&isdn_sd_msg.msg_list.restAck, (IsdnRestAck *)&restart, sizeof(IsdnRestAck));
		isdn_send_msg(pid, MSG_REST_ACK);
		restart_clear(pid);
		return GLOBAL_NULL_STATE;
	}
	else if(pPort->msg_cmd == MSG_RESTART)
	{
		pPort->msg_cmd = 0;
		trans_callref_sd_rest_req(pid, ISDN_RESTART_REQ);
		return GLOBAL_RESTART_STATE;
	}

	return -1;
}

void isdn_restart_ctrl(u32 pid)
{
	int num = 0;
	static IsdnRestart restart;
	ISDN_Port_struct *pPort = &(isdn_rs.port_pond[pid]);
	const pal_circuit_struct *circuit_ptr = pal_circuit_ptr(pid / ISDN_CIRCUIT_CIC);
	if(circuit_ptr == NULL)
		return;

	switch(pPort->cic_state.call_state)
	{
		case CALLOUT_FLAG:
		case CALLIN_FLAG:
		case GLOBAL_NULL_STATE:
			switch(rest0_proc(pid, &restart))
			{
				case GLOBAL_RESTART_REQ_STATE:
					pPort->cic_state.call_state = GLOBAL_RESTART_REQ_STATE;
					break;
				case GLOBAL_RESTART_STATE:
					pPort->cic_state.call_state = GLOBAL_RESTART_STATE;
					break;
				default:
					break;
			}
			break;
		case GLOBAL_RESTART_REQ_STATE:
			switch(rest1_proc(pid))
			{
				case GLOBAL_NULL_STATE:
					pPort->cic_state.call_state = GLOBAL_NULL_STATE;
					break;
				case GLOBAL_RESTART_STATE:
					pPort->cic_state.call_state = GLOBAL_RESTART_STATE;
					break;
				default:
					break;
			}
			break;
		case GLOBAL_RESTART_STATE:
			switch(rest2_proc(pid, restart))
			{
				case GLOBAL_NULL_STATE:
					pPort->cic_state.call_state = GLOBAL_NULL_STATE;
					break;
				case GLOBAL_RESTART_STATE:
					pPort->cic_state.call_state = GLOBAL_RESTART_STATE;
					break;
				default:
					break;
			}
			break;
		default:
			break;
	}
	
//	printf("global state = 0x%02x\n",pPort->cic_state.call_state);
	if(pPort->g_pri_cmd == ISDN_RESTART_REQ)
	{
		pPort->g_pri_cmd = 0;
		if(pPort->cic_state.call_state == GLOBAL_RESTART_STATE)
			memcpy(&isdn_sd_msg.msg_list.restAck, &isdn_rv_msg.msg_list.restart, sizeof(IsdnRestart));
		if((num = trans_callref_sd_rest_req(pid, ISDN_RESTART_CNF)) == circuit_ptr->attrib.cic_range)
			pPort->g_pri_cmd = ISDN_RESTART_CNF;
//		isdn_restart_ctrl(pid);
	}
	else if(pPort->g_pri_cmd != 0)
	{
		isdn_log_err(pid, "global g_pri_cmd = 0x%x\r\n", pPort->g_pri_cmd);
		pPort->g_pri_cmd = 0;
	}
	
	if(pPort->msg_cmd != 0)
	{
		isdn_log_err(pid, "global msg_cmd = 0x%x\r\n", pPort->msg_cmd);
		pPort->msg_cmd = 0;
		isdn_set_status(&isdn_sd_msg.msg_list.status, pPort->cic_state.call_state, CAUSE_INVALID_CR);	//cause 81
		isdn_send_msg(pid, MSG_STATUS);
	}	
	
}


/*************************************************************
Function:		not_isdn_rel_st
Description:	Handling state is isdn release state or not
Input:			state:call state
Return:			ISDN_CM_OK:success
				ISDN_CM_FAILED:failed
*************************************************************/
static int not_isdn_rel_st(u8 state)
{
	if((state != NULL_STATE) && 
		(state != DISC_REQ_STATE) && 
		(state != DISC_IND_STATE) && 
		(state != REL_REQ_STATE))
		return ISDN_CM_OK;
	else
		return ISDN_CM_FAILED;
}

/*************************************************************
Function:		isdn_comm_ctrl
Description:	ISDN Protocol Common Control 
Input:		pid:port id
Return:		state value:success
*************************************************************/
u8 isdn_comm_ctrl(u32 pid)
{
	u8 state, msg_cmd, pri_cmd, g_pri_cmd;
	ISDN_Port_struct *pPort = &(isdn_rs.port_pond[pid]);
	const pal_circuit_struct *circuit_ptr = pal_circuit_ptr(pid / ISDN_CIRCUIT_CIC);
	if(circuit_ptr == NULL)
	{
		isdn_log_err(pid, "isdn_comm_ctrl err! circuit_id %d can't find circuit_ptr!\r\n",pid/ISDN_CIRCUIT_CIC);
		return ISDN_CM_FAILED;
	}

	state = pPort->fsm_state.cpc_state;
	msg_cmd = pPort->msg_cmd;
	pri_cmd = pPort->primitive_cmd;
	g_pri_cmd = pPort->g_pri_cmd;
	if(not_isdn_rel_st(state))
	{
		if(msg_cmd == MSG_DISC)
		{
			pPort->msg_cmd = 0;
			if(state != ACTIVE_STATE)
			{
				isdn_log_err(pid, "isdn_comm_ctrl err1!\r\n");
			}
			return nd_proc(pid);
		}
		else if(pri_cmd == ISDN_DISCONNECT_REQ)
		{
			pPort->primitive_cmd = 0;
			if(state != ACTIVE_STATE)
			{
				isdn_log_err(pid, "isdn_comm_ctrl err2!\r\n");
			}
			return nc_proc(pid);
		}
		else if(pri_cmd == ISDN_RELEASE_REQ)
		{
			pPort->primitive_cmd = 0;
			isdn_log_err(pid, "isdn_comm_ctrl err3, rv release req!\r\n");
			return nr_proc(pid);
		}
		else if(msg_cmd == MSG_REL) 
		{
			pPort->msg_cmd = 0;
			pPort->w_time = 0;	//stop all
			isdn_log_err(pid, "isdn_comm_ctrl err4, rv rel!\r\n");
			isdn_event_handle(pid, ISDN_RELEASE_IND);
			rel_B_chnl(pid);
//			memcpy(&isdn_sd_msg.msg_list.relComp, &isdn_rv_msg.msg_list.rel, sizeof(IsdnRel));
			isdn_send_msg(pid, MSG_REL_COMP);
			rel_cr(pid);
			isdn_cpc_clear(pPort);
			return NULL_STATE;
		}
	}

	if((state != NULL_STATE) && (state != REL_REQ_STATE))
	{
		if(msg_cmd == MSG_STATUS)
		{
			pPort->msg_cmd = 0;
			if(isdn_rv_msg.msg_list.status.call_stat.stat_val == 0)
			{
				isdn_log_err(pid, "isdn_comm_ctrl err5, rv status with null state!\r\n");
				isdn_event_handle(pid, ISDN_STAT_IND);
				rel_B_chnl(pid);
				rel_cr(pid);
				isdn_cpc_clear(pPort);
				return NULL_STATE;
			}
			else if(isdn_rv_msg.msg_list.status.call_stat.stat_val != state)
			{
				isdn_log_err(pid, "isdn_comm_ctrl err5, rv status with no compatible state!\r\n");
				if(state == ACTIVE_STATE)
				{
					isdn_send_msg(pid, MSG_STAT_ENQ);
					return ACTIVE_STATE;
				}
				isdn_set_cause(&isdn_rv_msg.msg_list.rel.cause, CAUSE_MSG_NOTCOMP_NOTIMPL);
				isdn_set_cause(&isdn_sd_msg.msg_list.relComp.cause, CAUSE_MSG_NOTCOMP_NOTIMPL);
				isdn_event_handle(pid, ISDN_RELEASE_IND);
				rel_B_chnl(pid);
				isdn_send_msg(pid, MSG_REL_COMP);
				rel_cr(pid);
				isdn_cpc_clear(pPort);
				return NULL_STATE;
			}
			//cs != 0 discard msg
		}
		else if(msg_cmd == MSG_REL_COMP)
		{
			pPort->msg_cmd = 0;
			isdn_log_err(pid, "isdn_comm_ctrl err6, rv rel comp!\r\n");
			isdn_event_handle(pid, ISDN_RELEASE_IND);
			rel_B_chnl(pid);
			rel_cr(pid);
			isdn_cpc_clear(pPort);
			return NULL_STATE;
		}
		else if(msg_cmd == MSG_INFORMATION)
		{
			if(state != CALL_INIT_STATE && 
				state != CALL_PRE_STATE && 
				((state != OVERLAP_RV_STATE && circuit_ptr->attrib.user_network_if == USER_SIDE) ||
				(state != OVERLAP_SD_STATE && circuit_ptr->attrib.user_network_if == NETWORK_SIDE)))
			{
				pPort->msg_cmd = 0;
				isdn_event_handle(pid, ISDN_INFO_IND);
			}
		}
		else if(pri_cmd == ISDN_INFO_REQ)
		{
			if(state != CALL_INIT_STATE && 
				state != CALL_PRE_STATE && 
				((state != OVERLAP_SD_STATE && circuit_ptr->attrib.user_network_if == USER_SIDE) ||
				(state != OVERLAP_RV_STATE && circuit_ptr->attrib.user_network_if == NETWORK_SIDE)))
			{
				pPort->primitive_cmd = 0;
				isdn_send_msg(pid, MSG_INFORMATION);
			}
		}
	}

	if(msg_cmd == MSG_STAT_ENQ)
	{
		pPort->msg_cmd = 0;
		isdn_log_err(pid, "isdn_comm_ctrl err7, rv status enq!\r\n");
		isdn_set_status(&isdn_sd_msg.msg_list.status, state, CAUSE_STAT_ENQ);
		isdn_send_msg(pid, MSG_STATUS);
	}

	if(g_pri_cmd == ISDN_RESTART_REQ)	//restart_request
	{
		pPort->g_pri_cmd = 0;
		pPort->w_time = 0;
		isdn_log_err(pid, "isdn_comm_ctrl err8, rv restart req!\r\n");
		isdn_set_cause(&isdn_rv_msg.msg_list.rel.cause, CAUSE_TEMP_FAIL);
		isdn_event_handle(pid, ISDN_RELEASE_IND);
		rel_cr(pid);
		pPort->g_pri_cmd = ISDN_RESTART_CNF;
//		isdn_event_handle(pid, ISDN_RESTART_CNF);	//0411
		return NULL_STATE;
	}
	
	/* DL Primitive -- Not Implemented Yet */
	return state;
}

static void isdn_cpc_nt_proc(u32 pid)
/*
isdn状态机，包含n1 ...n25状态
*/
{
	int state;
	ISDN_Port_struct *pPort = &(isdn_rs.port_pond[pid]);

	state = isdn_comm_ctrl(pid);
	if(state == pPort->fsm_state.cpc_state)
	{
		switch(state)
		{
			case NULL_STATE:
				switch(n0_proc(pid))
				{
					case CALL_INIT_STATE:
						state = CALL_INIT_STATE;
	  					break;
					case CALL_PRE_STATE:
						state = CALL_PRE_STATE;
	  					break;
					default:
						break;
				}
				break;
			case CALL_INIT_STATE:
				switch(n1_proc(pid))
				{
					case NULL_STATE:
						state = NULL_STATE;
						break;
	  				case OVERLAP_SD_STATE:
	  					state = OVERLAP_SD_STATE;
	  					break;
	  				case OUT_CALL_PROC_STATE:
	  					state = OUT_CALL_PROC_STATE;
	  					break;
	  				default:
	 					break;
				}
				break;
			case OVERLAP_SD_STATE:
				switch(n2_proc(pid))
				{
					case OUT_CALL_PROC_STATE:
						state = OUT_CALL_PROC_STATE;
						break;
					case CALL_DV_STATE:
						state = CALL_DV_STATE;
						break;
					case ACTIVE_STATE:
						state = ACTIVE_STATE;
						break;
					default:
						break;
				}
				break;
			case OUT_CALL_PROC_STATE:
				switch(n3_proc(pid))
				{
					case CALL_DV_STATE:
						state = CALL_DV_STATE;
	  					break;
					case ACTIVE_STATE:
						state = ACTIVE_STATE;
	  					break;
					default:
						break;
				}
				break;
			case CALL_DV_STATE:
				switch(n4_proc(pid))
				{
					case ACTIVE_STATE:
						state = ACTIVE_STATE;
	  					break;
					default:
						break;
				}
				break;
			case CALL_PRE_STATE:
				switch(n6_proc(pid))
				{
					case NULL_STATE:
						state = NULL_STATE;
	  					break;
					case CALL_RV_STATE:
						state = CALL_RV_STATE;
	  					break;
					case CONN_REQ_STATE:
						state = CONN_REQ_STATE;
	  					break;
					case IN_CALL_PROC_STATE:
						state = IN_CALL_PROC_STATE;
	  					break;
					case OVERLAP_RV_STATE:
						state = OVERLAP_RV_STATE;
	  					break;
					default:
						break;
				}
				break;
			case CALL_RV_STATE:
				switch(n7_proc(pid))
				{
					case CONN_REQ_STATE:
						state = CONN_REQ_STATE;
	  					break;
					default:
						break;
				}
				break;
			case CONN_REQ_STATE:
				switch(n8_proc(pid))
				{
					case ACTIVE_STATE:
						state = ACTIVE_STATE;
	  					break;
					default:
						break;
				}
				break;
			case IN_CALL_PROC_STATE:
				switch(n9_proc(pid))
				{
					case CALL_RV_STATE:
						state = CALL_RV_STATE;
	  					break;
					case CONN_REQ_STATE:
						state = CONN_REQ_STATE;
	  					break;
					default:
						break;
				}
				break;
			case ACTIVE_STATE:
				switch(n10_proc(pid))
				{
					case -1:
						break;
					default:
						break;
				}
				break;
			case DISC_REQ_STATE:
				switch(n11_proc(pid))
				{
					case REL_REQ_STATE:
						state = REL_REQ_STATE;
	  					break;
					default:
						break;
				}
				break;
			case DISC_IND_STATE:
				switch(n12_proc(pid))
				{
					case NULL_STATE:
						state = NULL_STATE;
	  					break;
					case REL_REQ_STATE:
						state = REL_REQ_STATE;
	  					break;
					default:
						break;
				}
				break;
			case REL_REQ_STATE:
				switch(n19_proc(pid))
				{
					case NULL_STATE:
						state = NULL_STATE;
	  					break;
					default:
						break;
				}
				break;
			case OVERLAP_RV_STATE:
				switch(n25_proc(pid))
				{
					case CALL_RV_STATE:
						state = CALL_RV_STATE;
	  					break;
					case CONN_REQ_STATE:
						state = CONN_REQ_STATE;
	  					break;
					case IN_CALL_PROC_STATE:
						state = IN_CALL_PROC_STATE;
	  					break;
					default:
						break;
				}
				break;

			default:
				break;
		}
	}

//	printf("nt state = 0x%02x\n",state);
	pPort->fsm_state.cpc_state = state;

	isdn_cc_nt(pid);

	//unexpected  message  and send_isdn_msg(status) 	//u03-04  u03-05  u01-03
	if(pPort->msg_cmd != 0)
	{
		pPort->msg_cmd = 0;
		isdn_log_err(pid, "isdn_cpc_nt_proc, receive msg=0x02%x, not handle!\r\n");
		isdn_set_status(&isdn_sd_msg.msg_list.status, pPort->fsm_state.cpc_state, CAUSE_MSG_NOTCOMP);	//cause 98  101
		isdn_send_msg(pid, MSG_STATUS);
	}

	return;
}

static void isdn_cpc_lt_proc(u32 pid)
{
	int state;
	ISDN_Port_struct *pPort = &(isdn_rs.port_pond[pid]);

	state = isdn_comm_ctrl(pid);
	if(state == pPort->fsm_state.cpc_state)
	{
		switch(state)
		{
			case NULL_STATE:
				switch(u0_proc(pid))
				{
					case CALL_INIT_STATE:
						state = CALL_INIT_STATE;
						break;
					case CALL_PRE_STATE:
						state = CALL_PRE_STATE;
					default:
						break;
				}
				break;
			case CALL_INIT_STATE:
				switch(u1_proc(pid))
				{
					case NULL_STATE:
						state = NULL_STATE;
	  					break;
					case OVERLAP_SD_STATE:
						state = OVERLAP_SD_STATE;
						break;
					case OUT_CALL_PROC_STATE:
						state = OUT_CALL_PROC_STATE;
	  					break;
					case CALL_DV_STATE:
						state = CALL_DV_STATE;
	  					break;
					case ACTIVE_STATE:
						state = ACTIVE_STATE;
	  					break;
					default:
						break;
				}
				break;
			case OVERLAP_SD_STATE:
				switch(u2_proc(pid))
				{
					case OUT_CALL_PROC_STATE:
						state = OUT_CALL_PROC_STATE;
	  					break;
					case CALL_DV_STATE:
						state = CALL_DV_STATE;
	  					break;
					case ACTIVE_STATE:
						state = ACTIVE_STATE;
	  					break;
					default:
						break;
				}
				break;
			case OUT_CALL_PROC_STATE:
				switch(u3_proc(pid))
				{
					case CALL_DV_STATE:
						state = CALL_DV_STATE;
	  					break;
					case ACTIVE_STATE:
						state = ACTIVE_STATE;
	  					break;
					default:
						break;
				}
				break;
			case CALL_DV_STATE:
				switch(u4_proc(pid))
				{
					case ACTIVE_STATE:
						state = ACTIVE_STATE;
						break;
					default:
						break;
				}
				break;
			case CALL_PRE_STATE:
				switch(u6_proc(pid))
				{
					case NULL_STATE:
						state = NULL_STATE;
						break;
	  				case CALL_RV_STATE:
	  					state = CALL_RV_STATE;
	  					break;
					case CONN_REQ_STATE:
						state = CONN_REQ_STATE;
						break;
	  				case IN_CALL_PROC_STATE:
	  					state = IN_CALL_PROC_STATE;
	  					break;
	  				case OVERLAP_RV_STATE:
	  					state = OVERLAP_RV_STATE;
	  					break;
	  				default:
	 					break;
				}
				break;
			case CALL_RV_STATE:
				switch(u7_proc(pid))
				{
					case CONN_REQ_STATE:
						state = CONN_REQ_STATE;
						break;
					default:
						break;
				}
				break;
			case CONN_REQ_STATE:
				switch(u8_proc(pid))
				{
					case ACTIVE_STATE:
						state = ACTIVE_STATE;
						break;
					default:
						break;
				}
				break;
			case IN_CALL_PROC_STATE:
				switch(u9_proc(pid))
				{
					case CALL_RV_STATE:
						state = CALL_RV_STATE;
	  					break;
					case CONN_REQ_STATE:
						state = CONN_REQ_STATE;
	  					break;
					default:
						break;
				}
				break;
			case ACTIVE_STATE:
				switch(u10_proc(pid))
				{
					case -1:
						break;
					default:
						break;
				}
				break;
			case DISC_REQ_STATE:
				switch(u11_proc(pid))
				{
					case NULL_STATE:
						state = NULL_STATE;
	  					break;
					case REL_REQ_STATE:
						state = REL_REQ_STATE;
	  					break;
					default:
						break;
				}
				break;
			case DISC_IND_STATE:
				switch(u12_proc(pid))
				{
					case NULL_STATE:
						state = NULL_STATE;
	  					break;
					case REL_REQ_STATE:
						state = REL_REQ_STATE;
	  					break;
					default:
						break;
				}
				break;
			case REL_REQ_STATE:
				switch(u19_proc(pid))
				{
					case NULL_STATE:
						state = NULL_STATE;
						break;
					default:
						break;
				}
				break;
			case OVERLAP_RV_STATE:
				switch(u25_proc(pid))
				{
					case CALL_RV_STATE:
						state = CALL_RV_STATE;
						break;
					case CONN_REQ_STATE:
						state = CONN_REQ_STATE;
						break;
					case IN_CALL_PROC_STATE:
						state = IN_CALL_PROC_STATE;
						break;
					default:
						break;
				}
				break;
			default:
				break;
		}
	}

//	printf("lt state = 0x%02x\n",state);
	pPort->fsm_state.cpc_state = state;

	isdn_cc_lt(pid);

	//unexpected  message  and send_isdn_msg(status) 	//u03-04  u01-03
	if(pPort->msg_cmd != 0)
	{
		pPort->msg_cmd = 0;		
		isdn_log_err(pid, "isdn_cpc_lt_proc, receive msg=0x02%x, not handle!\r\n");
		isdn_set_status(&isdn_sd_msg.msg_list.status, pPort->fsm_state.cpc_state, CAUSE_MSG_NOTCOMP);	//cause 98  101
		isdn_send_msg(pid, MSG_STATUS);
	}

	return;
}

void isdn_cpc_proc(u32 pid)
{
	int circuit_id = pid / ISDN_CIRCUIT_CIC;
	const pal_circuit_struct *circuit_ptr = pal_circuit_ptr(circuit_id);
	if(circuit_ptr == NULL)
		return;

	if(circuit_ptr->attrib.user_network_if)
		isdn_cpc_lt_proc(pid);
	else
		isdn_cpc_nt_proc(pid);
}

static int isdn_cc_nt(u32 pid)
{	
	ISDN_Port_struct *pPort = &(isdn_rs.port_pond[pid]);
	
	switch(pPort->fsm_state.cpc_state)
	{
		case CONN_REQ_STATE:
			if(pPort->primitive_cmd == ISDN_SETUP_CNF)	//msc does not provide ISDN_SETUP_COMP_REQ to isdn
			{
				pPort->primitive_cmd = ISDN_SETUP_COMP_REQ;
				isdn_cpc_nt_proc(pid);
			}
			break;
		case DISC_REQ_STATE:
			break;
		default:
			break;
	}
	if(pPort->primitive_cmd != 0)
	{
		pPort->primitive_cmd = 0;
		isdn_log_err(pid, "isdn_cc_nt, primitive err!\r\n");
		return ISDN_CM_FAILED;
	}

	return ISDN_CM_OK;
}

static int isdn_cc_lt(u32 pid)
{
	ISDN_Port_struct *pPort = &(isdn_rs.port_pond[pid]);
	
	switch(pPort->fsm_state.cpc_state)
	{
		case DISC_IND_STATE:
			break;
		default:
			break;
	}
	if(pPort->primitive_cmd != 0)
	{
		pPort->primitive_cmd = 0;
		isdn_log_err(pid, "isdn_cc_lt, primitive err!\r\n");
		return ISDN_CM_FAILED;
	}

	return ISDN_CM_OK;
}

static void isdn_cpc_nt_timer(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	switch(pPort->fsm_state.cpc_state)
	{
		case OVERLAP_SD_STATE:
//			if((++(pPort->w_time)) % (isdn_timer_var.t302) == 0)
//			{
//				pPort->w_time = 0;
//				isdn_log_err(pid, "[timeout]: NT OVERLAP SD STATE\r\n");
//				isdn_event_handle(pid, ISDN_TIMEOUT_IND);
//			}
			break;
		case CALL_PRE_STATE:
			if((++(pPort->w_time)) % (isdn_timer_var.t303) == 0)
			{
				pPort->w_time = 0;
				if(pPort->timeout_fg == 0)
				{
					pPort->timeout_fg = 1;
					isdn_log_err(pid, "[timeout]:t303 NT CALL PRE STATE first timeout, resend SETUP\r\n");
					isdn_send_msg(pid, MSG_SETUP);
				}
				else
				{
					isdn_log_err(pid, "[timeout]:t303 NT CALL PRE STATE second timeout, clear call!\r\n");
					isdn_set_cause(&isdn_rv_msg.msg_list.rel.cause, CAUSE_TIMER_EXPIRY);
					isdn_event_handle(pid, ISDN_RELEASE_IND);
					rel_B_chnl(pid);
					isdn_set_cause(&isdn_sd_msg.msg_list.relComp.cause, CAUSE_TIMER_EXPIRY);
					isdn_send_msg(pid, MSG_REL_COMP);
					rel_cr(pid);
					isdn_cpc_clear(pPort);
				}
			}
			break;
		case CALL_RV_STATE:
			if((++(pPort->w_time)) % (isdn_timer_var.t301) == 0)
			{
				pPort->w_time = 0;
				isdn_log_err(pid, "[timeout]:t301 NT CALL RV STATE\r\n");
				isdn_event_handle(pid, ISDN_TIMEOUT_IND);
			}
			break;
		case IN_CALL_PROC_STATE:
			if((++(pPort->w_time)) % (isdn_timer_var.t310) == 0)
			{
				pPort->w_time = 0;
				isdn_log_err(pid, "[timeout]:t310 NT IN CALL PROC STATE\r\n");
				isdn_event_handle(pid, ISDN_TIMEOUT_IND);
			}
			break;
		case DISC_IND_STATE:
			if((++(pPort->w_time)) % (isdn_timer_var.t305) == 0)
			{
				isdn_log_err(pid, "[timeout]:t305 NT DISC IND STATE\r\n");
				isdn_set_cause(&isdn_sd_msg.msg_list.rel.cause, CAUSE_TIMER_EXPIRY);
				nr_proc(pid);
				pPort->fsm_state.cpc_state = REL_REQ_STATE;
			}
			break;
		case REL_REQ_STATE:
			if((++(pPort->w_time)) % (isdn_timer_var.t308) == 0)
			{
				pPort->w_time = 0;
				if(pPort->timeout_fg == 0)
				{
					pPort->timeout_fg = 1;
					isdn_log_err(pid, "[timeout]:t308 NT REL REQ STATE first timeout, resend REL\r\n");
					isdn_set_cause(&isdn_sd_msg.msg_list.rel.cause, CAUSE_TIMER_EXPIRY);
					isdn_send_msg(pid, MSG_REL);
				}
				else
				{
					isdn_log_err(pid, "[timeout]:t308 NT REL REQ STATE\r\n");
					isdn_set_cause(&isdn_rv_msg.msg_list.relComp.cause, CAUSE_TIMER_EXPIRY);
					isdn_event_handle(pid, ISDN_RELEASE_CNF);	//error
					rel_B_chnl(pid);
					rel_cr(pid);
					isdn_cpc_clear(pPort);
				}
			}
			break;
		case OVERLAP_RV_STATE:
			if((++(pPort->w_time)) % (isdn_timer_var.t304) == 0)
			{
				pPort->w_time = 0;
				isdn_log_err(pid, "[timeout]:t304 NT OVERLAP RV STATE\r\n");
				isdn_event_handle(pid, ISDN_TIMEOUT_IND);
			}
			break;
		default:
			break;
	}

	return;
}

static void isdn_cpc_lt_timer(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	switch(pPort->fsm_state.cpc_state)
	{
		case CALL_INIT_STATE:
			if((++(pPort->w_time)) % (isdn_timer_var.t303) == 0)
			{
				pPort->w_time = 0;
				if(pPort->timeout_fg == 0)
				{
					pPort->timeout_fg = 1;
					isdn_log_err(pid, "[timeout]:t303 LT CALL INIT STATE, resend SETUP\r\n");
					isdn_send_msg(pid, MSG_SETUP);
				}
				else
				{
					isdn_log_err(pid, "[timeout]:t303 LT CALL INIT STATE, second timeout, clear call!\r\n");
					isdn_set_cause(&isdn_rv_msg.msg_list.rel.cause, CAUSE_TIMER_EXPIRY);
					isdn_event_handle(pid, ISDN_RELEASE_IND);
					rel_B_chnl(pid);
					isdn_set_cause(&isdn_sd_msg.msg_list.relComp.cause, CAUSE_TIMER_EXPIRY);
					isdn_send_msg(pid, MSG_REL_COMP);
					rel_cr(pid);
					isdn_cpc_clear(pPort);
				}
			}
			break;
		case OVERLAP_SD_STATE:
			if((++(pPort->w_time)) % (isdn_timer_var.t304) == 0)
			{
				pPort->w_time = 0;	//stop t304 and start t305
				isdn_log_err(pid, "[timeout]:t304 LT OVERLAP SD STATE\r\n");
				isdn_event_handle(pid, ISDN_TIMEOUT_IND);
			}
			break;
		case OUT_CALL_PROC_STATE:
			if((++(pPort->w_time)) % (isdn_timer_var.t310) == 0)
			{
				pPort->w_time = 0;	//stop t310 and start t305
				isdn_log_err(pid, "[timeout]:t310 LT OUT CALL PROC STATE\r\n");
				isdn_event_handle(pid, ISDN_TIMEOUT_IND);
			}
			break;
		case CALL_DV_STATE:
			if((++(pPort->w_time)) % (isdn_timer_var.t301) == 0)
			{
				pPort->w_time = 0;
				isdn_log_err(pid, "[timeout]:t301 LT CALL DV STATE\r\n");
				isdn_event_handle(pid, ISDN_TIMEOUT_IND);
			}
			break;
		case CONN_REQ_STATE:
			if((++(pPort->w_time)) % (isdn_timer_var.t313) == 0)
			{
				pPort->w_time = 0;	//stop t313 and start t305
				isdn_log_err(pid, "[timeout]:t313 LT CONN REQ STATE\r\n");
				isdn_event_handle(pid, ISDN_TIMEOUT_IND);
			}
			break;
		case DISC_REQ_STATE:
			if((++(pPort->w_time)) % (isdn_timer_var.t305) == 0)
			{
				isdn_log_err(pid, "[timeout]:t305 LT DISC REQ STATE\r\n");
				isdn_set_cause(&isdn_sd_msg.msg_list.rel.cause, CAUSE_TIMER_EXPIRY);
				nr_proc(pid);
				pPort->fsm_state.cpc_state = REL_REQ_STATE;
			}
			break;
		case REL_REQ_STATE:
			if((++(pPort->w_time)) % (isdn_timer_var.t308) == 0)
			{
				pPort->w_time = 0;
				if(pPort->timeout_fg == 0)
				{
					pPort->timeout_fg = 1;
					isdn_log_err(pid, "[timeout]:t308 LT REL REQ STATE, resend REL\r\n");
					isdn_set_cause(&isdn_sd_msg.msg_list.rel.cause, CAUSE_TIMER_EXPIRY);
					isdn_send_msg(pid, MSG_REL);
				}
				else
				{
					isdn_log_err(pid, "[timeout]:t308 LT REL REQ STATE\r\n");
					isdn_set_cause(&isdn_rv_msg.msg_list.relComp.cause, CAUSE_TIMER_EXPIRY);
					isdn_event_handle(pid, ISDN_RELEASE_CNF);	//error
					rel_B_chnl(pid);
					rel_cr(pid);
					isdn_cpc_clear(pPort);
				}
			}
			break;
		case OVERLAP_RV_STATE:
//			if((++(pPort->w_time)) % (isdn_timer_var.t302) == 0)
//			{
//				pPort->w_time = 0;
//				isdn_log_err(pid, "[timeout]:t302 LT OVERLAP RV STATE\r\n");
//				isdn_event_handle(pid, ISDN_TIMEOUT_IND);
//			}
			break;
		default:
			break;
	}

	return;
}

void isdn_cpc_timer(u32 pid)
{
	int circuit_id = pid / ISDN_CIRCUIT_CIC;
	const pal_circuit_struct *circuit_ptr = pal_circuit_ptr(circuit_id);
	if(circuit_ptr == NULL)
		return;

	if(!(isdn_rs.port_pond[pid].timer_flag & CALLIN_FLAG) && 
		!(isdn_rs.port_pond[pid].timer_flag & CALLOUT_FLAG))
		return;
	if(circuit_ptr->attrib.user_network_if)
		isdn_cpc_lt_timer(pid);
	else
		isdn_cpc_nt_timer(pid);
}

void isdn_restart_timer(u32 pid)
{
	int circuit_id, i, link_id, cic_range;
	const pal_circuit_struct *circuit_ptr = NULL;
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	circuit_id = pid / ISDN_CIRCUIT_CIC;
	circuit_ptr = pal_circuit_ptr(circuit_id);
	if(circuit_ptr == NULL)
		return;

	link_id = circuit_ptr->attrib.link_id;
	cic_range = circuit_ptr->attrib.cic_range;
	if(cic_range == 24)	//T1
		cic_range++;
	switch(pPort->cic_state.call_state)
	{
		case GLOBAL_RESTART_REQ_STATE:
			if((++(pPort->w_time)) % (isdn_timer_var.t316) == 0)
			{
				pPort->w_time = 0;
				if(pPort->timeout_fg == 2)
				{
					if(isdn_rs.link_pond[link_id].restart_clas == 0)
					{
						pid = find_port_by_cic(pPort->cic_val, circuit_id);
						isdn_log_err(pid, "[timeout]:t316 GLOBAL RESTART REQ STATE\r\n");
						isdn_event_handle(pid, ISDN_TIMEOUT_IND);
						rel_B_chnl(pid);
						rel_cr(pid);
						isdn_cpc_clear(pPort);
					}
					else
					{
						for(i = 1; i < cic_range; i++)
						{
							pid = circuit_id * ISDN_CIRCUIT_CIC + i;
							pPort = &isdn_rs.port_pond[pid];
							if(pPort->cic_val != 0)
							{
								isdn_log_err(pid, "[timeout]:t316 GLOBAL RESTART REQ STATE\r\n");
								isdn_event_handle(pid, ISDN_TIMEOUT_IND);
								rel_B_chnl(pid);
								rel_cr(pid);
								isdn_cpc_clear(pPort);
							}
						}
					}
				}
				else
				{
					pPort->timeout_fg++;
					isdn_log_err(pid, "[timeout]:t316 GLOBAL RESTART REQ STATE, resend RESTART\r\n");
					isdn_send_msg(pid, MSG_RESTART);
				}
			}
			break;			
		case GLOBAL_RESTART_STATE:
			if((++(pPort->w_time)) % (isdn_timer_var.t317) == 0)
			{
				pPort->w_time = 0;
				if(isdn_rs.link_pond[link_id].restart_clas == 0)
				{
					pid = find_port_by_cic(pPort->cic_val, circuit_id);
					isdn_log_err(pid, "[timeout]:t317 GLOBAL RESTART STATE\r\n");
					isdn_event_handle(pid, ISDN_TIMEOUT_IND);
					rel_B_chnl(pid);
					rel_cr(pid);
					isdn_cpc_clear(pPort);
				}
				else
				{
					for(i = 1; i < cic_range; i++)
					{
						pid = circuit_id * ISDN_CIRCUIT_CIC + i;
						pPort = &isdn_rs.port_pond[pid];
						if(pPort->cic_val != 0)
						{
							isdn_log_err(pid, "[timeout]:t317 GLOBAL RESTART STATE\r\n");
							isdn_event_handle(pid, ISDN_TIMEOUT_IND);
							rel_B_chnl(pid);
							rel_cr(pid);
							isdn_cpc_clear(pPort);
						}
					}
				}
			}
			break;
		default:
			break;
	}
}

int isdn_event_handle(u32 pid, u8 primitive)
/*
处理msc上层的状态机
*/
{
	int offset, circuit_id;
	Pst pst;
	ISDN_EventHandle_struct *event_handle = NULL;
	const pal_circuit_struct *circuit_ptr = NULL;
	const pal_cg_struct *cg_ptr = NULL;

	pst.sp_proc_id = pid;
	pst.su_proc_id = isdn_rs.port_pond[pid].su_proc_id;

	circuit_id = pid / ISDN_CIRCUIT_CIC;
	offset = pid % ISDN_CIRCUIT_CIC;
	circuit_ptr = pal_circuit_ptr(circuit_id);
	if(circuit_ptr == NULL)
		return ISDN_CM_FAILED;

	if(circuit_ptr->attrib.cic_range == 32)
		pst.cic = circuit_ptr->attrib.head_cic + offset;
	else
		pst.cic = circuit_ptr->attrib.head_cic + offset - 1;
	pst.cg_id = circuit_ptr->cg_id;
	cg_ptr = pal_cg_ptr(pst.cg_id);
	if(cg_ptr == NULL)
		return ISDN_CM_FAILED;
	if(cg_ptr->attrib.protocol != PROTO_ISDN)
		return ISDN_CM_FAILED;

	pst.tg_id = cg_ptr->attrib.tg_id;
	event_handle = (ISDN_EventHandle_struct *)pal_get_handler(pst.cg_id);
	if(event_handle == NULL)
		return ISDN_CM_FAILED;

	switch(primitive)
	{
		case ISDN_SETUP_IND:
			if(event_handle->h_isdn_setup_ind == NULL)
			{
				isdn_log_err(pid,"Setup indication handle is not registered@%s\r\n", __FUNCTION__);
				return ISDN_CM_FAILED;
			}
			isdn_trace_func(pid,"APP => function trace: isdn_setup_ind\r\n");
			event_handle->h_isdn_setup_ind(&pst, &(isdn_rv_msg.msg_list.setup));
			isdn_rs.port_pond[pid].su_proc_id = pst.su_proc_id;
			isdn_rs.port_pond[pid].trace_flag = pst.trace_flag;
			break;
		case ISDN_MORE_INFO_IND:
			if(event_handle->h_isdn_minfo_ind == NULL)
			{
				isdn_log_err(pid,"More information indication handle is not registered@%s\r\n", __FUNCTION__);
				return ISDN_CM_FAILED;
			}
			isdn_trace_func(pid,"APP => function trace: isdn_minfo_ind\r\n");
			event_handle->h_isdn_minfo_ind(&pst, &(isdn_rv_msg.msg_list.setupAck));
			break;
		case ISDN_ALERT_IND:
			if(event_handle->h_isdn_alert_ind == NULL)
			{
				isdn_log_err(pid,"Alert indication handle is not registered@%s\r\n", __FUNCTION__);
				return ISDN_CM_FAILED;
			}
			isdn_trace_func(pid,"APP => function trace: isdn_alert_ind\r\n");
			event_handle->h_isdn_alert_ind(&pst, &(isdn_rv_msg.msg_list.alert));
			break;
		case ISDN_SETUP_CNF:
			if(event_handle->h_isdn_setup_cnf == NULL)
			{
				isdn_log_err(pid,"Setup confirm handle is not registered@%s\r\n", __FUNCTION__);
				return ISDN_CM_FAILED;
			}
			isdn_trace_func(pid,"APP => function trace: isdn_setup_cnf\r\n");
			event_handle->h_isdn_setup_cnf(&pst, &(isdn_rv_msg.msg_list.conn));
			break;
		case ISDN_RELEASE_IND:
			if(event_handle->h_isdn_rel_ind == NULL)
			{
				isdn_log_err(pid,"Release indication handle is not registered@%s\r\n", __FUNCTION__);
				return ISDN_CM_FAILED;
			}
			isdn_trace_func(pid,"APP => function trace: isdn_rel_ind\r\n");
			event_handle->h_isdn_rel_ind(&pst, &(isdn_rv_msg.msg_list.rel));
			break;
		case ISDN_RELEASE_CNF:
			if(event_handle->h_isdn_rel_cnf == NULL)
			{
				isdn_log_err(pid,"Release confirm handle is not registered@%s\r\n", __FUNCTION__);
				return ISDN_CM_FAILED;
			}
			isdn_trace_func(pid,"APP => function trace: isdn_rel_cnf\r\n");
			event_handle->h_isdn_rel_cnf(&pst, &(isdn_rv_msg.msg_list.relComp));
			break;
		case ISDN_STAT_IND:
			if(event_handle->h_isdn_stat_ind == NULL)
			{
				isdn_log_err(pid,"Status indication handle is not registered@%s\r\n", __FUNCTION__);
				return ISDN_CM_FAILED;
			}
			isdn_trace_func(pid,"APP => function trace: isdn_stat_ind\r\n");
			event_handle->h_isdn_stat_ind(&pst, &(isdn_rv_msg.msg_list.status));
			break;
		case ISDN_RESTART_REQ:
			if(event_handle->h_isdn_restart_req == NULL)
			{
				isdn_log_err(pid,"Restart request handle is not registered@%s\r\n", __FUNCTION__);
				return ISDN_CM_FAILED;
			}
			isdn_trace_func(pid,"APP => function trace: isdn_restart_req\r\n");
			event_handle->h_isdn_restart_req(&pst, &(isdn_rv_msg.msg_list.restart));
			break;
		case ISDN_RESTART_CNF:
			if(event_handle->h_isdn_rest_cnf == NULL)
			{
				isdn_log_err(pid,"Restart confirm handle is not registered@%s\r\n", __FUNCTION__);
				return ISDN_CM_FAILED;
			}
			isdn_trace_func(pid,"APP => function trace: isdn_rest_cnf\r\n");
			event_handle->h_isdn_rest_cnf(&pst, &(isdn_rv_msg.msg_list.restAck));
			break;
		case ISDN_INFO_IND:
			if(event_handle->h_isdn_info_ind == NULL)
			{
				isdn_log_err(pid,"Information indication handle is not registered@%s\r\n", __FUNCTION__);
				return ISDN_CM_FAILED;
			}
			isdn_trace_func(pid,"APP => function trace: isdn_info_ind\r\n");
			event_handle->h_isdn_info_ind(&pst, &(isdn_rv_msg.msg_list.info));
			break;
		case ISDN_PROG_IND:
			if(event_handle->h_isdn_prog_ind == NULL)
			{
				isdn_log_err(pid,"Progress indication handle is not registered@%s\r\n", __FUNCTION__);
				return ISDN_CM_FAILED;
			}
			isdn_trace_func(pid,"APP => function trace: isdn_prog_ind\r\n");
			event_handle->h_isdn_prog_ind(&pst, &(isdn_rv_msg.msg_list.prog));
			break;
		case ISDN_NOTI_IND:
			if(event_handle->h_isdn_noti_ind == NULL)
			{
				isdn_log_err(pid,"Notify indication handle is not registered@%s\r\n", __FUNCTION__);
				return ISDN_CM_FAILED;
			}
			isdn_trace_func(pid,"APP => function trace: isdn_noti_ind\r\n");
			event_handle->h_isdn_noti_ind(&pst, &(isdn_rv_msg.msg_list.noti));
			break;
		case ISDN_TIMEOUT_IND:
			if(event_handle->h_isdn_timeout_ind == NULL)
			{
				isdn_log_err(pid,"Timeout indication handle is not registered@%s\r\n", __FUNCTION__);
				return ISDN_CM_FAILED;
			}
			isdn_trace_func(pid,"APP => function trace: isdn_timeout_ind\r\n");
			event_handle->h_isdn_timeout_ind(&pst);
			break;
		case ISDN_REATTEMPT_IND:
			if(event_handle->h_isdn_reattempt_ind == NULL)
			{
				isdn_log_err(pid,"Reattempt indication handle is not registered@%s\r\n", __FUNCTION__);
				return ISDN_CM_FAILED;
			}
			isdn_trace_func(pid,"APP => function trace: isdn_reattempt_ind\r\n");
			event_handle->h_isdn_reattempt_ind(&pst);
			break;
			
		case ISDN_PROC_IND:		//msc does not handle
/*			if(event_handle->h_isdn_proc_ind == NULL)
			{
				isdn_log_err(pid,"Call proceeding indication handle is not registered@%s\r\n", __FUNCTION__);
				return ISDN_CM_FAILED;
			}
			isdn_trace_func(pid,"APP => function trace: isdn_proc_ind\r\n");
			event_handle->h_isdn_proc_ind(&pst, &(isdn_rv_msg.msg_list.callProc));
*/			break;
		case ISDN_SETUP_COMP_IND:
			break;
		case ISDN_DISCONNECT_IND:	//msc does not handle
			if(event_handle->h_isdn_disc_ind == NULL)
			{
				isdn_log_err(pid,"Disconnect indication handle is not registered@%s\r\n", __FUNCTION__);
				return ISDN_CM_FAILED;
			}
			isdn_trace_func(pid,"APP => function trace: isdn_disc_ind\r\n");
			event_handle->h_isdn_disc_ind(&pst, &(isdn_rv_msg.msg_list.disc));
			break;

		case ISDN_SERVICE_IND:
			if(event_handle->h_isdn_service_ind == NULL)
			{
				isdn_log_err(pid,"Service indication handle is not registered@%s\r\n", __FUNCTION__);
				return ISDN_CM_FAILED;
			}
			isdn_trace_func(pid,"APP => function trace: isdn_service_ind\r\n");
			event_handle->h_isdn_service_ind(&pst, &(isdn_rv_msg.msg_list.service));
			isdn_rs.port_pond[pid].su_proc_id = pst.su_proc_id;
			isdn_rs.port_pond[pid].trace_flag = pst.trace_flag;
			break;
		case ISDN_SERVICE_CNF:
			if(event_handle->h_isdn_service_cnf == NULL)
			{
				isdn_log_err(pid,"Service confirm handle is not registered@%s\r\n", __FUNCTION__);
				return ISDN_CM_FAILED;
			}
			isdn_trace_func(pid,"APP => function trace: isdn_service_cnf\r\n");
			event_handle->h_isdn_service_cnf(&pst, &(isdn_rv_msg.msg_list.servAck));
			break;
		case ISDN_SER_TIMEOUT_IND:
			if(event_handle->h_isdn_ser_timeout_ind == NULL)
			{
				isdn_log_err(pid,"Service timeout indication handle is not registered@%s\r\n", __FUNCTION__);
				return ISDN_CM_FAILED;
			}
			isdn_trace_func(pid,"APP => function trace: isdn_ser_timeout_ind\r\n");
			event_handle->h_isdn_ser_timeout_ind(&pst);
			break;
		default:
			break;
	}

	return ISDN_CM_OK;
}


void stuff_encode_m(u32 pid, IsdnMsgStr *ptr, int type)
{
	ChgStat	chg_stat;
	ChnlId	chnl_id;

	chg_stat.pres = 1;
	chg_stat.pref = 1;
	chg_stat.new_stat = isdn_rs.port_pond[pid].cic_state.maintenance_state;
	chnl_id.pres = 1;
	chnl_id.b3.int_id_pre = 1;
	chnl_id.b3.int_type = 1;
	chnl_id.b3.pref_excl = 1;
	chnl_id.b3.chnl_ind = 1;
	chnl_id.b3.info_chnl_sel = 1;
	chnl_id.b3.int_id = pid / ISDN_CIRCUIT_CIC;
	chnl_id.b3.has_chnl = 1;
	chnl_id.b3.code_stan = 0;
	chnl_id.b3.num_map = 0;
	chnl_id.b3.chnl_type = 3;
	chnl_id.b3.chnl_num = pid % ISDN_CIRCUIT_CIC;
	if(type == MSG_SERVICE)
	{
		memcpy(&ptr->msg_list.service.chg_stat, &chg_stat, sizeof(ChgStat));
		memcpy(&ptr->msg_list.service.chnl_id, &chnl_id, sizeof(ChnlId));
	}
	else if(type == MSG_SERVICE_ACK)
	{
		memcpy(&ptr->msg_list.servAck.chg_stat, &chg_stat, sizeof(ChgStat));
		memcpy(&ptr->msg_list.servAck.chnl_id, &chnl_id, sizeof(ChnlId));
	}		
}

//ansi isdn maintenance D-channel and B-channel
void service_dc_proc(u32 pid)
{
	int circuit_id, link_id, cg_id, ds_0, ds_1;
	int far_status;
	const pal_circuit_struct *circuit_ptr = NULL;
	const pal_cg_struct *cg_ptr = NULL;
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	circuit_id = pid / ISDN_CIRCUIT_CIC;
	circuit_ptr = pal_circuit_ptr(circuit_id);
	if(circuit_ptr == NULL)
		return;

	link_id = circuit_ptr->attrib.link_id;
	cg_id = circuit_ptr->cg_id;
	cg_ptr = pal_cg_ptr(cg_id);
	if(cg_ptr == NULL)
		return;
	if(cg_ptr->attrib.protocol != PROTO_ISDN)
		return;

	ds_0 = cg_ptr->attrib.nfas.prim_link;
	ds_1 = cg_ptr->attrib.nfas.backup_link;
	far_status = isdn_rv_msg.msg_list.service.chg_stat.new_stat;

	if(cg_ptr->attrib.variant == VARIANT_ANSI)	//ANSI
	{
		switch(pPort->fsm_state.m_state)
		{
			case SERVICE_IDLE:
				if(pPort->g_pri_cmd == ISDN_SERVICE_REQ)
				{
					pPort->g_pri_cmd = 0;
					isdn_rs.link_pond[link_id].dc_status = DS_WAIT;
					pPort->w_time = 0;	//start t321
					pPort->timer_flag |= DC_M_FLAG;
					pPort->cic_state.maintenance_state = IN_SERVICE;
					stuff_encode_m(pid, &isdn_sd_msg, MSG_SERVICE);
					isdn_send_maintenance_msg(pid, MSG_SERVICE);
					pPort->cic_state.maintenance_state = OUT_OF_SERVICE;
					pPort->fsm_state.m_state = WAIT_SERVICE_ACK;
					printf("service_dc_proc: wait service ack!\n");
				}
				else if(pPort->msg_cmd == MSG_SERVICE)
				{
					pPort->msg_cmd = 0;
					pPort->callout_fg = 1;
					if(link_id == ds_0)
					{
						if((isdn_rs.link_pond[ds_1].dc_status != DS_IS) && 
							(isdn_rs.link_pond[link_id].lk3_status == LK_IS) && 
							(far_status == IN_SERVICE))
						{
							isdn_rs.link_pond[link_id].dc_status = DS_IS;
							pPort->cic_state.maintenance_state = IN_SERVICE;
							stuff_encode_m(pid, &isdn_sd_msg, MSG_SERVICE_ACK);
							isdn_send_maintenance_msg(pid, MSG_SERVICE_ACK);
							pPort->fsm_state.m_state = SERVICE_IDLE;
						}
					}
					else if(link_id == ds_1)
					{
						if(((isdn_rs.link_pond[ds_0].dc_status) == DS_OOS || 
							(isdn_rs.link_pond[ds_0].dc_status == DS_STBY)) && 
							(isdn_rs.link_pond[link_id].lk3_status == LK_IS) && 
							(far_status == IN_SERVICE))
						{
							isdn_rs.link_pond[link_id].dc_status = DS_IS;
							pPort->cic_state.maintenance_state = IN_SERVICE;
							stuff_encode_m(pid, &isdn_sd_msg, MSG_SERVICE_ACK);
							isdn_send_maintenance_msg(pid, MSG_SERVICE_ACK);
							pPort->fsm_state.m_state = SERVICE_IDLE;
						}
					}
					printf("service_dc_proc: receive service!\n");
				}
				if(pPort->msg_cmd == MSG_SERVICE_ACK)	//timeout t321		TODO
				{
					pPort->msg_cmd = 0;
					pPort->w_time = 0;	//stop t321
					if(far_status == IN_SERVICE)
					{
						isdn_rs.link_pond[link_id].dc_status = DS_IS;
						pPort->cic_state.maintenance_state = IN_SERVICE;
					}
					else
					{
						isdn_rs.link_pond[link_id].dc_status = DS_STBY;
						pPort->cic_state.maintenance_state = OUT_OF_SERVICE;
					}
					pPort->fsm_state.m_state = SERVICE_IDLE;
					printf("service_dc_proc: receive service ack in service idle!\n");
				}
				break;
			case WAIT_SERVICE_ACK:
				if(pPort->msg_cmd == MSG_SERVICE_ACK)
				{
					pPort->msg_cmd = 0;
					pPort->w_time = 0;	//stop t321
					if(far_status == IN_SERVICE)
					{
						isdn_rs.link_pond[link_id].dc_status = DS_IS;
						pPort->cic_state.maintenance_state = IN_SERVICE;
					}
					else
					{
						isdn_rs.link_pond[link_id].dc_status = DS_STBY;
						pPort->cic_state.maintenance_state = OUT_OF_SERVICE;
					}
					pPort->fsm_state.m_state = SERVICE_IDLE;
					printf("service_dc_proc: receive service ack!and enter service idle state\n");
				}
				else if(pPort->msg_cmd == MSG_SERVICE)	//collision
				{
					if(!cg_ptr->attrib.priority)
					{
						pPort->w_time = 0;	//stop t321
						pPort->fsm_state.m_state = SERVICE_IDLE;
						service_dc_proc(pid);
						printf("service_dc_proc: collision, and renew the state with service idle to receive msg!\n");
					}
					else
					{
						pPort->msg_cmd = 0;
						isdn_log_err(pid, "service_dc_proc: discard receive msg!\r\n");
						return;
					}
				}
				break;
			case RSP_SERVICE:
				break;
			default:
				break;
		}
	}
	else		//ITU
	{
		if(pPort->g_pri_cmd == ISDN_SERVICE_REQ)
		{
			pPort->g_pri_cmd = 0;
			isdn_rs.link_pond[link_id].dc_status = DS_IS;
		}
		else if(isdn_rs.link_pond[link_id].lk3_status == LK_IS && isdn_rs.link_pond[link_id].dc_status != DS_IS)
		{
			isdn_rs.link_pond[link_id].dc_status = DS_STBY;
		}
	}

//	if(isdn_rs.link_pond[link_id].dc_status == DS_OOS && isdn_rs.link_pond[link_id].lk3_status == LK_IS)
//		isdn_rs.link_pond[link_id].dc_status = DS_STBY;
	
	if(isdn_rs.link_pond[ds_0].dc_status == DS_IS && isdn_rs.link_pond[ds_1].dc_status == DS_IS)
		isdn_rs.link_pond[ds_1].dc_status = DS_STBY;
	else if(isdn_rs.link_pond[ds_0].dc_status == DS_STBY && isdn_rs.link_pond[ds_1].dc_status == DS_STBY)
		isdn_rs.link_pond[ds_0].dc_status = DS_IS;
	else if(isdn_rs.link_pond[ds_0].dc_status == DS_OOS && isdn_rs.link_pond[ds_1].dc_status == DS_STBY)
		isdn_rs.link_pond[ds_1].dc_status = DS_IS;
	else if(isdn_rs.link_pond[ds_0].dc_status == DS_STBY && isdn_rs.link_pond[ds_1].dc_status == DS_OOS)
		isdn_rs.link_pond[ds_0].dc_status = DS_IS;
	else if(isdn_rs.link_pond[ds_0].dc_status == DS_OOS && isdn_rs.link_pond[ds_1].dc_status == DS_OOS)
	{
		isdn_rs.link_pond[ds_0].dc_status = DS_MOOS;
		isdn_rs.link_pond[ds_1].dc_status = DS_MOOS;
	}

	return;
}

void service_bc_proc(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];
	const pal_cg_struct *cg_ptr = NULL;
	const pal_circuit_struct *circuit_ptr = pal_circuit_ptr(pid / ISDN_CIRCUIT_CIC);
	if(circuit_ptr == NULL)
		return;

	cg_ptr = pal_cg_ptr(circuit_ptr->cg_id);
	if(cg_ptr == NULL)
		return;
	if(cg_ptr->attrib.protocol != PROTO_ISDN)
		return;

	switch(pPort->fsm_state.m_state)
	{
		case SERVICE_IDLE:
			if(pPort->g_pri_cmd == ISDN_SERVICE_REQ)
			{
				pPort->g_pri_cmd = 0;
				if(isdn_sd_msg.msg_list.service.chg_stat.new_stat != IN_SERVICE)
				{
					pPort->primitive_cmd = ISDN_RELEASE_REQ;
					isdn_cpc_proc(pid);
				}
				pPort->w_time = 0;	//start t3M1
				pPort->timer_flag |= BC_M_FLAG;
				isdn_send_maintenance_msg(pid, MSG_SERVICE);
				pPort->cic_state.maintenance_state = isdn_sd_msg.msg_list.service.chg_stat.new_stat;
				pPort->fsm_state.m_state = WAIT_SERVICE_ACK;
				printf("service_bc_proc: wait service ack!\n");
			}
			else if(pPort->msg_cmd == MSG_SERVICE)
			{
				pPort->msg_cmd = 0;
				pPort->callout_fg = 1;
				pPort->cic_state.maintenance_state = isdn_rv_msg.msg_list.service.chg_stat.new_stat;
				pPort->fsm_state.m_state = RSP_SERVICE;
				printf("service_bc_proc: receive service!\n");
				isdn_event_handle(pid, ISDN_SERVICE_IND);	//indicate
			}
			else if(pPort->msg_cmd == MSG_SERVICE_ACK)	//timeout t3M1
			{
				pPort->msg_cmd = 0;
				pPort->w_time = 0;	//stop t3M1
				pPort->cic_state.maintenance_state = isdn_rv_msg.msg_list.service.chg_stat.new_stat;
				isdn_event_handle(pid, ISDN_SERVICE_CNF);	//confirm
				pPort->fsm_state.m_state = SERVICE_IDLE;
				printf("service_bc_proc: receive service ack in service idle!\n");
			}
			break;
		case WAIT_SERVICE_ACK:
			if(pPort->msg_cmd == MSG_SERVICE_ACK)
			{
				pPort->msg_cmd = 0;
				isdn_event_handle(pid, ISDN_SERVICE_CNF);	//confirm
				pPort->fsm_state.m_state = SERVICE_IDLE;
				printf("service_bc_proc: receive service ack!\n");
			}
			if(pPort->msg_cmd == MSG_SERVICE)	//接收service冲突 TODO
			{
				if(!cg_ptr->attrib.priority)
				{
					pPort->w_time = 0;
					pPort->cic_state.maintenance_state = ((pPort->cic_state.maintenance_state & 0x1) | (pPort->cic_state.maintenance_state >> 1)) ^ 0x1;		//run back initial
					pPort->fsm_state.m_state = SERVICE_IDLE;
					isdn_event_handle(pid, ISDN_REATTEMPT_IND);	//indicate
					service_bc_proc(pid);
					printf("service_bc_proc: collision, and renew the state with service idle to receive msg!\n");
				}
				else
				{
					pPort->msg_cmd = 0;
					isdn_log_err(pid, "service_dc_proc: discard receive msg!\r\n");
					return;
				}
			}
			break;
		case RSP_SERVICE:
			if(pPort->g_pri_cmd == ISDN_SERVICE_RSP)
			{
				pPort->g_pri_cmd = 0;
				pPort->fsm_state.m_state = SERVICE_IDLE;
				pPort->cic_state.maintenance_state = isdn_sd_msg.msg_list.servAck.chg_stat.new_stat;
				isdn_send_maintenance_msg(pid, MSG_SERVICE_ACK);
				printf("service_bc_proc: response service!\n");
			}
			break;
		default:
			break;
	}
}

void service_dc_timer(u32 pid)
{
	int link_id;
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];
	const pal_circuit_struct *circuit_ptr = pal_circuit_ptr(pid / ISDN_CIRCUIT_CIC);
	if(circuit_ptr == NULL)
		return;

	link_id = circuit_ptr->attrib.link_id;
	switch(pPort->fsm_state.m_state)
	{
		case WAIT_SERVICE_ACK:
			if((++(pPort->w_time)) % (isdn_timer_var.t321) == 0)
			{
				pPort->w_time = 0;	//stop t3M1
				pPort->fsm_state.m_state = SERVICE_IDLE;
				pPort->cic_state.maintenance_state = OUT_OF_SERVICE;
				isdn_rs.link_pond[link_id].dc_status = DS_OOS;
				isdn_log_err(pid, "service_dc_timer: t321 timeout!\r\n");
			}
			break;
		default:
			break;
	}
}

void service_bc_timer(u32 pid)
{
	ISDN_Port_struct *pPort = &isdn_rs.port_pond[pid];

	switch(pPort->fsm_state.m_state)
	{
		case WAIT_SERVICE_ACK:
			if((++(pPort->w_time)) % (isdn_timer_var.t3M1) == 0)
			{
				pPort->w_time = 0;	//stop t3M1
				isdn_event_handle(pid, ISDN_SER_TIMEOUT_IND);
				pPort->fsm_state.m_state = SERVICE_IDLE;
				pPort->cic_state.maintenance_state = OUT_OF_SERVICE;
				isdn_log_err(pid, "service_bc_timer: t3M1 timeout!\r\n");
			}
			break;
		default:
			break;
	}
}

void maintenance_timer(u32 pid)
{
	if(isdn_rs.port_pond[pid].timer_flag & BC_M_FLAG)
		service_bc_timer(pid);
	if(isdn_rs.port_pond[pid].timer_flag & DC_M_FLAG)
		service_dc_timer(pid);
}

