#include "./include/inc.h"
#include "./include/var_ext.h"
#include "../../public/src/include/license_id.h"

BiccReadPrim_union readPrim_union[BICC_MAX_PORT];
BiccWritePrim_union writePrim_union[BICC_MAX_PORT];
u8 Bicc_Version[4] = BICC_VERSION;
u8									local_platid=0;
extern BiccData_struct 				Bicc_Data;
BiccTimer_struct					Timer_Data;
up_message_2						r_mtp_msg; 			//message receive from mtp3
extern BiccMsg_union            	msg_union[BICC_MAX_PORT];

//void bicc_cpio_proc(u32 pid);
int     check_outbound_route(BYTE nw, long dpc, BYTE sls);
extern BOOL bicc_event_handle(u32 pid, const BiccReadPrim_union *prm_ptr, u8 primitive, u8 eventType);
extern void bicc_cpci_proc(u32 pid);
extern void bicc_cpco_proc(u32 pid);
extern void bicc_mgbs_proc(u32 pid);
extern void bicc_mgbr_proc(u32 pid);
extern void bicc_crs_proc(u32 pid);
extern BOOL check_crs_waiting(u32 pid);
extern void bicc_crr_proc(u32 pid);
extern void bicc_cgrs_proc(u32 pid);
extern void bicc_cgrr_proc(u32 pid);
extern void bicc_circuit_reset(u32 pid, const char *s);
extern void bicc_decode_backcall(BackCallInd_struct *ptr, const u8 *flw_ptr);
extern void bicc_decode_app(AppTrans_struct *ptr, const u8 *flw_ptr, u8 length);
extern void bicc_decode_calledptynum(CalledPtyNum_struct *ptr, const u8 *flw_ptr, u8 length);
extern void bicc_decode_callingptynum(CallingPtyNum_struct *ptr, const u8 *flw_ptr, u8 length);
extern void bicc_decode_callingptycat(CallingPtyCat_struct *ptr, const u8 *flw_ptr);
extern void bicc_decode_cause(CauseInd_struct *ptr, const u8 *flw_ptr, u8 length);
extern void bicc_decode_cicgrpspv(CicGrpSpv_struct *ptr, const u8 *flw_ptr);
extern void bicc_decode_collectcallreq(CollectCallReq_struct *ptr, const u8 *flw_ptr);
extern void bicc_decode_conftreat(ConfTreatInd_struct *ptr, const u8 *flw_ptr);
extern void bicc_decode_connnum(ConnNum_struct *ptr, const u8 *flw_ptr, u8 length);
extern void bicc_decode_genericnumber(GenericNumber_struct *ptr, const u8 *flw_ptr, u8 length);
extern void bicc_decode_genericDigits(GenericDigits_struct *ptr, const u8 *flw_ptr, u8 length);
extern void bicc_decode_correlationid(CorrelationId_struct *ptr, const u8 *flw_ptr, u8 length);
extern void bicc_decode_fwdcall(FwdCallInd_struct *ptr, const u8 *flw_ptr);
extern void bicc_decode_natconn(NatConnInd_struct *ptr, const u8 *flw_ptr);
extern void bicc_decode_origcallednum(OrigCalledNum_struct *ptr, const u8 *flw_ptr, u8 length);
extern void bicc_decode_utuind(UserToUserInd_struct *ptr, const u8 *flw_ptr);
extern void bicc_decode_utuinfo(UserToUserInfo_struct *ptr, const u8 *flw_ptr, u8 length);
extern void bicc_decode_eventinfo(EventInfo_struct *ptr, const u8 *flw_ptr);
extern void bicc_decode_rangestatus(RangeStatus_struct *ptr, const u8 *flw_ptr, u8 length, u8 need_status);
extern void bicc_decode_transmedreq(TransMedReq_struct *ptr, const u8 *flw_ptr);
extern void bicc_decode_redirgnum(RedirgNum_struct *ptr, const u8 *flw_ptr, u8 length);
extern void bicc_decode_redirinfo(RedirInfo_struct *ptr, u8 *flw_ptr, u8 length);
extern void bicc_decode_scfid(ScfId_struct *ptr, const u8 *flw_ptr, u8 length);
extern void bicc_decode_susres(SusResInd_struct *ptr, const u8 *flw_ptr);
extern void bicc_decode_subseqnum(SubseqNum_struct *ptr, const u8 *flw_ptr, u8 length);
extern void bicc_decode_calldiverinfo(CallDiverInfo_struct *ptr, const u8 *flw_ptr);
extern void bicc_decode_optBackCallInd(OptBackCallInd_struct *ptr, const u8 *flw_ptr);
extern void bicc_msg2prm(BiccReadPrim_union *prm_ptr, BiccMsg_union *msg_ptr, u8 msg_type);
extern void bicc_log_err(const char *fmt, ...);
extern void bicc_send_apm(u32 pid);

int BICC_active_dmp(u8 plat_id, u32 alter_id)
{
	if(plat_id >= 2)
		return 0;
	Bicc_Data.dmp_data.active = 1;
	Bicc_Data.dmp_data.processor_id = local_platid;
	Bicc_Data.dmp_data.remote_ip = alter_id;
	return BICC_CM_OK;
}

int BICC_deactive_dmp()
{
	Bicc_Data.dmp_data.active = 0;
	Bicc_Data.dmp_data.remote_ip = 0;
	Bicc_Data.dmp_data.processor_id = local_platid;
	return BICC_CM_OK;
}

void bicc_transmit_func(u32 remote_ip, up_message_2 *upmsg_ptr)                  //transmit message to remote ip
{
	upmsg_ptr->dest_ip = remote_ip;
	//bicc_to_mtp3(upmsg_ptr);
	bicc_redirect(upmsg_ptr);
}

int getPidByCic(u32 *pid, u32 cg_id, u32 cic)
{
	const pal_circuit_struct *pcircuit = NULL;
	if((pcircuit = pal_locate_circuit(cg_id, cic)) != NULL)
	{
		*pid = (pcircuit->id)*BICC_CIRCUIT_CIC + (cic - pcircuit->attrib.head_cic);
		return 1;
	}
	bicc_log_err("can not get port by cic %d, cg %d [%s]\n", cic,cg_id,__FUNCTION__);
	return 0;
}

static int find_port_by_cic(u8 ni, u32 dpc, u32 opc, u32 cic_val, u32* pid)
{
	const pal_circuit_struct *pcircuit = NULL;
	if((pcircuit = pal_ss7_find_circuit(ni, opc, dpc, cic_val)) != NULL)
	{
		*pid = pcircuit->id*BICC_CIRCUIT_CIC + (cic_val - pcircuit->attrib.head_cic);
		return 1;
	}
	bicc_log_err("can not find port by cic %d dpc %d opc %d ni %d [%s]\n",cic_val,opc,dpc,ni,__FUNCTION__);
	return 0;
}



int BICC_mdsc_proc()				//get the message form Lower Layer
{
	u32							sap_id, cg_id, circuit_id;
	u32							cic_val;
	u32							pid;
	u8							*flw_ptr;	//message flow pointer
	u8							msg_type;
	BICC_Port_struct			*port_ptr;
	BiccMsg_union				*msg_ptr;
	BiccDmp_struct				*dmp_ptr = &Bicc_Data.dmp_data;
	const pal_circuit_struct 	*pcircuit = NULL;
	const pal_cg_struct			*pcg = NULL;
	if(bicc_GetMsg(&r_mtp_msg) == 0)
		return 0;


	cic_val = (r_mtp_msg.cic[3]<<24) + (r_mtp_msg.cic[2]<<16) + (r_mtp_msg.cic[1]<<8) + r_mtp_msg.cic[0];

	if(!find_port_by_cic(r_mtp_msg.sio>>6, r_mtp_msg.dpc, r_mtp_msg.opc, cic_val, &pid))
		return 0;
	circuit_id = pid / BICC_CIRCUIT_CIC;
	pcircuit = pal_circuit_ptr(circuit_id);
	if((dmp_ptr->active == 1) && (pcircuit != NULL) && (pcircuit->attrib.plat_id != dmp_ptr->processor_id))
   	{    	
    	bicc_transmit_func(dmp_ptr->remote_ip, &r_mtp_msg);
        monitor_bicc_msg(r_mtp_msg.msgList, r_mtp_msg.len, 2, cic_val,pid);
        return 1 ;
    }
	cg_id = pcircuit->cg_id;
	pcg = pal_cg_ptr(cg_id);
	if(pcg == NULL && pcg->enable == 0)
    	return 0;
	sap_id = pcg->sap_id;
	port_ptr = &Bicc_Data.port_data[pid];
	flw_ptr = r_mtp_msg.msgList;
	msg_type = *(flw_ptr++);
	msg_ptr = &msg_union[pid];
	memset(msg_ptr, 0, sizeof(BiccMsg_union));

	monitor_bicc_msg(r_mtp_msg.msgList, r_mtp_msg.len, 0, cic_val, pid);
	switch(msg_type)
	{
		case M_ACM:
			if(port_ptr->cic_state.call_state == BICC_CIC_IDLE)
			{
				bicc_circuit_reset(pid, "recv acm at idle");
				break;
			}
			port_ptr->sprc_cmd = M_ACM;
			bicc_decode_backcall(&msg_ptr->acm.backCall, flw_ptr);
			flw_ptr += 2;
			if(*flw_ptr == 0)
				break;
			flw_ptr += *flw_ptr;
			while(flw_ptr+flw_ptr[1]+2-r_mtp_msg.msgList <= r_mtp_msg.len)
			{
				if(*flw_ptr == 0)	//end of option parameter
					break;
				switch(*flw_ptr)
				{
					case P_APPTRANS:
						bicc_decode_app(&msg_ptr->acm.app, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_CAUSEIND:
						bicc_decode_cause(&msg_ptr->acm.cause, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_CONFTREATIND:
						bicc_decode_conftreat(&msg_ptr->acm.confTreat, flw_ptr+2);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_OPTBACKCALLIND:
						bicc_decode_optBackCallInd(&msg_ptr->acm.optBackCall,flw_ptr+2);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_UTUIND:
						bicc_decode_utuind(&msg_ptr->acm.utuInd, flw_ptr+2);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_UTUINFO:
						bicc_decode_utuinfo(&msg_ptr->acm.utuInfo, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					default:
						flw_ptr += flw_ptr[1] + 2;
						break;
				}
			}
			bicc_cpco_proc(pid);
			break;
		case M_ANM:
			if(port_ptr->cic_state.call_state == BICC_CIC_IDLE)
			{
				bicc_circuit_reset(pid, "recv anm at idle");
				break;
			}
			port_ptr->sprc_cmd = M_ANM;
			if(*flw_ptr == 0)
				break;
			flw_ptr += *flw_ptr;
			while(flw_ptr+flw_ptr[1]+2-r_mtp_msg.msgList <= r_mtp_msg.len)
			{
				if(*flw_ptr == 0)	//end of option parameter
					break;
				switch(*flw_ptr)
				{
					case P_APPTRANS:
						bicc_decode_app(&msg_ptr->anm.app, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_BACKCALLIND:
						bicc_decode_backcall(&msg_ptr->anm.backCall, flw_ptr+2);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_CONFTREATIND:
						bicc_decode_conftreat(&msg_ptr->anm.confTreat, flw_ptr+2);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_CONNNUM:
						bicc_decode_connnum(&msg_ptr->anm.connNum, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_UTUIND:
						bicc_decode_utuind(&msg_ptr->anm.utuInd, flw_ptr+2);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_UTUINFO:
						bicc_decode_utuinfo(&msg_ptr->anm.utuInfo, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					default:
						flw_ptr += flw_ptr[1] + 2;
						break;
				}
			}
			break;
		case M_APM:	// APM is not sent to CPC, event handle function is called directly
			if(port_ptr->cic_state.call_state == BICC_CIC_IDLE)
			{
				bicc_circuit_reset(pid, "recv apm at idle");
				return 0;
			}
			if(*flw_ptr == 0)
				break;
			flw_ptr += *flw_ptr;
			while(flw_ptr+flw_ptr[1]+2-r_mtp_msg.msgList <= r_mtp_msg.len)
			{
				if(*flw_ptr == 0)	//end of option parameter
					break;
				switch(*flw_ptr)
				{
					case P_APPTRANS:
						bicc_decode_app(&msg_ptr->apm.app, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					default:
						flw_ptr += flw_ptr[1] + 2;
						break;
				}
			}
			break;
		case M_CPG:
			if(port_ptr->cic_state.call_state == BICC_CIC_IDLE)
			{
				bicc_circuit_reset(pid, "recv cpg at idle");
				break;
			}
			port_ptr->sprc_cmd = M_CPG;
			bicc_decode_eventinfo(&msg_ptr->cpg.eventInfo, flw_ptr);
			flw_ptr += 1;
			if(*flw_ptr == 0)
				break;
			flw_ptr += *flw_ptr;
			while(flw_ptr+flw_ptr[1]+2-r_mtp_msg.msgList <= r_mtp_msg.len)
			{
				if(*flw_ptr == 0)	//end of option parameter
					break;
				switch(*flw_ptr)
				{
					case P_APPTRANS:
						bicc_decode_app(&msg_ptr->cpg.app, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_BACKCALLIND:
						bicc_decode_backcall(&msg_ptr->cpg.backCall, flw_ptr+2);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_CAUSEIND:
						bicc_decode_cause(&msg_ptr->cpg.cause, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_CONFTREATIND:
						bicc_decode_conftreat(&msg_ptr->cpg.confTreat, flw_ptr+2);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_CONNNUM:
						bicc_decode_connnum(&msg_ptr->cpg.connNum, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_UTUIND:
						bicc_decode_utuind(&msg_ptr->cpg.utuInd, flw_ptr+2);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_UTUINFO:
						bicc_decode_utuinfo(&msg_ptr->cpg.utuInfo, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_CALLDIVERINFO:
						bicc_decode_calldiverinfo(&msg_ptr->cpg.calldiver, flw_ptr+2);
						flw_ptr += flw_ptr[1] + 2;
						break;
					default:
						flw_ptr += flw_ptr[1] + 2;
						break;
				}
			}
			break;
		case M_CGB:
			port_ptr->sprc_cmd = M_CGB;
			bicc_decode_cicgrpspv(&msg_ptr->cgb.cicGrpSpv, flw_ptr);
			flw_ptr += 1;
			bicc_decode_rangestatus(&msg_ptr->cgb.rangeStatus, flw_ptr+*flw_ptr+1, *(flw_ptr + *flw_ptr), 1);
			break;
		case M_CGBA:
			port_ptr->sprc_cmd = M_CGBA;
			bicc_decode_cicgrpspv(&msg_ptr->cgba.cicGrpSpv, flw_ptr);
			flw_ptr += 1;
			bicc_decode_rangestatus(&msg_ptr->cgba.rangeStatus, flw_ptr+*flw_ptr+1, *(flw_ptr + *flw_ptr), 1);
			break;
		case M_CGU:
			port_ptr->sprc_cmd = M_CGU;
			bicc_decode_cicgrpspv(&msg_ptr->cgu.cicGrpSpv, flw_ptr);
			flw_ptr += 1;
			bicc_decode_rangestatus(&msg_ptr->cgu.rangeStatus, flw_ptr+*flw_ptr+1, *(flw_ptr + *flw_ptr), 1);
			break;
		case M_CGUA:
			port_ptr->sprc_cmd = M_CGUA;
			bicc_decode_cicgrpspv(&msg_ptr->cgua.cicGrpSpv, flw_ptr);
			flw_ptr += 1;
			bicc_decode_rangestatus(&msg_ptr->cgua.rangeStatus, flw_ptr+*flw_ptr+1, *(flw_ptr + *flw_ptr), 1);
			break;
		case M_GRS:
			port_ptr->sprc_cmd = M_GRS;
			bicc_decode_rangestatus(&msg_ptr->grs.rangeStatus, flw_ptr+*flw_ptr+1, *(flw_ptr + *flw_ptr), 0);
			break;
		case M_GRA:
			port_ptr->sprc_cmd = M_GRA;
			bicc_decode_rangestatus(&msg_ptr->gra.rangeStatus, flw_ptr+*flw_ptr+1, *(flw_ptr + *flw_ptr), 1);
			break;
		case M_CON:
			if(port_ptr->cic_state.call_state == BICC_CIC_IDLE)
			{
				bicc_circuit_reset(pid, "recv con at idle");
				break;
			}
			port_ptr->sprc_cmd = M_CON;
			bicc_decode_backcall(&msg_ptr->con.backCall, flw_ptr);
			flw_ptr += 2;
			if(*flw_ptr == 0)
				break;
			flw_ptr += *flw_ptr;
			while(flw_ptr+flw_ptr[1]+2-r_mtp_msg.msgList <= r_mtp_msg.len)
			{
				if(*flw_ptr == 0)	//end of option parameter
					break;
				switch(*flw_ptr)
				{
					case P_APPTRANS:
						bicc_decode_app(&msg_ptr->con.app, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_CONFTREATIND:
						bicc_decode_conftreat(&msg_ptr->con.confTreat, flw_ptr+2);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_CONNNUM:
						bicc_decode_connnum(&msg_ptr->con.connNum, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_UTUIND:
						bicc_decode_utuind(&msg_ptr->con.utuInd, flw_ptr+2);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_UTUINFO:
						bicc_decode_utuinfo(&msg_ptr->con.utuInfo, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					default:
						flw_ptr += flw_ptr[1] + 2;
						break;
				}
			}
			break;
		case M_IAM:
#ifdef BICC_REATTEMPT
			if(port_ptr->cic_state.call_state == BICC_INCOMING)
				return 0;
#else
			if(port_ptr->cic_state.call_state != BICC_CIC_IDLE)
				return 0;
#endif
			if(port_ptr->cic_state.call_state == BICC_TYPE_OUTGOING)
			{
				bicc_circuit_reset(pid, "recv iam at outgoing cic");
				break;
			}
#ifdef BICC_REATTEMPT
			if(port_ptr->cic_state.call_state == BICC_CIC_IDLE)
			{
				port_ptr->cic_state.call_state = BICC_INCOMING;	// mark the cic
			}
#else
			port_ptr->cic_state.call_state = BICC_INCOMING;	// mark the cic
#endif
			port_ptr->sprc_cmd = M_IAM;
			bicc_decode_natconn(&msg_ptr->iam.natConn, flw_ptr);
			flw_ptr += 1;
			bicc_decode_fwdcall(&msg_ptr->iam.fwdCall, flw_ptr);
			flw_ptr += 2;
			bicc_decode_callingptycat(&msg_ptr->iam.callingPtyCat, flw_ptr);
			flw_ptr += 1;
			bicc_decode_transmedreq(&msg_ptr->iam.transMedReq, flw_ptr);
			flw_ptr += 1;
			bicc_decode_calledptynum(&msg_ptr->iam.calledPtyNum, flw_ptr+*flw_ptr+1, *(flw_ptr + *flw_ptr));
			flw_ptr++;
			if(*flw_ptr == 0)
				break;
			flw_ptr += *flw_ptr;
			while(flw_ptr+flw_ptr[1]+2-r_mtp_msg.msgList <= r_mtp_msg.len)
			{
				if(*flw_ptr == 0)	//end of option parameter
					break;
				switch(*flw_ptr)
				{
					case P_APPTRANS:
						bicc_decode_app(&msg_ptr->iam.app, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_CALLINGPTYNUM:
						bicc_decode_callingptynum(&msg_ptr->iam.callingPtyNum, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_COLLECTCALLREQ:
						bicc_decode_collectcallreq(&msg_ptr->iam.collectCallReq, flw_ptr+2);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_CONFTREATIND:
						bicc_decode_conftreat(&msg_ptr->iam.confTreat, flw_ptr+2);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_CORRELATIONID:
						bicc_decode_correlationid(&msg_ptr->iam.correlationId, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_ORIGCALLEDNUM:
						bicc_decode_origcallednum(&msg_ptr->iam.origCalledNum, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_REDIRGNUM:
						bicc_decode_redirgnum(&msg_ptr->iam.redirgNum, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_REDIRINFO:
						bicc_decode_redirinfo(&msg_ptr->iam.redirInfo, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_SCFID:
						bicc_decode_scfid(&msg_ptr->iam.scfId, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_UTUIND:
						bicc_decode_utuind(&msg_ptr->iam.utuInd, flw_ptr+2);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_UTUINFO:
						bicc_decode_utuinfo(&msg_ptr->iam.utuInfo, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					default:
						flw_ptr += flw_ptr[1] + 2;
						break;
				}
			}
			break;
		case M_REL:
			if(port_ptr->cic_state.call_state == BICC_CIC_IDLE)
				port_ptr->cic_state.call_state = BICC_INCOMING;
			port_ptr->sprc_cmd = M_REL;
			bicc_decode_cause(&msg_ptr->rel.cause, flw_ptr+*flw_ptr+1, *(flw_ptr + *flw_ptr));
			flw_ptr++;
			if(*flw_ptr == 0)
				break;
			flw_ptr += *flw_ptr;
			while(flw_ptr+flw_ptr[1]+2-r_mtp_msg.msgList <= r_mtp_msg.len)
			{
				if(*flw_ptr == 0)	//end of option parameter
					break;
				switch(*flw_ptr)
				{
					case P_UTUIND:
						bicc_decode_utuind(&msg_ptr->iam.utuInd, flw_ptr+2);
						flw_ptr += flw_ptr[1] + 2;
						break;
					case P_UTUINFO:
						bicc_decode_utuinfo(&msg_ptr->iam.utuInfo, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					default:
						flw_ptr += flw_ptr[1] + 2;
						break;
				}
			}
			break;
		case M_RLC:
		//	if(Bicc_Data.port_data[pid].used_flag == 0)
		//		return 0;
			if(check_crs_waiting(pid))
				port_ptr->sprc_cmd = M_RLC;
			else
			{
				if(port_ptr->cic_state.call_state == BICC_CIC_IDLE)
			//		port_ptr->cic_state.call_state = BICC_INCOMING;
					break;
				port_ptr->sprc_cmd = M_RLC;
			}
			if(*flw_ptr == 0)
				break;
			flw_ptr += *flw_ptr;
			while(flw_ptr+flw_ptr[1]+2-r_mtp_msg.msgList <= r_mtp_msg.len)
			{
				if(*flw_ptr == 0)	//end of option parameter
					break;
				switch(*flw_ptr)
				{
					case P_CAUSEIND:
						bicc_decode_cause(&msg_ptr->rlc.cause, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					default:
						flw_ptr += flw_ptr[1] + 2;
						break;
				}
			}
			break;
		case M_RSC:
			port_ptr->sprc_cmd = M_RSC;
			break;
		case M_RES:
			if(port_ptr->cic_state.call_state == BICC_CIC_IDLE)
			{
				bicc_circuit_reset(pid, "recv res at idle");
				break;
			}
			port_ptr->sprc_cmd = M_RES;
			bicc_decode_susres(&msg_ptr->res.susRes, flw_ptr);
			break;
		case M_SUS:
			if(port_ptr->cic_state.call_state == BICC_CIC_IDLE)
			{
				bicc_circuit_reset(pid, "recv sus at idle");
				break;
			}
			port_ptr->sprc_cmd = M_SUS;
			bicc_decode_susres(&msg_ptr->sus.susRes, flw_ptr);
			break;
		case M_SAM:
			if(port_ptr->cic_state.call_state == BICC_CIC_IDLE)
			{
				bicc_circuit_reset(pid, "recv sam at idle");
				break;
			}
			port_ptr->sprc_cmd = M_SAM;
			if(*flw_ptr == 0)
				break;
			flw_ptr += *flw_ptr;
			while(flw_ptr+flw_ptr[1]+2-r_mtp_msg.msgList <= r_mtp_msg.len)
			{
				if(*flw_ptr == 0)	//end of option parameter
					break;
				switch(*flw_ptr)
				{
					case P_SUBSEQNUM:
						bicc_decode_subseqnum(&msg_ptr->sam.subseqNum, flw_ptr+2, flw_ptr[1]);
						flw_ptr += flw_ptr[1] + 2;
						break;
					default:
						flw_ptr += flw_ptr[1] + 2;
						break;
				}
			}
			break;
		default:	//unknow message type
			break;
	}
	bicc_msg2prm(&readPrim_union[pid], &msg_union[pid], msg_type);
	if(msg_type == M_GRS)
		bicc_cgrr_proc(pid);
	if(msg_type == M_GRA)
		bicc_cgrs_proc(pid);
	if(msg_type == M_APM)
		bicc_event_handle(pid, &readPrim_union[pid], BICC_APM_IND, EN_NONE);
	if(msg_type == M_IAM)
	{
		bicc_cpci_proc(pid);
		Bicc_Data.port_data[pid].used_flag = 1;
	}
	return 1;
	
}

void BICC_msdc_proc(u32 pid, up_message_2 * upmsg_ptr)			//send the message to Lower Layer 
{
	u32							cg_id, circuit_id;
	u32							cic_val;
	const pal_circuit_struct 	*pcircuit = NULL;
	const pal_cg_struct 		*pcg = NULL;
	
	circuit_id = pid / BICC_CIRCUIT_CIC;
	pcircuit = pal_circuit_ptr(circuit_id);
	if(pcircuit != NULL)
		cg_id = pcircuit->cg_id;
	pcg = pal_cg_ptr(cg_id);
	if(pcg == NULL)
		return;
	if((cic_val = pcircuit->attrib.head_cic+ pid % BICC_CIRCUIT_CIC) >
		(pcircuit->attrib.head_cic + pcircuit->attrib.cic_range))
	{
		bicc_log_err("No cic corresponds to pid.\n");
		return;
	}

	
	upmsg_ptr->dest_ip = 0xffffffff;
	upmsg_ptr->dpc = pcg->attrib.dpc;
	upmsg_ptr->opc = pcg->attrib.opc;
	upmsg_ptr->cic[0] = cic_val & 0xff;
	upmsg_ptr->cic[1] = (cic_val >> 8) & 0xff;
	upmsg_ptr->cic[2] = (cic_val >> 16) & 0xff;
	upmsg_ptr->cic[3] = (cic_val >> 24) & 0xff;
	upmsg_ptr->sio = (pcg->attrib.network_id<<6) + BICC_SI;
	
	monitor_bicc_msg(Bicc_Data.port_data[pid].s_mtp_msg.msgList, Bicc_Data.port_data[pid].s_mtp_msg.len, 1, cic_val, pid);
	bicc_to_mtp3(upmsg_ptr);
}

int BICC_con_req(Pst *pst, BiccSetup_Req * ptr)
{
	
	BICC_Port_struct *port_ptr;
	if(pst->sp_proc_id == 0)
		if(!getPidByCic(&pst->sp_proc_id, pst->cg_id, pst->cic))
			return 0;

	port_ptr = &Bicc_Data.port_data[pst->sp_proc_id];
	if(port_ptr->cic_state.call_state == BICC_CIC_IDLE)
	{
		port_ptr->su_proc_id = pst->su_proc_id;
		port_ptr->primitive_cmd = BICC_SETUP_REQ;
		port_ptr->used_flag = 1;
		port_ptr->trace_flag = pst->trace_flag;
	//if(port_ptr->cic_state.call_state == BICC_CIC_IDLE)
	//{
		port_ptr->cic_state.call_state = BICC_OUTGOING;
		memcpy(&writePrim_union[pst->sp_proc_id].setup_req, ptr, sizeof(BiccSetup_Req));
	}
	else
	{
		
		bicc_log_err("cic not idle,cic=%d, port = %d\n",pst->cic,pst->sp_proc_id);
        	return 0;

	}
	
	return 1;

}

int BICC_con_rsp(Pst *pst, BiccSetup_Rsp * ptr)
{

	BICC_Port_struct *port_ptr;
	if(pst->sp_proc_id == 0)
		if(!getPidByCic(&pst->sp_proc_id, pst->cg_id, pst->cic))
			return 0;

	port_ptr = &Bicc_Data.port_data[pst->sp_proc_id];
//	port_ptr->su_proc_id = pst->su_proc_id;
	port_ptr->primitive_cmd = BICC_SETUP_RSP;

	memcpy(&writePrim_union[pst->sp_proc_id].setup_rsp, ptr, sizeof(BiccSetup_Rsp));
	return 1;
}



int BICC_rel_req(Pst *pst, BiccRel_Req * ptr)
{
	BICC_Port_struct *port_ptr;
	if(pst->sp_proc_id == 0)
		if(!getPidByCic(&pst->sp_proc_id, pst->cg_id, pst->cic))
			return 0;
	port_ptr = &Bicc_Data.port_data[pst->sp_proc_id];
//	port_ptr->su_proc_id = pst->su_proc_id;
	port_ptr->primitive_cmd = BICC_RELEASE_REQ;

	memcpy(&writePrim_union[pst->sp_proc_id].rel_req, ptr, sizeof(BiccRel_Req));
	return 1;
}

int BICC_rel_rsp(Pst *pst, BiccRel_Rsp * ptr)
{
	BICC_Port_struct *port_ptr;
	if(pst->sp_proc_id == 0)
		if(!getPidByCic(&pst->sp_proc_id, pst->cg_id, pst->cic))
			return 0;
	port_ptr = &Bicc_Data.port_data[pst->sp_proc_id];
//	port_ptr->su_proc_id = pst->su_proc_id;
	port_ptr->primitive_cmd = BICC_RELEASE_RSP;

	memcpy(&writePrim_union[pst->sp_proc_id].rel_rsp, ptr, sizeof(BiccRel_Rsp));
	return 1;
}

int BICC_alert_req(Pst *pst, BiccAlert_Req *ptr)
{
	BICC_Port_struct *port_ptr;
	if(pst->sp_proc_id == 0)
		if(!getPidByCic(&pst->sp_proc_id, pst->cg_id, pst->cic))
			return 0;
	port_ptr = &Bicc_Data.port_data[pst->sp_proc_id];
//	port_ptr->su_proc_id = pst->su_proc_id;
	port_ptr->primitive_cmd = BICC_ALERT_REQ;
	memcpy(&writePrim_union[pst->sp_proc_id].alert_req, ptr, sizeof(BiccAlert_Req));
	bicc_cpci_proc(pst->sp_proc_id);
	return 1;
}

int BICC_info_req(Pst *pst, BiccInfo_Req *ptr)
{
	BICC_Port_struct *port_ptr;
	if(pst->sp_proc_id == 0)
		if(!getPidByCic(&pst->sp_proc_id, pst->cg_id, pst->cic))
			return 0;
	port_ptr = &Bicc_Data.port_data[pst->sp_proc_id];
//	port_ptr->su_proc_id = pst->su_proc_id;
	port_ptr->primitive_cmd = BICC_INFO_REQ;
	memcpy(&writePrim_union[pst->sp_proc_id].info_req, ptr, sizeof(BiccInfo_Req));
	return 1;
}

int BICC_prog_req(Pst *pst, BiccCpg_Req *ptr)
{
	BICC_Port_struct *port_ptr;
	if(pst->sp_proc_id == 0)
		if(!getPidByCic(&pst->sp_proc_id, pst->cg_id, pst->cic))
			return 0;
	port_ptr = &Bicc_Data.port_data[pst->sp_proc_id];
//	port_ptr->su_proc_id = pst->su_proc_id;
	port_ptr->primitive_cmd = BICC_PROG_REQ;
	memcpy(&writePrim_union[pst->sp_proc_id].cpg_req, ptr, sizeof(BiccCpg_Req));
	return 1;	
}

int BICC_block_req(Pst *pst, BiccCgb_Req *ptr)
{		
	BICC_Port_struct *port_ptr;
    if(pst->sp_proc_id == 0)
    	if(!getPidByCic(&pst->sp_proc_id, pst->cg_id, pst->cic))
        	return 0;
    port_ptr = &Bicc_Data.port_data[pst->sp_proc_id];
    port_ptr->su_proc_id = pst->su_proc_id;
    port_ptr->primitive_cmd = BICC_BLOCK_REQ;
    memcpy(&writePrim_union[pst->sp_proc_id].cgb_req, ptr, sizeof(BiccCgb_Req));

    return 1;


}

int BICC_unblock_req(Pst *pst,  BiccCgb_Req *ptr)
{
    BICC_Port_struct *port_ptr;
    if(pst->sp_proc_id == 0)
    	if(!getPidByCic(&pst->sp_proc_id, pst->cg_id, pst->cic))
        	return 0;
    port_ptr = &Bicc_Data.port_data[pst->sp_proc_id];
    port_ptr->su_proc_id = pst->su_proc_id;
    port_ptr->primitive_cmd = BICC_RESET_REQ;
    memcpy(&writePrim_union[pst->sp_proc_id].cgb_req, ptr, sizeof(BiccCgb_Req));

    return 1;



}

int BICC_resm_req(Pst *pst, BiccRes_Req * ptr)
{
	BICC_Port_struct *port_ptr;
	if(pst->sp_proc_id == 0)
		if(!getPidByCic(&pst->sp_proc_id, pst->cg_id, pst->cic))
			return 0;
	port_ptr = &Bicc_Data.port_data[pst->sp_proc_id];
//	port_ptr->su_proc_id = pst->su_proc_id;
	port_ptr->primitive_cmd = BICC_RESUME_REQ;

	memcpy(&writePrim_union[pst->sp_proc_id].res_req, ptr, sizeof(BiccRes_Req));
	return 1;
}

int BICC_apm_req(Pst *pst, BiccApm_Req * ptr)
{
	BICC_Port_struct *port_ptr;
	if(pst->sp_proc_id == 0)
		if(!getPidByCic(&pst->sp_proc_id, pst->cg_id, pst->cic))
			return 0;
	port_ptr = &Bicc_Data.port_data[pst->sp_proc_id];
//	port_ptr->su_proc_id = pst->su_proc_id;
	port_ptr->primitive_cmd = BICC_APM_REQ;

	memcpy(&writePrim_union[pst->sp_proc_id].apm_req, ptr, sizeof(BiccApm_Req));
	bicc_send_apm(pst->sp_proc_id);
	return 1;
}

int BICC_sus_req(Pst *pst, BiccSus_Req *ptr)
{
	BICC_Port_struct *port_ptr;
	if(pst->sp_proc_id == 0)
		if(!getPidByCic(&pst->sp_proc_id, pst->cg_id, pst->cic))
			return 0;
	port_ptr = &Bicc_Data.port_data[pst->sp_proc_id];
//	port_ptr->su_proc_id = pst->su_proc_id;
	port_ptr->primitive_cmd = BICC_SUSPEND_REQ;

	memcpy(&writePrim_union[pst->sp_proc_id].sus_req, ptr, sizeof(BiccSus_Req));
	return 1;
}


int BICC_reset_req(Pst *pst, BiccGrs_Req *ptr)
{	
	BICC_Port_struct *port_ptr;
        //if(pst->sp_proc_id == 0)
    if(!getPidByCic(&pst->sp_proc_id, pst->cg_id, pst->cic))
    	return 0;
    port_ptr = &Bicc_Data.port_data[pst->sp_proc_id];
    port_ptr->su_proc_id = pst->su_proc_id;
    if(ptr!=NULL)
    {
    	port_ptr->primitive_cmd = BICC_GROUP_RESET_REQ;
    	memcpy(&writePrim_union[pst->sp_proc_id].grs_req, ptr, sizeof(BiccGrs_Req));
    	bicc_cgrs_proc(pst->sp_proc_id);

    }
    else
     	port_ptr->primitive_cmd = BICC_RESET_REQ;

//	memcpy(&writePrim_union[pst->sp_proc_id].grs_req, ptr, sizeof(BiccGrs_Req));

    return 1;
	
}


int BICC_reset_rsp(Pst *pst, BiccGrs_Rsp *ptr)
{
	BICC_Port_struct *port_ptr;
	if(pst->sp_proc_id == 0)
		if(!getPidByCic(&pst->sp_proc_id, pst->cg_id, pst->cic))
			return 0;
	port_ptr = &Bicc_Data.port_data[pst->sp_proc_id];
//	port_ptr->su_proc_id = pst->su_proc_id;
	port_ptr->primitive_cmd = BICC_RESET_RSP;
	memcpy(&writePrim_union[pst->sp_proc_id].grs_rsp, ptr, sizeof(BiccGrs_Rsp));

	return 1;
}

void BICC_EMPTY_APM(ApmUser_struct *ptr)
{
	ptr->action.pres = 0;
	ptr->bnc_id.pres = 0;
	ptr->bnc_chr.pres = 0;
	ptr->bc_info.pres = 0;
	ptr->bc_tunnel.pres = 0;
	ptr->signal_type.pres = 0;
	ptr->duration.pres = 0;
}

/* This function clear optional parameter flag */
void BICC_EMPTY_OPTPAR(void *ptr, u8 prim)
{
	if((prim & 0xf0) == 0x00)	//request
	{
		switch(prim)
		{
			case BICC_SETUP_REQ:
				((BiccSetup_Req *)ptr)->app.pres = 0;
				BICC_EMPTY_APM(&((BiccSetup_Req *)ptr)->app.apm_info);
				((BiccSetup_Req *)ptr)->callingPtyNum.pres = 0;
				((BiccSetup_Req *)ptr)->collectCallReq.pres = 0;
				((BiccSetup_Req *)ptr)->confTreat.pres = 0;
				((BiccSetup_Req *)ptr)->correlationId.pres = 0;
				((BiccSetup_Req *)ptr)->origCalledNum.pres = 0;
				((BiccSetup_Req *)ptr)->redirgNum.pres = 0;
				((BiccSetup_Req *)ptr)->scfId.pres = 0;
				((BiccSetup_Req *)ptr)->utuInd.pres = 0;
				((BiccSetup_Req *)ptr)->utuInfo.pres = 0;
				break;
			case BICC_ALERT_REQ:
				((BiccAlert_Req *)ptr)->app.pres = 0;
				BICC_EMPTY_APM(&((BiccAlert_Req *)ptr)->app.apm_info);
				((BiccAlert_Req *)ptr)->cause.pres = 0;
				((BiccAlert_Req *)ptr)->confTreat.pres = 0;
				((BiccAlert_Req *)ptr)->utuInd.pres = 0;
				((BiccAlert_Req *)ptr)->utuInfo.pres = 0;
				break;
			case BICC_APM_REQ:
				((BiccApm_Req *)ptr)->app.pres = 0;
				BICC_EMPTY_APM(&((BiccApm_Req *)ptr)->app.apm_info);
				break;
			case BICC_PROG_REQ:
				((BiccCpg_Req *)ptr)->app.pres = 0;
				BICC_EMPTY_APM(&((BiccCpg_Req *)ptr)->app.apm_info);
				((BiccCpg_Req *)ptr)->backCall.pres = 0;
				((BiccCpg_Req *)ptr)->cause.pres = 0;
				((BiccCpg_Req *)ptr)->confTreat.pres = 0;
				((BiccCpg_Req *)ptr)->connNum.pres = 0;
				((BiccCpg_Req *)ptr)->utuInd.pres = 0;
				((BiccCpg_Req *)ptr)->utuInfo.pres = 0;
				break;
			case BICC_RELEASE_REQ:
				((BiccRel_Req *)ptr)->utuInd.pres = 0;
				((BiccRel_Req *)ptr)->utuInfo.pres = 0;
				break;
			default:
				break;
		}
	}
	else if((prim & 0xf0) == 0x80)	//response
	{
		switch(prim)
		{
			case BICC_SETUP_RSP:
				((BiccSetup_Rsp *)ptr)->app.pres = 0;
				BICC_EMPTY_APM(&((BiccSetup_Rsp *)ptr)->app.apm_info);
				((BiccSetup_Rsp *)ptr)->backCall.pres = 0;
				((BiccSetup_Rsp *)ptr)->confTreat.pres = 0;
				((BiccSetup_Rsp *)ptr)->connNum.pres = 0;
				((BiccSetup_Rsp *)ptr)->utuInd.pres = 0;
				((BiccSetup_Rsp *)ptr)->utuInfo.pres = 0;
				break;
			case BICC_RELEASE_RSP:
				((BiccRel_Rsp *)ptr)->cause.pres = 0;
				break;
			default:
				break;
		}
	}
}

void bicc_timer_init(int interval_ms)
{
	BiccTimer_struct *timer_ptr = &Timer_Data;
	timer_ptr ->t1 = BICC_T1 * 1000 / interval_ms;
	timer_ptr ->t5 = BICC_T5 * 1000 / interval_ms;
	timer_ptr ->t7 = BICC_T7 * 1000 / interval_ms;
	timer_ptr ->t8 = BICC_T8 * 1000 / interval_ms;
	timer_ptr ->t9 = BICC_T9 * 1000 / interval_ms;
	timer_ptr ->t12 = BICC_T12 * 1000 / interval_ms;
	timer_ptr ->t13 = BICC_T13 * 1000 / interval_ms;
	timer_ptr ->t14 = BICC_T14 * 1000 / interval_ms;
	timer_ptr ->t15 = BICC_T15 * 1000 / interval_ms;
	timer_ptr ->t16 = BICC_T16 * 1000 / interval_ms;
	timer_ptr ->t17 = BICC_T17 * 1000 / interval_ms;
	timer_ptr ->t18 = BICC_T18 * 1000 / interval_ms;
	timer_ptr ->t19 = BICC_T19 * 1000 / interval_ms;
	timer_ptr ->t20 = BICC_T20 * 1000 / interval_ms;
	timer_ptr ->t21 = BICC_T21 * 1000 / interval_ms;
	timer_ptr ->t22 = BICC_T22 * 1000 / interval_ms;
	timer_ptr ->t23 = BICC_T23 * 1000 / interval_ms;
	timer_ptr ->t28 = BICC_T28 * 1000 / interval_ms;
	timer_ptr ->t33 = BICC_T33 * 1000 / interval_ms;
	timer_ptr ->t34 = BICC_T34 * 1000 / interval_ms;
	timer_ptr ->t35 = BICC_T35 * 1000 / interval_ms;
	timer_ptr ->t40 = BICC_T40 * 1000 / interval_ms;
	timer_ptr ->t41 = BICC_T41 * 1000 / interval_ms;
	timer_ptr ->t42 = BICC_T42 * 1000 / interval_ms;
	timer_ptr ->t43 = BICC_T43 * 1000 / interval_ms;
	timer_ptr->user_t10 = BICC_USER_T10 * 1000 / interval_ms;
	
		
}


void BICC_init(int interval_ms,int local_id)
{
	u32	stack_size;
	printf("Start BICC module init......\n");
    //memset(&BiccResource, 0, sizeof(BICC_Resource_pond));
    memset(&Bicc_Data, 0, sizeof(BiccData_struct));
    bicc_timer_init(interval_ms);
	stack_size = sizeof(Bicc_Data);
    bicc_debug_init();
	local_platid = local_id;
	printf("BICC module init complete! Stack size: %ld bytes\n", stack_size);
}


void BICC_cpc_proc(u32 pid)
{
	BICC_Port_struct *port_ptr = &Bicc_Data.port_data[pid];
	if(port_ptr->cic_state.call_state == BICC_INCOMING)
		bicc_cpci_proc(pid);
	else if(port_ptr->cic_state.call_state == BICC_OUTGOING)
		bicc_cpco_proc(pid);
	else
	{
//		if((port_ptr->fsm_state.cgrs_state == 0)&&(port_ptr->primitive_cmd == 0))
//			memset(&Bicc_Data.port_data[pid],0,sizeof(BICC_Port_struct));
	}
}


void BICC_csc_proc(u32 pid)
{
	bicc_mgbs_proc(pid);
	bicc_mgbr_proc(pid);
	bicc_crs_proc(pid);
	bicc_crr_proc(pid);
	bicc_cgrs_proc(pid);
	bicc_cgrr_proc(pid);
//	bicc_blr_proc(pid);
//	bicc_bls_proc(pid);
}

void BICC_timer()
{
	u32			i, j;
	u32			offset, pid;
	const pal_circuit_struct *pcircuit = NULL;
	const pal_cg_struct		*pcg = NULL;
	for(i = 0; i < 64; i++)
	{
		if(BICC_mdsc_proc() == 0)
			break;
	}
	for(i = 0; i < PAL_MAX_CIRCUIT; i++)
	{
		pcircuit = pal_circuit_ptr(i);
	
		if((pcircuit !=NULL) && (pcircuit->enable))
		{
			if((pcg = pal_cg_ptr(pcircuit->cg_id)) && (pcg->attrib.protocol == PROTO_BICC))
			{
				offset = BICC_CIRCUIT_CIC * i;
				for(j = 0; j < BICC_CIRCUIT_CIC; j++)
				{	
					pid = offset + j;
					BICC_cpc_proc(pid);
					BICC_csc_proc(pid);
				}
			}
		}
	}
	bicc_debug_timer();
	
}

