/***********************************************************
Copyright (C), LGC Wireless.
File Name:		isdn_ie.c
Description:	ISDN information elements
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_msg.h"
#include "./include/isdn_ie.h"


u16 find_ie_para(u8 *start, u8 ie_type, u8 **target)
/*
*/
{
	u16 offset = 0;
	u8 ie_ind, len, ie_num = 0;
	
	while ((offset < IE_MAX_LEN) && (ie_num < IE_COUNT))
	{
		ie_num++;
		ie_ind = (((*start) >> 7) & 0x01);
		if (ie_ind == 1)
			len = 1;
		else
			len = (*(start + 1)) + 2;
			
		if ((*start) == ie_type)
		{
			(*target) = start;
			return len;
		}
		else
		{
			if (ie_ind == 1)
			{
				offset++;
				start++;
			}	
			else
			{
				offset += len;
				start += len;
			}
		}
	}
	
	return 0;
}

u8 IA5_to_Hex(u8 digit)
{
	if ((digit >= '0') && (digit <= '9'))
		return (digit - '0');
	else if ((digit == '*') || (digit == 0x3A))
		return 0x0B;
	else if ((digit == '#') || (digit == 0x3B))
		return 0x0C;
	else
		return 0xFF;
}

u8 Hex_to_IA5(u8 digit)
{
	if (digit == 0x0B)
		return ('*');
	else if (digit == 0x0C)
		return ('#');
	else if (digit == 0x0A)
		return ('0');
	else if (digit < 0x0A)
		return ('0' + digit);
	else
		return 0xFF;
}


u8 itu_encode_br_cap(u8 *dst, BrCap *src)
{
	u8 offset = 0;
	dst[offset++] = 0x80 | (src->code_stan << 5) | (src->tran_cap);	
	dst[offset++] = 0x80 | (src->b4.tran_mode << 5) | (src->b4.tran_rate);

	if((src->b4.tran_rate & 0x1F) == 0x18)	//Multirate	octet4 and 4.1
	{
		dst[offset++] = 0x80 | (src->b4.rate_mul);
	}
	
	if(src->ext_flag & 0x01)	//octet5
	{
		dst[offset++] = (src->b5.has_ext_a << 7) | (0x1 << 5) | (src->b5.usr_layer1);
		if(!src->b5.has_ext_a)	//octet5 and 5a
		{
			dst[offset++] = (src->b5.has_ext_b << 7) | (src->b5.syn_asy << 6) | 
				(src->b5.neg << 5) | (src->b5.usr_rate);
			
			if(!src->b5.has_ext_b)	//5b
			{
				if((src->b5.usr_layer1 & 0x1F) == 0x1)
				{
					dst[offset++] = (src->b5.has_ext_c << 7) | (src->b5.inter_rate << 5) | 
						(src->b5.nic_tx << 4) | (src->b5.nic_rx << 3) | 
						(src->b5.ctl_tx << 2) | (src->b5.ctl_rx <<1);
				}
				else if((src->b5.usr_layer1 & 0x1F) == 0x8)
				{
					dst[offset++] = (src->b5.has_ext_c << 7) | (src->b5.hdr << 6) | 
						(src->b5.mul_fra << 5) | (src->b5.mode << 4) | 
						(src->b5.lli_neg << 3) | (src->b5.assign << 2) | 
						(src->b5.inband << 1);
				}
				
				if(!src->b5.has_ext_c)	//5c
				{
					dst[offset++] = (src->b5.has_ext_d << 7) | (src->b5.stop_bit << 5) | 
						(src->b5.data_bit << 3) | (src->b5.par);

					if(!src->b5.has_ext_d)	//5d
					{
						dst[offset++] = 0x80 | (src->b5.du_mode << 6) | (src->b5.mod_type);
					}
				}
			}
		}
	}
	
	if(src->ext_flag & 0x02)	//octet6
	{
		dst[offset++] = 0x80 | (0x2 << 5) | (src->usr_layer2);
	}
	
	if(src->ext_flag & 0x04)	//octet7
	{
		dst[offset++] = 0x80 | (0x3 << 5) | (src->usr_layer3);
	}
	
	return offset;
}

int itu_decode_br_cap(BrCap *dst, u8 *src, u8 len)	//
{
	u8 offset = 0;
	dst->pres = 1;
	if((len < 2) || (len > 13))
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
	
	if(!(src[offset] & 0x80))
	{
		printf("encode ie err!\n");
		return ISDN_CM_FAILED;
	}
	dst->code_stan = ((src[offset] & 0x60) >> 5);
	dst->tran_cap = (src[offset++] & 0x1F);
	
	dst->b4.tran_mode = ((src[offset] & 0x60) >> 5);
	dst->b4.tran_rate = (src[offset++] & 0x1F);

	if((dst->b4.tran_rate & 0x1F) == 0x18)	//Multirate	with 4.1
	{
		dst->b4.rate_mul = (src[offset++] & 0x7F);
	}

	if(offset < len)	//octet at offside
	{
		if(((src[offset] & 0x60) >> 5) == 0x1)		//octet 5
		{
			dst->ext_flag |= 0x01;
			dst->b5.has_ext_a = ((src[offset] & 0x80) >> 7);
			dst->b5.usr_layer1 = (src[offset++] & 0x1F);
			if(!dst->b5.has_ext_a)		//with 5a
			{
				dst->b5.has_ext_b = ((src[offset] & 0x80) >> 7);
				dst->b5.syn_asy = ((src[offset] & 0x40) >> 6);
				dst->b5.neg = ((src[offset] & 0x20) >> 5);
				dst->b5.usr_rate = (src[offset++] & 0x1F);
				if(!dst->b5.has_ext_b)	//with 5b
				{
					dst->b5.has_ext_c = ((src[offset] & 0x80) >> 7);
					if((dst->b5.usr_layer1 & 0x1F) == 0x1)	//V.110/X.30
					{
						dst->b5.inter_rate = ((src[offset] & 0x60) >> 5);
						dst->b5.nic_tx = ((src[offset] & 0x10) >> 4);
						dst->b5.nic_rx = ((src[offset] & 0x08) >> 3);
						dst->b5.ctl_tx = ((src[offset] & 0x04) >> 2);
						dst->b5.ctl_rx = ((src[offset++] & 0x02) >> 1);
					}
					else if((dst->b5.usr_layer1 & 0x1F) == 0x8)	//V.120
					{
						dst->b5.hdr = ((src[offset] & 0x40) >> 6);
						dst->b5.mul_fra = ((src[offset] & 0x20) >> 5);
						dst->b5.mode = ((src[offset] & 0x10) >> 4);
						dst->b5.lli_neg = ((src[offset] & 0x08) >> 3);
						dst->b5.assign = ((src[offset] & 0x04) >> 2);
						dst->b5.inband =((src[offset++] & 0x02) >> 1);
					}

					if(!dst->b5.has_ext_c)		//with 5c
					{
						dst->b5.has_ext_d = ((src[offset] & 0x80) >> 7);
						dst->b5.stop_bit = ((src[offset] & 0x60) >> 5);
						dst->b5.data_bit = ((src[offset] & 0x18) >> 3);
						dst->b5.par = (src[offset++] & 0x07);

						if(!dst->b5.has_ext_d)	//with 5d
						{
							dst->b5.du_mode = ((src[offset] & 0x40) >> 6);
							dst->b5.mod_type =(src[offset++] & 0x3F);
						}
					}
				}
			}
		}
	}
	if(offset < len)	//octet at offside
	{
		if(((src[offset] & 0x60) >> 5) == 0x2)		//octet 6
		{
			dst->ext_flag |= 0x02;
			dst->usr_layer2 = (src[offset++] & 0x1F);
		}
	}
	if(offset < len)	//octet at offside
	{
		if(((src[offset] & 0x60) >> 5) == 0x3)		//octet 7
		{
			dst->ext_flag |= 0x04;
			dst->usr_layer3 = (src[offset] & 0x1F);
		}
	}
	
	return ISDN_CM_OK;
}

u8 isdn_encode_br_cap(u8 *dst, BrCap *src)
{
	u8 offset = 0;
	dst[offset++] = 0x80 | (src->code_stan << 5) | (src->tran_cap);
	dst[offset++] = 0x80 | (src->b4.tran_mode << 5) | (src->b4.tran_rate);

	if((src->b4.tran_rate & 0x1F) == 0x18)	//Multirate	octet4 and 4.1
	{
		dst[offset++] = 0x80 | (src->b4.rate_mul);
	}
	
	if(src->ext_flag & 0x01)	//octet5
	{
		dst[offset++] = (src->b5.has_ext_a << 7) | (0x1 << 5) | (src->b5.usr_layer1);
		if((!src->b5.has_ext_a) && (src->b5.usr_layer1 == 0x1))	//with 5a when V.110/X.30
		{
			dst[offset++] = 0x80 | (src->b5.usr_rate);
		}
	}
	
	return offset;
}

int isdn_decode_br_cap(BrCap *dst, u8 *src, u8 len)	//
{
	u8 offset = 0;
	dst->pres = 1;
	if((len < 2) || (len > 5))
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
	
	if(!(src[offset] & 0x80))
	{
		printf("encode ie err!\n");
		return ISDN_CM_FAILED;
	}
	dst->code_stan = ((src[offset] & 0x60) >> 5);
	dst->tran_cap = (src[offset++] & 0x1F);
	
	dst->b4.tran_mode = ((src[offset] & 0x60) >> 5);
	dst->b4.tran_rate = (src[offset++] & 0x1F);

	if((dst->b4.tran_rate & 0x1F) == 0x18)	//Multirate	with 4.1
	{
		dst->b4.rate_mul = (src[offset++] & 0x7F);
	}

	if(offset < len)	//octet at offside
	{
		if(((src[offset] & 0x60) >> 5) == 0x1)		//octet 5
		{
			dst->ext_flag |= 0x01;
			dst->b5.has_ext_a = ((src[offset] & 0x80) >> 7);
			dst->b5.usr_layer1 = (src[offset++] & 0x1F);
			if((!dst->b5.has_ext_a) && (dst->b5.usr_layer1 == 0x1))	//with 5a when V.110/X.30
			{
				dst->b5.syn_asy = ((src[offset] & 0x40) >> 6);
				dst->b5.neg = ((src[offset] & 0x20) >> 5);
				dst->b5.usr_rate = (src[offset++] & 0x1F);
			}
		}
	}
	
	return ISDN_CM_OK;
}

u8 isdn_encode_cause(u8 *dst, CauseStr *src)
{
	u8 offset = 0;
	int i = 0;
	dst[offset++] = (src->b3.has_ext_a << 7) | (src->b3.code_stan << 5) | (src->b3.loc);
	if(!src->b3.has_ext_a)		//with 3a
	{
		dst[offset++] = 0x80 | (src->b3.rec);
	}
	dst[offset++] = 0x80 | (src->cause_val);
	if(src->ext_flag & 0x01)	//octet 5
	{
		for(i=0; i<src->dia_num; i++)
		{
			dst[offset++] = src->dia[i].attrib_num;
			dst[offset++] = (src->dia[i].has_ext_b << 7) | (src->dia[i].rej_attrib);
			if(!src->dia[i].has_ext_b)	//with 5b
			{
				dst[offset++] = 0x80 | (src->dia[i].avail_attrib);
			}
		}
	}
	
	return offset;
}

int isdn_decode_cause(CauseStr *dst, u8 *src, u8 len)
{
	u8 offset = 0;
	int i = 0;
	dst->pres = 1;
	if((len < 2) || (len > 30))
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
	
	dst->b3.has_ext_a = ((src[offset] & 0x80) >> 7);
	dst->b3.code_stan = ((src[offset] & 0x60) >> 5);
	dst->b3.loc = (src[offset++] & 0x0F);
	if(!dst->b3.has_ext_a)	//with 3a
	{
		dst->b3.rec = (src[offset++] & 0x7F);
	}
	
	if(!(src[offset] & 0x80))
	{
		printf("encode ie err!\n");
		return ISDN_CM_FAILED;
	}
	dst->cause_val = (src[offset++] & 0x7F);
	if(offset < len)
	{
		dst->ext_flag |= 0x01;
		while(offset < len && i < 8)
		{
//			dst->dia[i].has_ext_a = ((src[offset] & 0x80) >> 7);
			dst->dia[i].attrib_num = (src[offset++] & 0x7F);
			dst->dia[i].has_ext_b = ((src[offset] & 0x80) >> 7);
			dst->dia[i].rej_attrib = (src[offset++] & 0x7F);
			if(!dst->dia[i].has_ext_b)
				dst->dia[i].avail_attrib = (src[offset++] & 0x7F);
			i++;
		}
		dst->dia_num = i;
	}

	return ISDN_CM_OK;
}

u8 isdn_encode_call_id(u8 *dst, CallId *src)
{
	u8 offset = 0;
	
	return offset;
}

int isdn_decode_call_id(CallId *dst, u8 *src, u8 len)
{
//	u8 offset = 0;
	dst->pres = 1;

	return ISDN_CM_OK;
}

u8 isdn_encode_call_stat(u8 *dst, CallStat *src)
{
	u8 offset = 0;
	dst[offset++] = (src->code_stan << 6) | (src->stat_val & 0x3F);
	
	return offset;
}

int isdn_decode_call_stat(CallStat *dst, u8 *src, u8 len)
{
	u8 offset = 0;
	dst->pres = 1;
	if(len != 1)
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
	dst->code_stan = ((src[offset] & 0xC0) >> 6);
	dst->stat_val = (src[offset++] & 0x3F);

	return ISDN_CM_OK;
}

u8 qsig_encode_chnl_id(u8 *dst, ChnlId *src)
{
	u8 offset = 0;
	dst[offset++] = 0x80 | (src->b3.pref_excl << 3) | (src->b3.chnl_ind << 2) | (src->b3.info_chnl_sel);

	if(src->b3.has_chnl)
	{
		dst[offset++] = 0x80 | (src->b3.code_stan << 5) | (src->b3.num_map << 4) | (src->b3.chnl_type);	//with 3.2
		dst[offset++] = 0x80 | (src->b3.chnl_num & 0x1F);	//with 3.3
	}
	
	return offset;
}

int qsig_decode_chnl_id(ChnlId *dst, u8 *src, u8 len)
{
	int i;
	u8 offset = 0;
	dst->pres = 1;
	if((len < 1) || (len > 32))
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
	
	if(!(src[offset] & 0x80))
	{
		printf("encode ie err!\n");
		return ISDN_CM_FAILED;
	}
	dst->b3.int_id_pre = ((src[offset] & 0x40) >> 6);
	dst->b3.int_type = ((src[offset] & 0x20) >> 5);
	dst->b3.pref_excl = ((src[offset] & 0x08) >> 3);
	dst->b3.chnl_ind = ((src[offset] & 0x04) >> 2);
	dst->b3.info_chnl_sel = (src[offset++] & 0x03);
	if(dst->b3.int_id_pre || (!dst->b3.int_type))	//with 3.1 err
	{
		printf("encode ie err!\n");
		return ISDN_CM_FAILED;
	}
	if((dst->b3.int_type & 0x1) && (offset < len))		//with 3.2 and 3.3
	{
		dst->b3.has_chnl = 1;
		dst->b3.code_stan = ((src[offset] & 0x60) >> 5);
		dst->b3.num_map = ((src[offset] & 0x10) >> 4);
		dst->b3.chnl_type = (src[offset++] & 0x0F);
		if(dst->b3.num_map)
		{
			dst->b3.num_map = 0;
			switch(len - offset)
			{
				case 4:	//E1
					for(i = 0; i < 4; i++)
					{
						if(src[offset])
						{
							switch(src[offset])
							{
								case 0x01:
									dst->b3.chnl_num = (3 - i) * 8 + 0;
									break;
								case 0x02:
									dst->b3.chnl_num = (3 - i) * 8 + 1;
									break;
								case 0x04:
									dst->b3.chnl_num = (3 - i) * 8 + 2;
									break;
								case 0x08:
									dst->b3.chnl_num = (3 - i) * 8 + 3;
									break;
								case 0x10:
									dst->b3.chnl_num = (3 - i) * 8 + 4;
									break;
								case 0x20:
									dst->b3.chnl_num = (3 - i) * 8 + 5;
									break;
								case 0x40:
									dst->b3.chnl_num = (3 - i) * 8 + 6;
									break;
								case 0x80:
									dst->b3.chnl_num = (3 - i) * 8 + 7;
									break;
								default:
									break;
							}
						}
						offset++;
					}
					break;
				case 3:	//T1
					for(i = 0; i < 3; i++)
					{
						if(src[offset])
						{
							switch(src[offset])
							{
								case 0x01:
									dst->b3.chnl_num = (2 - i) * 8 + 0;
									break;
								case 0x02:
									dst->b3.chnl_num = (2 - i) * 8 + 1;
									break;
								case 0x04:
									dst->b3.chnl_num = (2 - i) * 8 + 2;
									break;
								case 0x08:
									dst->b3.chnl_num = (2 - i) * 8 + 3;
									break;
								case 0x10:
									dst->b3.chnl_num = (2 - i) * 8 + 4;
									break;
								case 0x20:
									dst->b3.chnl_num = (2 - i) * 8 + 5;
									break;
								case 0x40:
									dst->b3.chnl_num = (2 - i) * 8 + 6;
									break;
								case 0x80:
									dst->b3.chnl_num = (2 - i) * 8 + 7;
									break;
								default:
									break;
							}
						}
						offset++;
					}
					break;
				case 1:
					break;
				default:
					break;
			}			
		}
		else
			dst->b3.chnl_num = (src[offset++] & 0x1F);
	}

	return ISDN_CM_OK;
}

u8 isdn_encode_chnl_id(u8 *dst, ChnlId *src)
{
	u8 offset = 0;
	dst[offset++] = 0x80 | (src->b3.int_id_pre << 6) | (src->b3.int_type << 5) | 
		(src->b3.pref_excl << 3) | (src->b3.chnl_ind << 2) | (src->b3.info_chnl_sel);
	if((src->b3.int_id_pre & 0x1) == 1)	//with 3.1
	{
		if((src->b3.int_type & 0x1) && (src->b3.has_chnl))	//with3.1, 3.2 and 3.3
		{
			dst[offset++] = 0x80 | (src->b3.int_id);
			dst[offset++] = 0x80 | (src->b3.code_stan << 5) | (src->b3.num_map << 4) | 
				(src->b3.chnl_type);
			dst[offset++] = 0x80 | (src->b3.chnl_num & 0x1F);
		}
		else		//without 3.2 and 3.3 but with 3.1
		{
			dst[offset++] = 0x80 | (src->b3.int_id);
		}
	}
	else		//without 3.1
	{
		if((src->b3.int_type & 0x1) && (src->b3.has_chnl))	//with 3.2 and 3.3 but without 3.1
		{
			dst[offset++] = 0x80 | (src->b3.code_stan << 5) | (src->b3.num_map << 4) | 
				(src->b3.chnl_type);
			dst[offset++] = 0x80 | (src->b3.chnl_num & 0x1F);
		}
	}
	
	return offset;
}

int isdn_decode_chnl_id(ChnlId *dst, u8 *src, u8 len)
{
	int i;
	u8 offset = 0;
	dst->pres = 1;
	if((len < 1) || (len > 32))
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
	
	if(!(src[offset] & 0x80))
	{
		printf("encode ie err!\n");
		return ISDN_CM_FAILED;
	}
	dst->b3.int_id_pre = ((src[offset] & 0x40) >> 6);
	dst->b3.int_type = ((src[offset] & 0x20) >> 5);
	dst->b3.pref_excl = ((src[offset] & 0x08) >> 3);
	dst->b3.chnl_ind = ((src[offset] & 0x04) >> 2);
	dst->b3.info_chnl_sel = (src[offset++] & 0x03);
	if((dst->b3.int_id_pre & 0x1) == 0x1)	//with 3.1
	{
		dst->b3.int_id = (src[offset++] & 0x7F);
	}
	if((dst->b3.int_type & 0x1) && (offset < len))		//with 3.2 and 3.3
	{
		dst->b3.has_chnl = 1;
		dst->b3.code_stan = ((src[offset] & 0x60) >> 5);
		dst->b3.num_map = ((src[offset] & 0x10) >> 4);
		dst->b3.chnl_type = (src[offset++] & 0x0F);
		if(dst->b3.num_map)
		{
			dst->b3.num_map = 0;
			switch(len - offset)
			{
				case 4:	//E1
					for(i = 0; i < 4; i++)
					{
						if(src[offset])
						{
							switch(src[offset])
							{
								case 0x01:
									dst->b3.chnl_num = (3 - i) * 8 + 0;
									break;
								case 0x02:
									dst->b3.chnl_num = (3 - i) * 8 + 1;
									break;
								case 0x04:
									dst->b3.chnl_num = (3 - i) * 8 + 2;
									break;
								case 0x08:
									dst->b3.chnl_num = (3 - i) * 8 + 3;
									break;
								case 0x10:
									dst->b3.chnl_num = (3 - i) * 8 + 4;
									break;
								case 0x20:
									dst->b3.chnl_num = (3 - i) * 8 + 5;
									break;
								case 0x40:
									dst->b3.chnl_num = (3 - i) * 8 + 6;
									break;
								case 0x80:
									dst->b3.chnl_num = (3 - i) * 8 + 7;
									break;
								default:
									break;
							}
						}
						offset++;
					}
					break;
				case 3:	//T1
					for(i = 0; i < 3; i++)
					{
						if(src[offset])
						{
							switch(src[offset])
							{
								case 0x01:
									dst->b3.chnl_num = (2 - i) * 8 + 0;
									break;
								case 0x02:
									dst->b3.chnl_num = (2 - i) * 8 + 1;
									break;
								case 0x04:
									dst->b3.chnl_num = (2 - i) * 8 + 2;
									break;
								case 0x08:
									dst->b3.chnl_num = (2 - i) * 8 + 3;
									break;
								case 0x10:
									dst->b3.chnl_num = (2 - i) * 8 + 4;
									break;
								case 0x20:
									dst->b3.chnl_num = (2 - i) * 8 + 5;
									break;
								case 0x40:
									dst->b3.chnl_num = (2 - i) * 8 + 6;
									break;
								case 0x80:
									dst->b3.chnl_num = (2 - i) * 8 + 7;
									break;
								default:
									break;
							}
						}
						offset++;
					}
					break;
				case 1:
					break;
				default:
					break;
			}			
		}
		else
			dst->b3.chnl_num = (src[offset++] & 0x1F);
	}

	return ISDN_CM_OK;
}

u8 isdn_encode_prg_ind(u8 *dst, PrgInd *src)
{
	u8 offset = 0;
	dst[offset++] = 0x80 | (src->code_stan << 5) | (src->loc);
	dst[offset++] = 0x80 | (src->prg_descr & 0x7F);

	return offset;
}

int isdn_decode_prg_ind(PrgInd *dst, u8 *src, u8 len)
{
	u8 offset = 0;
	dst->pres = 1;
	if(len != 2)
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
	
	if(!(src[offset] & 0x80))
	{
		printf("encode ie err!\n");
		return ISDN_CM_FAILED;
	}
	dst->code_stan = ((src[offset] & 0x60) >> 5);
	dst->loc = (src[offset++] & 0x0F);
	
	if(!(src[offset] & 0x80))
	{
		printf("encode ie err!\n");
		return ISDN_CM_FAILED;
	}
	dst->prg_descr = (src[offset++] & 0x7F);

	return ISDN_CM_OK;
}

u8 ansi_encode_ntsp_fac(u8 *dst, NtSpFac *src)
{
	u8 offset = 0;
	dst[offset++] = src->b3.len_net_id;
	if((src->b3.len_net_id) != 0)	//with 3.1 and 3.2
	{
		dst[offset++] = 0x80 | (src->b3.net_id_type << 4) | (src->b3.net_id_plan);
		dst[offset++] = 0x80 | (src->b3.net_id);
	}
	dst[offset++] = 0xE0 | (src->fac_val);
	dst[offset++] = 0x80 | (src->ser_par);

	return offset;
}

int ansi_decode_ntsp_fac(NtSpFac *dst, u8 *src, u8 len)
{
	u8 offset = 0;
	dst->pres = 1;
	if(len < 2)
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}

	dst->b3.len_net_id = (src[offset++] & 0xFF);
	if((dst->b3.len_net_id) != 0)	//with 3.1 and 3.2
	{
		dst->b3.net_id_type = ((src[offset] & 0x70) >> 4);
		dst->b3.net_id_plan = (src[offset++] & 0x0F);

		dst->b3.net_id = (src[offset++] & 0x7F);
	}
	dst->fac_val = (src[offset++] & 0x1F);
	dst->ser_par = (src[offset++] & 0x7F);

	return ISDN_CM_OK;
}

u8 isdn_encode_ntsp_fac(u8 *dst, NtSpFac *src)
{
	u8 offset = 0;
	dst[offset++] = src->b3.len_net_id;
	if((src->b3.len_net_id) != 0)	//with 3.1 and 3.2
	{
		dst[offset++] = 0x80 | (src->b3.net_id_type << 4) | (src->b3.net_id_plan);
		dst[offset++] = 0x80 | (src->b3.net_id);
	}
	dst[offset++] = src->spec;

	return offset;
}

int isdn_decode_ntsp_fac(NtSpFac *dst, u8 *src, u8 len)
{
	u8 offset = 0;
	dst->pres = 1;
	if(len < 2)
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}

	dst->b3.len_net_id = (src[offset++] & 0xFF);
	if((dst->b3.len_net_id) != 0)	//with 3.1 and 3.2
	{
		dst->b3.net_id_type = ((src[offset] & 0x70) >> 4);
		dst->b3.net_id_plan = (src[offset++] & 0x0F);

		dst->b3.net_id = (src[offset++] & 0x7F);
	}
	dst->spec = (src[offset++] & 0xFF);

	return ISDN_CM_OK;
}

u8 ansi_encode_notify_ind(u8 *dst, NotifyInd *src)	//TODO
{
	u8 offset = 0;
	dst[offset++] = 0x80 | (src->notify_descr & 0x7F);

	return offset;
}

int ansi_decode_notify_ind(NotifyInd *dst, u8 *src, u8 len)	//TODO
{
	dst->pres = 1;
	if(len != 1)
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}

	if(!(src[0] & 0x80))
	{
		printf("encode ie err!\n");
		return ISDN_CM_FAILED;
	}
	dst->notify_descr = (src[0] & 0x7F);

	return ISDN_CM_OK;
}

u8 isdn_encode_notify_ind(u8 *dst, NotifyInd *src)
{
	u8 offset = 0;
	dst[offset++] = 0x80 | (src->notify_descr & 0x7F);

	return offset;
}

int isdn_decode_notify_ind(NotifyInd *dst, u8 *src, u8 len)
{
	dst->pres = 1;
	if(len != 1)
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}

	if(!(src[0] & 0x80))
	{
		printf("encode ie err!\n");
		return ISDN_CM_FAILED;
	}
	dst->notify_descr = (src[0] & 0x7F);

	return ISDN_CM_OK;
}

u8 isdn_encode_disp(u8 *dst, Disp *src)
{
	u8 offset = 0;
	memcpy(dst,src->disp_info,src->disp_info_len);  
	offset += src->disp_info_len;

	return offset;
}

int isdn_decode_disp(Disp *dst, u8 *src, u8 len)
{
	dst->pres = 1;
	if(len < 1)
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
	
	if(len > 18)
	{
		len = 18;
		printf("len is truncated!\n");
	}
	dst->disp_info_len = len;
	memcpy(dst->disp_info, src, dst->disp_info_len);

	return ISDN_CM_OK;
}

u8 isdn_encode_dt_time(u8 *dst, DtTime *src)
{
	u8 offset = 0;
	dst[offset++] = src->year;
	dst[offset++] = src->month;
	dst[offset++] = src->day;
	if(src->ext_flag & 0x01)	//with octet 6, 7 and 8
	{
		dst[offset++] = src->hour;
		dst[offset++] = src->minute;
		dst[offset++] = src->second;
	}
		
	return offset;
}

int isdn_decode_dt_time(DtTime *dst, u8 *src, u8 len)
{
	u8 offset = 0;
	dst->pres = 1;
	if((len < 3) || (len > 6))
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
	
	dst->year = (src[offset++]);
	dst->month = (src[offset++]);
	dst->day = (src[offset++]);
	if(offset < len)
	{
		dst->ext_flag |= 0x01;
		dst->hour = (src[offset++]);
		dst->minute = (src[offset++]);
		dst->second = (src[offset++]);
	}

	return ISDN_CM_OK;
}

u8 isdn_encode_kpd_fac(u8 *dst, KpdFac *src)
{
	u8 offset = 0;
	int i = 0;
//	memcpy(dst+offset, src->key_fac_info, src->keyfac_info_len);
//	offset += src->keyfac_info_len;
	while(i < src->keyfac_info_len)
	{
		dst[offset++] = Hex_to_IA5(src->key_fac_info[i]);
		i++;
	}
	
	return offset;
}

int isdn_decode_kpd_fac(KpdFac *dst, u8 *src, u8 len)
{
	u8 offset = 0, digit;
	int i = 0;
	dst->pres = 1;
	if((len < 1) || (len > 32))
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
//	dst->keyfac_info_len = len;
//	memcpy(dst->key_fac_info, src, dst->keyfac_info_len);
	dst->keyfac_info_len = len - offset;
	while((offset < len) && ((digit = IA5_to_Hex(src[offset])) < 0x0D))
	{
		dst->key_fac_info[i] = digit;
		offset++;
		i++;
	}

	return ISDN_CM_OK;
}

u8 isdn_encode_sign(u8 *dst, Sign *src)
{
	u8 offset = 0;
	dst[offset++] = src->sign_val;
	
	return offset;
}

int isdn_decode_sign(Sign *dst, u8 *src, u8 len)
{
	dst->pres = 1;
	if(len != 1)
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
	dst->sign_val = (src[0]);
	
	return ISDN_CM_OK;
}


u8 isdn_encode_cg_num(u8 *dst, CgPtyNum *src)
{
	u8 offset = 0;
	int i = 0;
	dst[offset++] = (src->b3.has_ext_a << 7) | (src->b3.num_type << 4) | (src->b3.num_plan_id);
	if(!src->b3.has_ext_a)		//with 3a
	{
		dst[offset++] = 0x80 | (src->b3.pres_ind << 5) | (src->b3.screen_ind);
	}
	
	if(src->ext_flag & 0x01)		//octet 4
	{
		while(i < src->num_digit_len)
		{
			dst[offset++] = Hex_to_IA5(src->num_digit[i]);
			i++;
		}
	}

	return offset;
}

int isdn_decode_cg_num(CgPtyNum *dst, u8 *src, u8 len)
{
	u8 offset = 0, digit;
	int i = 0;
	dst->pres = 1;
	if((len < 1) || (len > 34))
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
	dst->b3.has_ext_a = ((src[offset] & 0x80) >> 7);
	dst->b3.num_type = ((src[offset] & 0x70) >> 4);
	dst->b3.num_plan_id = (src[offset++] & 0x0F);
	if(!dst->b3.has_ext_a)		//with 3a
	{
		dst->b3.pres_ind = ((src[offset] & 0x60) >> 5);
		dst->b3.screen_ind = (src[offset++] & 0x03);
	}
	
	if(offset < len)
	{
		dst->ext_flag |= 0x01;
		dst->num_digit_len = len - offset;
		while((offset < len) && ((digit = IA5_to_Hex(src[offset])) < 0x0D))	//octet 4
		{
			dst->num_digit[i] = digit;
			offset++;
			i++;
		}
	}

	return ISDN_CM_OK;
}

u8 isdn_encode_cg_addr(u8 *dst, CgPtyAddr *src)
{
	u8 offset = 0;
	dst[offset++] = 0x80 | (src->addr_type << 4) | (src->odd_even << 3);
	memcpy(dst+offset, src->addr_info, src->addr_info_len);
	offset += src->addr_info_len;

	return offset;
}

int isdn_decode_cg_addr(CgPtyAddr *dst, u8 *src, u8 len)
{
	u8 offset = 0;
	dst->pres = 1;
	if((len < 2) || (len > 21))
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
	
	if(!(src[offset] & 0x80))
	{
		printf("encode ie err!\n");
		return ISDN_CM_FAILED;
	}
	dst->addr_type = ((src[offset] & 0x70) >> 4);
	dst->odd_even = ((src[offset++] & 0x08) >> 3);
	dst->addr_info_len = len - 1;
	memcpy(dst->addr_info, src+offset, dst->addr_info_len);
	
	return ISDN_CM_OK;
}

u8 isdn_encode_cd_num(u8 *dst, CdPtyNum *src)
{
	u8 offset = 0;
	int i = 0;
	dst[offset++] = 0x80 | (src->num_type << 4) | (src->num_plan_id);
	while(i < src->num_digit_len)
	{
		dst[offset++] = Hex_to_IA5(src->num_digit[i]);
		i++;
	}
	
	return offset;
}

int isdn_decode_cd_num(CdPtyNum *dst, u8 *src, u8 len)
{
	u8 offset = 0, digit;
	int i = 0;
	dst->pres = 1;
	if((len < 2) || (len > 33))
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
	
	if(!(src[offset] & 0x80))
	{
		printf("encode ie err!\n");
		return ISDN_CM_FAILED;
	}
	dst->num_type = ((src[offset] & 0x70) >> 4);
	dst->num_plan_id = (src[offset++] & 0x0F);
	dst->num_digit_len = len - offset;
	while((offset < len) && ((digit = IA5_to_Hex(src[offset])) < 0x0D))
	{
		dst->num_digit[i] = digit;
		offset++;
		i++;
	}

	return ISDN_CM_OK;
}

u8 isdn_encode_cd_addr(u8 *dst, CdPtyAddr *src)
{
	u8 offset = 0;
	dst[offset++] = 0x80 | (src->addr_type << 4) | (src->odd_even);
	memcpy(dst+offset, src->addr_info, src->addr_info_len);
	offset += src->addr_info_len;

	return offset;
}

int isdn_decode_cd_addr(CdPtyAddr *dst, u8 *src, u8 len)
{
	u8 offset = 0;
	dst->pres = 1;
	if((len < 2) || (len > 21))
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
	
	if(!(src[offset] & 0x80))
	{
		printf("encode ie err!\n");
		return ISDN_CM_FAILED;
	}
	dst->addr_type = ((src[offset] & 0x70) >> 4);
	dst->odd_even = ((src[offset++] & 0x08) >> 3);
	dst->addr_info_len = len - 1;
	memcpy(dst->addr_info, src+offset, dst->addr_info_len);

	return ISDN_CM_OK;
}

u8 isdn_encode_tran_sel(u8 *dst, TranNtSel *src)
{
	u8 offset = 0;
	dst[offset++] = 0x80 | (src->net_id_type << 4) | (src->net_id_plan);
	dst[offset++] = src->net_id & 0x7F;
	
	return offset;
}

int isdn_decode_tran_sel(TranNtSel *dst, u8 *src, u8 len)
{
	u8 offset = 0;
	dst->pres = 1;
	if(len < 2)
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
	
	if(!(src[offset] & 0x80))
	{
		printf("encode ie err!\n");
		return ISDN_CM_FAILED;
	}
	dst->net_id_type = ((src[offset] & 0x70) >> 4);
	dst->net_id_plan = (src[offset++] & 0x0F);
	dst->net_id = (src[offset++] & 0x7F);

	return ISDN_CM_OK;
}

u8 isdn_encode_restart_ind(u8 *dst, RestartInd *src)
{
	u8 offset = 0;
	dst[offset++] = 0x80 | (src->clas);
	
	return offset;
}

int isdn_decode_restart_ind(RestartInd *dst, u8 *src, u8 len)
{
	u8 offset = 0;
	dst->pres = 1;
	if(len != 1)
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
	
	if(!(src[offset] & 0x80))
	{
		printf("encode ie err!\n");
		return ISDN_CM_FAILED;
	}
	dst->clas = (src[offset++] & 0x07);

	return ISDN_CM_OK;
}

u8 isdn_encode_ll_comp(u8 *dst, LLComp *src)
{
	u8 offset = 0;
	dst[offset++] = (src->b3.has_ext_a << 7) | (src->b3.code_stan << 5) | (src->b3.tran_cap);
	if(!src->b3.has_ext_a)	//octet 3 with 3a
	{
		dst[offset++] = 0x80 | (src->b3.neg_ind << 6);
	}
	dst[offset++] = 0x80 | (src->b4.tran_mode << 5) | (src->b4.tran_rate);
	if((src->b4.tran_rate & 0x1F) == 0x18)		//with 4.1		multirate
	{
		dst[offset++] = 0x80 | (src->b4.rate_mul);
	}
	if(src->ext_flag & 0x01)		//octet 5
	{
		dst[offset++] = (src->b5.has_ext_a << 7) | (0x1 << 5) | (src->b5.usr_layer1);
		if(!src->b5.has_ext_a)		//with 5a
		{
			dst[offset++] = (src->b5.has_ext_b << 7) | (src->b5.syn_asy << 6) | 
				(src->b5.neg << 5) | (src->b5.usr_rate);
			
			if(!src->b5.has_ext_b)	//with 5b
			{
				if((src->b5.usr_layer1 & 0xFF) == 0x1)
				{
					dst[offset++] = (src->b5.has_ext_c << 7) | (src->b5.inter_rate << 5) | 
						(src->b5.nic_tx << 4) | (src->b5.nic_rx << 3) | 
						(src->b5.ctl_tx << 2) | (src->b5.ctl_rx <<1);
				}
				else if((src->b5.usr_layer1 & 0xFF) == 0x8)
				{
					dst[offset++] = (src->b5.has_ext_c << 7) | (src->b5.hdr << 6) | 
						(src->b5.mul_fra << 5) | (src->b5.mode << 4) | 
						(src->b5.lli_neg << 3) | (src->b5.assign << 2) | 
						(src->b5.inband << 1);
				}
				
				if(!src->b5.has_ext_c)	//5c
				{
					dst[offset++] = (src->b5.has_ext_d << 7) | (src->b5.stop_bit << 5) | 
						(src->b5.data_bit << 3) | (src->b5.par);

					if(!src->b5.has_ext_d)	//5d
					{
						dst[offset++] = 0x80 | (src->b5.du_mode << 6) | (src->b5.mod_type);
					}
				}
			}
		}
	}
	else if(src->ext_flag & 0x02)	//octet 6
	{
		if((src->b6.usr_layer2 & 0x1F) == 0x10)	//with 6a	for user specified layer 2 protocol
		{
			dst[offset++] = (0x2 << 5) | (src->b6.usr_layer2);
			dst[offset++] = 0x80 | (src->b6.usr_layer2_info);
		}
		else if(((src->b6.usr_layer2 & 0x1F) == 0x02) || ((src->b6.usr_layer2 & 0x1F) == 0x06) || 
			((src->b6.usr_layer2 & 0x1F) == 0x07) || ((src->b6.usr_layer2 & 0x1F) == 0x09) || 
			((src->b6.usr_layer2 & 0x1F) == 0x0A) || ((src->b6.usr_layer2 & 0x1F) == 0x0B) ||
			((src->b6.usr_layer2 & 0x1F) == 0x0D) || ((src->b6.usr_layer2 & 0x1F) == 0x0E) ||
			((src->b6.usr_layer2 & 0x1F) == 0x11))	//with 6a and 6b	HDLC elements
		{
			dst[offset++] = (0x2 << 5) | (src->b6.usr_layer2);
			dst[offset++] = (src->b6.mode << 5) | (src->b6.q933_use);
			dst[offset++]	= 0x80 | (src->b6.win_size);
		}
		else
		{
			dst[offset++] = 0x80 | (0x2 << 5) | (src->b6.usr_layer2);
		}
	}
	else if(src->ext_flag & 0x04)	//octet 7
	{
		if((src->b7.usr_layer3 & 0x1F) == 0x10)	//with 7a	for user specified layer 3 protocol
		{
			dst[offset++] = (0x3 << 5) | (src->b7.usr_layer3);
			dst[offset++] = 0x80 | (src->b7.usr_layer3_info);
		}
		else if(((src->b7.usr_layer3 & 0x1F) == 0x6) || ((src->b7.usr_layer3 & 0x1F) == 0x7) ||
			((src->b7.usr_layer3 & 0x1F) == 0x8))	//with 7a, 7b and 7c
		{
			dst[offset++] = (0x3 << 5) | (src->b7.usr_layer3);
			dst[offset++] = (src->b7.mode);
			dst[offset++] = (src->b7.def_pac_size);
			dst[offset++] = 0x80 | (src->b7.pac_win_size);
		}
		else
		{
			dst[offset++] = 0x80 | (0x3 << 5) | (src->b7.usr_layer3);
		}
	}

	return offset;
}

int isdn_decode_ll_comp(LLComp *dst, u8 *src, u8 len)
{
	u8 offset = 0;
	dst->pres = 1;
	if((len < 2) || (len > 16))
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
	dst->b3.has_ext_a = ((src[offset] & 0x80) >> 7);
	dst->b3.code_stan = ((src[offset] & 0x60) >> 5);
	dst->b3.tran_cap = (src[offset++] & 0x1F);
	if(!dst->b3.has_ext_a)		//with 3a
	{
		dst->b3.neg_ind = ((src[offset++] & 0x40) >> 6);
	}
	
	if(!(src[offset] & 0x80))
	{
		printf("encode ie err!\n");
		return ISDN_CM_FAILED;
	}
	dst->b4.tran_mode = ((src[offset] & 0x60) >> 5);
	dst->b4.tran_rate = (src[offset++] & 0x1F);
	if((dst->b4.tran_rate & 0x1F) == 0x18)	//with 4.1
	{
		dst->b4.rate_mul = (src[offset++] & 0x7F);
	}

	if(offset < len)	//octet at offside
	{
		if(((src[offset] & 0x60) >> 5) == 0x1)		//octet 5
		{
			dst->ext_flag |= 0x01;
			dst->b5.has_ext_a = ((src[offset] & 0x80) >> 7);
			dst->b5.usr_layer1 = (src[offset++] & 0x1F);
			if(!dst->b5.has_ext_a)		//with 5a
			{
				dst->b5.has_ext_b = ((src[offset] & 0x80) >> 7);
				dst->b5.syn_asy = ((src[offset] & 0x40) >> 6);
				dst->b5.neg = ((src[offset] & 0x20) >> 5);
				dst->b5.usr_rate = (src[offset++] & 0x1F);
				if(!dst->b5.has_ext_b)	//with 5b
				{
					dst->b5.has_ext_c = ((src[offset] & 0x80) >> 7);
					if((dst->b5.usr_layer1 & 0x1F) == 0x1)	//V.110/X.30
					{
						dst->b5.inter_rate = ((src[offset] & 0x60) >> 5);
						dst->b5.nic_tx = ((src[offset] & 0x10) >> 4);
						dst->b5.nic_rx = ((src[offset] & 0x08) >> 3);
						dst->b5.ctl_tx = ((src[offset] & 0x04) >> 2);
						dst->b5.ctl_rx = ((src[offset++] & 0x02) >> 1);
					}
					else if((dst->b5.usr_layer1 & 0x1F) == 0x8)	//V.120
					{
						dst->b5.hdr = ((src[offset] & 0x40) >> 6);
						dst->b5.mul_fra = ((src[offset] & 0x20) >> 5);
						dst->b5.mode = ((src[offset] & 0x10) >> 4);
						dst->b5.lli_neg = ((src[offset] & 0x08) >> 3);
						dst->b5.assign = ((src[offset] & 0x04) >> 2);
						dst->b5.inband =((src[offset++] & 0x02) >> 1);
					}

					if(!dst->b5.has_ext_c)		//with 5c
					{
						dst->b5.has_ext_d = ((src[offset] & 0x80) >> 7);
						dst->b5.stop_bit = ((src[offset] & 0x60) >> 5);
						dst->b5.data_bit = ((src[offset] & 0x18) >> 3);
						dst->b5.par = (src[offset++] & 0x07);

						if(!dst->b5.has_ext_d)	//with 5d
						{
							dst->b5.du_mode = ((src[offset] & 0x40) >> 6);
							dst->b5.mod_type =(src[offset++] & 0x3F);
						}
					}
				}
			}
		}
	}
	if(offset < len)	//octet at offside
	{
		if(((src[offset] & 0x60) >> 5) == 0x2)		//octet 6
		{
			dst->ext_flag |= 0x02;
			dst->b6.usr_layer2 = (src[offset++] & 0x1F);
			if((dst->b6.usr_layer2 & 0x1F) == 0x10)	//with 6a	for user specified layer 2 protocol
			{
				dst->b6.usr_layer2_info = (src[offset++] & 0x7F);
			}
			else if(((dst->b6.usr_layer2 & 0x1F) == 0x02) || ((dst->b6.usr_layer2 & 0x1F) == 0x06) || 
				((dst->b6.usr_layer2 & 0x1F) == 0x07) || ((dst->b6.usr_layer2 & 0x1F) == 0x09) || 
				((dst->b6.usr_layer2 & 0x1F) == 0x0A) || ((dst->b6.usr_layer2 & 0x1F) == 0x0B) ||
				((dst->b6.usr_layer2 & 0x1F) == 0x0D) || ((dst->b6.usr_layer2 & 0x1F) == 0x0E) ||
				((dst->b6.usr_layer2 & 0x1F) == 0x11))	//with 6a and 6b	HDLC elements
			{
				dst->b6.mode = ((src[offset] & 0x60) >> 5);
				dst->b6.q933_use = (src[offset++] & 0x03);
			}
		}
	}
	if(offset < len)	//octet at offside
	{
		if(((src[offset] & 0x60) >> 5) == 0x3)	//octet 7
		{
			dst->ext_flag |= 0x04;
			dst->b7.usr_layer3 = (src[offset] & 0x1F);
			if((dst->b7.usr_layer3 & 0x1F) == 0x10)	//with 7a	for user specified layer 3 protocol
			{
				dst->b7.usr_layer3_info = (src[offset++] & 0x7F);
			}
			else if(((dst->b7.usr_layer3 & 0x1F) == 0x6) || ((dst->b7.usr_layer3 & 0x1F) == 0x7) ||
				((dst->b7.usr_layer3 & 0x1F) == 0x8))	//with 7a, 7b and 7c
			{
				dst->b7.mode = ((src[offset++] & 0x60) >> 5);
				dst->b7.def_pac_size = (src[offset++] & 0x0F);
				dst->b7.pac_win_size = (src[offset++] & 0x7F);
			}
		}
	}

	return ISDN_CM_OK;
}

u8 isdn_encode_hl_comp(u8 *dst, HLComp *src)
{
	u8 offset = 0;
	dst[offset++] = 0x80 | (src->code_stan << 5) | (src->intpr << 2) | (src->pre_meth);
	if(((src->b4.hl_ch_id & 0x7F) == 0x5E) || ((src->b4.hl_ch_id & 0x7F) == 0x5F))	//with 4a	maintenance or management
	{
		dst[offset++] = src->b4.hl_ch_id;
		dst[offset++] = 0x80 | (src->b4.ex_hl_ch_id);
	}
	else if(((src->b4.hl_ch_id & 0x7F) >= 0x60) && ((src->b4.hl_ch_id & 0x7F) <= 0x6F))	//with 4a	audio visual
	{
		dst[offset++] = src->b4.hl_ch_id;
		dst[offset++] = 0x80 | (src->b4.ex_vid_ch_id);
	}
	else
	{
		dst[offset++] = 0x80 | (src->b4.hl_ch_id);
	}

	return offset;
}

int isdn_decode_hl_comp(HLComp *dst, u8 *src, u8 len)
{
	u8 offset = 0;
	dst->pres = 1;
	if((len < 2) || (len > 3))
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
	
	if(!(src[offset] & 0x80))
	{
		printf("encode ie err!\n");
		return ISDN_CM_FAILED;
	}
	dst->code_stan = ((src[offset] & 0x60) >> 5);
	dst->intpr = ((src[offset] & 0x1C) >> 2);
	dst->pre_meth = (src[offset++] & 0x03);
	dst->b4.hl_ch_id = (src[offset++] & 0x7F);
	if(((dst->b4.hl_ch_id & 0x7F) == 0x5E) || ((dst->b4.hl_ch_id & 0x7F) == 0x5F))	//with 4a	maintenance or management
	{
		dst->b4.ex_hl_ch_id = (src[offset++] & 0x7F);
	}
	else if(((dst->b4.hl_ch_id & 0x7F) >= 0x60) && ((dst->b4.hl_ch_id & 0x7F) <= 0x6F))	//with 4a	audio visual
	{
		dst->b4.ex_vid_ch_id = (src[offset++] & 0x7F);
	}
	
	return ISDN_CM_OK;
}

u8 isdn_encode_usr_usr(u8 *dst, UsrUsr *src)
{
	u8 offset = 0;
	dst[offset++] = src->pro_discr;
	memcpy(dst+offset, src->usr_info, src->usr_info_len);
	offset += src->usr_info_len;
	
	return offset;
}

int isdn_decode_usr_usr(UsrUsr *dst, u8 *src, u8 len)
{
	u8 offset = 0;
	dst->pres = 1;
	if((len < 2) || (len > 129))
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
	dst->pro_discr = (src[offset++] & 0xFF);
	dst->usr_info_len = len - 1;
	memcpy(dst->usr_info, src+offset, dst->usr_info_len);

	return ISDN_CM_OK;
}


//ie exist only in ansi
u8 ansi_encode_chg_stat(u8 *dst, ChgStat *src)
{
	u8 offset = 0;
	dst[offset++] = 0x80 | (src->pref << 6) | (src->new_stat);

	return offset;
}

int ansi_decode_chg_stat(ChgStat *dst, u8 *src, u8 len)
{
	dst->pres = 1;
	if(len != 1)
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}

	if(!(src[0] & 0x80))
	{
		printf("encode ie err!\n");
		return ISDN_CM_FAILED;
	}
	dst->pref = ((src[0] & 0x40) >> 6);
	dst->new_stat = (src[0] & 0x07);

	return ISDN_CM_OK;
}

u8 ansi_encode_redir_num(u8 *dst, RedirNum *src)
{
	u8 offset = 0;
	int i = 0;
	dst[offset++] = 0x80 | (src->b3.num_type << 4) | (src->b3.num_plan_id);
	dst[offset++] = 0x80 | (src->b3.org_num_stat);	// 3a
	dst[offset++] = 0x80 | (src->b3.redir_rs);	// 3b
	
	while(i < src->num_digit_len)
	{
		dst[offset++] = Hex_to_IA5(src->num_digit[i]);
		i++;
	}

	return offset;
}

int ansi_decode_redir_num(RedirNum *dst, u8 *src, u8 len)
{
	u8 offset = 0, digit;
	int i = 0;
	dst->pres = 1;
	if((len < 4) || (len > 35))
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
	dst->b3.num_type = ((src[offset] & 0x70) >> 4);
	dst->b3.num_plan_id = (src[offset++] & 0x0F);
	dst->b3.org_num_stat = (src[offset++] & 0x7F);	// 3a
	dst->b3.redir_rs= (src[offset++] & 0x0F);		// 3b
	
	dst->num_digit_len = len - offset;
	while((offset < len) && ((digit = IA5_to_Hex(src[offset])) < 0x0D))	//octet 4
	{
		dst->num_digit[i] = digit;
		offset++;
		i++;
	}

	return ISDN_CM_OK;
}


//QSIG
u8 qsig_encode_conn_num(u8 *dst, ConnNum *src)
{
	u8 offset = 0;
	int i = 0;
	dst[offset++] = (src->b3.has_ext_a << 7) | (src->b3.num_type << 4) | (src->b3.num_plan_id);
	if(!src->b3.has_ext_a)		//with 3a
	{
		dst[offset++] = 0x80 | (src->b3.pres_ind << 5) | (src->b3.screen_ind);
	}
	
	if(src->ext_flag & 0x01)		//octet 4
	{
		while(i < src->num_digit_len)
		{
			dst[offset++] = Hex_to_IA5(src->num_digit[i]);
			i++;
		}
	}

	return offset;
}

int qsig_decode_conn_num(ConnNum *dst, u8 *src, u8 len)
{
	u8 offset = 0, digit;
	int i = 0;
	dst->pres = 1;
	if((len < 1) || (len > 34))
	{
		printf("len err!\n");
		return ISDN_CM_FAILED;
	}
	dst->b3.has_ext_a = ((src[offset] & 0x80) >> 7);
	dst->b3.num_type = ((src[offset] & 0x70) >> 4);
	dst->b3.num_plan_id = (src[offset++] & 0x0F);
	if(!dst->b3.has_ext_a)		//with 3a
	{
		dst->b3.pres_ind = ((src[offset] & 0x60) >> 5);
		dst->b3.screen_ind = (src[offset++] & 0x03);
	}
	
	if(offset < len)
	{
		dst->ext_flag |= 0x01;
		dst->num_digit_len = len - offset;
		while((offset < len) && ((digit = IA5_to_Hex(src[offset])) < 0x0D))	//octet 4
		{
			dst->num_digit[i] = digit;
			offset++;
			i++;
		}
	}

	return ISDN_CM_OK;
}

