⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 编写d300sc-e1卡呼出程序.txt

📁 编写D300SC-E1卡呼出程序 编写D300SC-E1卡呼出程序
💻 TXT
📖 第 1 页 / 共 5 页
字号:
编写D/300SC-E1卡呼出程序 

--------------------------------------------------------------------------------
 
文章来源: CTI在线编辑 发布日期: 2004-5-8 18:03:03 

--------------------------------------------------------------------------------
 
编写D/300SC-E1卡呼出程序
1 .1概述
11.4节和11.5节讲述了D/300SC-E1卡的呼入模式编程,本章将继续讲解该卡使用在呼出模式时的程序设计方法。呼出模式程序和呼入模式程序虽然结构上不一样,但是其原理都是差不多的,唯一不同的就是把主叫和被叫的位置颠倒了一下,原来我方是被叫方,现在成为主叫方。而我方发送的信令相应地变成了前向信令,而对方发送的信令叫做后向信令。

那么,按照前面我们讨论的过程,这次我们来发送Group I组和Group II组信号,并检测Group A组和Group B组信号,这正好和呼入模式相反。由于Dialogic在R2MF信令的处理上只提供了两个函数r2_creatfsig()和r2_playbsig(),前一个使通道可以检测到前向信令而后一个在通道上播放后向信令。可是现在我们需要播放前向信令和检测后向信令,这两个唯一提供的R2MF函数是不能完成的。于是我们只有自己编写函数来实现这一过程。
要播放前向信号音,我们必须首先建立该信号音的模板,然后再调用播放信号音函数dx_playtone()来播放前项信号音。按照互控的原理,当我们播放前向信号音的时候,如果后向信号音出现,则我们必须立即停止播放前向信号音,并根据检测到的信号音来确定下一个需要播放的前向信号音。于是我们可以参照r2_creatfsig()函数和r2_playbsig()函数来建立我们自己的r2_creatbsig()和r2_playfsig()函数。下面我们按照顺序来描述D/300SC-E1的外拨呼叫过程:

2 建立前向R2MF信号音模板
3 初始化R2MF播放终止条件表
4 打开语音资源和数字时隙资源
5 执行SC总线连接
6 使通道可以检测到后向R2MF
7 使通道可以检测到挂机事件
8 初始化数字时隙挂机
9 建立前向信令播放函数
10 外拨呼叫
11 播放提示语
12挂机
13 退出系统

1.2 建立前向R2MF信号音模板
为了播放R2MF信号音,我们必须首先建立该信号音的模板,所谓模板就是一个信号音特征的定义,包括信号音的频率、声强和持续时间等等。Dialogic用一个结构TN_GEN来定义信号音的特征,并使用函数dx_bldtngen()来建立信号音的特征。参考第三章,按照R2MF的标准,我们来定义前向15个信号音的频率:
int fsig[15][2]={
{1380,1500},{1380,1620},{1500,1620},{1380,1740},{1500,1740},
{1620,1740},{1380,1860},{1500,1860},{1620,1860},{1740,1860},
{1380,1980},{1500,1980},{1620,1980},{1740,1980},{1860,1980}
};
并使用一个TN_GEN数组来存放建立的R2MF信号音特征描述:
TN_GEN tngen[15];
然后调用dx_bldtngen()函数来循环建立这15个前向信号音:

memset(tngen,0,sizeof(tngen));
for(i=0;i<15;i++)
dx_bldtngen(&tngen[i],
fsig[i][0],fsig[i][1],
R2_DEFAMPL,R2_DEFAMPL,200);

函数dx_bldtngen()建立一个R2MF信号音,其中R2_DEFAMPL是Dialogic定义的R2MF信号音的分贝值-10db。函数执行完成后,15个信号音的特征定义就被存放在tngen变量里了,以后我们需要播放前向信号的时候,直接调用Dialogic的信号音播放函数dx_playtone()并指定信号音的模板就可以了。事实上我们实现了在通道上播放R2MF前向信号。
1..3 初始化R2MF播放终止条件表
按照MFC互控的规定,我方将一直播放前向信号,直到我方检测到后向的应答信号后,必须立即停止播放前向信号。因此,我们在调用函数dx_playtone()来播放信号音的时候,必须为该函数设置适当的终止条件,使得函数dx_playtone()在播放的过程中一但满足指定的条件边结束播放。终止条件类别DX_TONE用来设置当通道检测到信号音的时候便结束函数的执行,我们于是可以使用这个条件来设置dx_playtone()的终止条件。在我方作为主叫的情况下,需要检测的信号音是Group A组和Group B组的信号音。但是不是全部,而是只需要检测其中几个,就象当我们是被叫的时候只发送Group A和Group B组中的某几个信号音一样,现在只不过是主叫被叫正好颠倒,发送的信号音正好相反一样。
在我方作为主叫的情况时,我们只需要检测以下后向信号:
l Group A组A1信号 – 发送下一位
l Group A组A6信号 – 发送记费类型和主叫号码
l Group A组A3信号 – 转至B组
l Group B组B1信号 – 被叫用户应答
l Group B组B4信号 – 被叫用户忙或机键拥塞

另外,我们在播放前向信号音的时候,如果线路出现故障、对方不相应,我们当然不能无限制的等待下去,当播放信号音并等待一段指定的时间后线路依然检测不到后项应答信号,则我们认为对方没有应答信号,于是这段设置dx_playtone()函数终止参数表的代码可以编写如下,由于我们发送的是前向信号,一旦检测到后向应答信号的出现我们就立即终止前向信号的播放,所以我们只需要检测DE_TONEON事件,于是我们为每一个R2MF信号终止条件指定信号音标志DX_TONEON:

DV_TPT r2_tpt[6];
memset(r2_tpt,0,sizeof(r2_tpt));

/*R2MF信号A1的终止条件*/
r2_tpt[0].tp_type=IO_CONT;
r2_tpt[0].tp_termno=DX_TONE;
r2_tpt[0].tp_length=SIGA_1;
r2_tpt[0].tp_flags=TF_TONE;
r2_tpt[0].tp_data=DX_TONEON;

/*R2MF信号A6的终止条件*/
r2_tpt[1].tp_type=IO_CONT;
r2_tpt[1].tp_termno=DX_TONE;
r2_tpt[1].tp_length=SIGA_6;
r2_tpt[1].tp_flags=TF_TONE;
r2_tpt[1].tp_data=DX_TONEON;

/*R2MF信号A3的终止条件*/
r2_tpt[2].tp_type=IO_CONT;
r2_tpt[2].tp_termno=DX_TONE;
r2_tpt[2].tp_length=SIGA_3;
r2_tpt[2].tp_flags=TF_TONE;
r2_tpt[2].tp_data=DX_TONEON;

/*R2MF信号B1的终止条件*/
r2_tpt[3].tp_type=IO_CONT;
r2_tpt[3].tp_termno=DX_TONE;
r2_tpt[3].tp_length=SIGB_1;
r2_tpt[3].tp_flags=TF_TONE;
r2_tpt[3].tp_data=DX_TONEON;

/*R2MF信号B4的终止条件*/
r2_tpt[4].tp_type=IO_CONT;
r2_tpt[4].tp_termno=DX_TONE;
r2_tpt[4].tp_length=SIGB_4;
r2_tpt[4].tp_flags=TF_TONE;
r2_tpt[4].tp_data=DX_TONEON;

/*700*10 = 7秒不响应就表示线路出现问题了*/
r2_tpt[5].tp_type=IO_EOT;
r2_tpt[5].tp_termno=DX_MAXTIME;
r2_tpt[5].tp_length=700;
r2_tpt[5].tp_flags=TF_10MS;
1..4 打开语音资源和数字时隙资源
打开过程在呼入程序时已经描述,此处不再重复:
if ((vox = dx_open(voxname, 0)) == -1) 
{
printf("Error opening channel %s\n",dev[i].voxname);
exit(1);
}
if ((dti = dt_open(dtiname, 0)) == -1) 
{
printf("Error opening channel %s\n",dev[i].dtiname);
exit(1);
}
1..5 执行SC总线连接
不再重复,参考呼入部分的描述:
if(nr_scroute(dti,SC_DTI,vox,SC_VOX,SC_FULLDUP)==-1)
{
   printf("Can not route SC.%d\n",i);
   exit(1);
}
1..6 使通道可以检测到后向R2MF
为了能够检测到R2MF信号音,我们必须在通道建立其后向信号音的描述,并把描述增加到通道,当该特征的信号音出现的时候,通道才可以检测到。于是我们按照R2MF后向信号的标准来建立后向信号:
int bsig[15][2]={
{1140,1020},{1140, 900},{1020, 900},{1140, 780},{1020, 780},
{ 900, 780},{1140, 660},{1020, 660},{ 900, 660},{ 780, 660},
{1140, 540},{1020, 540},{ 900, 540},{ 780, 540},{ 660, 540}
};

首先必须将通道内以前的信号音特征定义删除,以留出足够的空间:
if(dx_deltones(vox)==-1){
printf("dx_deltones()\n");
return -1;
}

顺序建立15个后向R2MF信号:
for(td=SIGA_1;td<=SIGA_15;td++){
/* 建立该信号的特征描述 */
if(dx_blddt(td,
bsig[td-SIGA_1][0],50,
bsig[td-SIGA_1][1],50,TN_LEADING)==-1)
{
printf("dx_blddt error\n");
return -1;
       }
   /*将刚才建立的信号增加到通道,使通道可以检测到*/
if(dx_addtone(vox,NULL,0)==-1) 
{
printf("dx_addtone error\n");
return -1;
}
}

1..7 使通道可以检测到挂机事件
dt_setevtmsk(EV_ANYDEV,DTG_SIGEVT,DTMM_AON,DTA_SETMSK);
1..8 初始化数字时隙挂机
将信令传送位ABCD码初始化为1011表示线路空闲:
if(dt_settssig(dti,DTB_ABIT|DTB_CBIT|DTB_DBIT,DTA_SETMSK)==-1){
printf("%s: dt_settssig() in dt_onhook_out(1) error.\n",voxname);
return 0;
}
为什么设置为1011表示线路空闲,请参考第三章中关于市话局至市话局信号标志编码的ABCD码不同时候的含义说明。

1..9 建立前向信令播放函数
我们将建立一个自定义的函数来播放前向信令,该函数在播放的过程中如果检测到后向应答信号,则立即停止播放,并将后向 R2MF的ID返回,代码参考:
int r2_playfsig(int vox, int forwardsig, int mode)
{
int i,bksig;
int term;
i=forwardsig - SIGI_1;

if(dx_playtone(vox,&tngen[i],r2_tpt,EV_SYNC)==-1)
{
printf("%s: dx_playtone失败 %s\n",
ATDV_NAMEP(vox),ATDV_ERRMSGP(vox));
return -1;
} 

/*检测dx_playtone()的结束原因*/
if((term = ATDX_TERMMSK(vox))==-1)
{
printf("ATDX_TERMMSK error\n");
return -1;
}
if(term & TM_TONE) /*如果是由于检测到自定义信号音为结束,那么检测信号音的ID*/
{
    /*检测导致dx_playtone()函数结束的信号音ID*/
if((bksig = ATDX_TONEID(voxdev))==-1)
{
printf("ATDX_TONEID error\n");
return -1;
}
return bksig;
} else {
printf("%s: 没有检测到后向信号\n",ATDV_NAMEP(vox));
return -1;
}
}
1..10 外拨呼叫
外拨时正好和呼入时相反,我们首先要发送线路占用信号:

一、将AB 从10变化到00表示要占用此线路:
if(dt_settssig(dti,DTB_ABIT,DTA_SUBMSK) == -1)
{
printf("%s: dt_settssig() error.\n",.voxname);
return -1;
}

二、等待对方的占用确认信号:
int time = 0; /*记时*/
int tsbits = 0; /*传送和接收信令位*/
#define SZ_ACK_TIME 6 /*我们等待后向占用确认信号最长6秒*/
do{
Sleep(40);
time+=40;
if((tsbits=ATDT_TSSGBIT(dti))==AT_FAILURE){
printf("%s: ATDT_TSSGBIT() error\n",voxname);
return -1;
}
arcv=(tsbits & DTSG_RCVA)?1:0;
brcv=(tsbits & DTSG_RCVB)?1:0;
axmt=(tsbits & DTSG_XMTA)?1:0;
bxmt=(tsbits & DTSG_XMTB)?1:0;
printf("RX(%d,%d);TX(%d,%d)\n",arcv,brcv,axmt,bxmt);
if(time > (1000*SZ_ACK_TIME))/*如果等待超时*/
{
printf("%s: 等待后向占用确认信号超时.\n", dtiname);
return -1;
}
}while(!((arcv==1)&&(brcv==1)&&(axmt==0)&&(bxmt==0)));
当(arcv==1)&&(brcv==1)&&(axmt==0)&&(bxmt==0)也就是接收位(后向信号位)AB为11,传送位(前向信号位)AB为00的时候,表示对方应答了占用请求,也就是发送了占用确认应答信号,表示此线路空闲,可以被占用。

三、开始MFC互控接续过程
(1)发送被叫号码DNIS
首先,我们给被叫发送被叫号码,发送被叫号码的时候,按照1号信令规范,当我方接收到后向A6信号的时候,表示要求我方发送记费类别和主叫号码。那么,当我们检测到后向A6信号或发送被叫号码完毕时,我们就结束被叫号码发送过程:
char *dnis[8] = “62354848”; /*被叫号码*/
#define DNIS_LEN  8 /*被叫号码长度*/
char ani[8] = “123456”;/*主叫号码*/
#define ANI_LEN 6/*主叫号码长度*/

cur_num=0; /*当前发送了多少个前向信令*/
do{
     /*此处将号码的字符转换为信令的ID,为什么SIGI_10对应字符’0’,前面有说明*/
fwsig=(dnis[cur_num]=='0')?SIGI_10:(dnis[cur_num]-0x31+SIGI_1);
if((bksig=r2_playfsig(vox,fwsig,EV_SYNC))==-1)
 return -1;
printf("%s: Backward is %d\n",voxname,bksig);
cur_num++;
} while ((bksig!=SIGA_6)||(cur_num>DNIS_LEN));
其中,r2_playfsig()函数是我们自定义的函数,其实现原理请参考11.6.9小节。

(2) 发送记费类别
在此,我们将发送记费类别。SIGI_1表示记费类别为普通用户、立即记费:
fwsig=SIGI_1;
if((bksig = r2_playfsig(voxdev,fwsig,EV_SYNC))==-1) 
return -1;
printf("%s: Backward is %d\n", voxname,bksig);

(3) 发送主叫号码及主叫号码接受标志
发送主叫的时候,我们将按主叫号码的位顺序发送直到发送完毕,后向继续发送A1信号请求下一位的时候,我方发送SIGI_15信号表示主叫号码发送完毕。如下:
cur_num=0;
do{
fwsig=(ani[cur_num]=='0')?SIGI_10:(ani[cur_num]-0x31+SIGI_1);
if((bksig = r2_playfsig(vox,fwsig,EV_SYNC))==-1) 
return -1;
printf("%s: Backward is %d\n",dev[i].vox,bksig);
cur_num++;
} while (cur_num<ANI_LEN);

/*我方发送前向SIGI_15表示主叫号码发送完毕*/
fwsig = SIGI_15;
if((bksig = r2_playfsig(vox,fwsig,EV_SYNC))==-1) 
return -1;
printf("%s: Backward is %d\n",voxname,bksig);

(4) 发送发端呼叫业务类别
发端呼叫的业务类别为普通市话,其Group II组代码为SIGII_3,代码如下:
fwsig=SIGII_3;
if((bksig = r2_playfsig(vox,fwsig,EV_SYNC))==-1) 
return -1;
printf("%s: Backward is %d\n",voxname,bksig);
此时MFC接续过程就完毕了,且被叫线路此时已振铃,我们下一步需要等待后向的被叫应答信号,当后向A位从0变为1的时候,表示被叫应答了此呼叫,检测代码如下:

(5) 等待被叫应答
我们循环检测后向A位,一旦发现其变为1,就表示被叫摘机应答了,否则如果超过指定的时间依然没有检测到A位变为1,说明被叫电话无人应答,另外,如果检测的过程中发现后向B位变为0,表示被叫挂机了(后向挂机):
int time = 0;
int tsbits = 0 ;/*信令位状态变量*/
#define TIMEOUT 15000 /*等待15秒,如超时表示无人应答*/

do{
if((tsbits = ATDT_TSSGBIT(dtidev))==AT_FAILURE)
{
printf("%s: ATDT_TSSGBIT() error.\n",voxname);
return -1;
}

arcv=(tsbits & DTSG_RCVA)?1:0; /*后向A位*/
brcv=(tsbits & DTSG_RCVB)?1:0; /*后向B位*/
axmt=(tsbits & DTSG_XMTA)?1:0; /*前向A位*/
bxmt=(tsbits & DTSG_XMTB)?1:0; /*前向B位*/

if(brcv==0) {
printf("%s: 后向挂机.\n", voxname);
return -1;
}
Sleep(50);
time+=50;
if(time > TIMEOUT){
printf("%s: 线路 %s 无应答.\n",dev[i].voxname,dnis);
return -1;
}
} while(arcv==1);
当后向A位变为1的时候表示被叫应答了。
1..11 播放提示语
和呼入时一样,在播放语音文件之间先安装后项挂机事件的处理句柄:
if(sr_enbhdlr(dti,DTEV_SIG,AON_handler)==-1)
{
printf("sr_enbhdlr()失败.\n");
exit(1);
 }

然后调用播放函数放音:
DV_TPT tpt = {IO_EOT,DX_MAXTIME,60 * 10,TF_MAXTIME};
int fhandle = dx_fileopen("sample.vox",O_RDONLY|O_BINARY);
DX_IOTT iott = {IO_DEV,0,0,-1,fhandle,0};

if(dx_play(vox,&iott,&tpt,PM_TONE|EV_SYNC)==-1)
{
printf("播放错误, %s\n",ATDV_ERRMSGP(vox));
return 1;
}

播放结束,关闭文件,销毁事件处理句柄:
dx_close(fhandle);
if(sr_dishdlr(dti,DTEV_SIG,AON_handler)==-1){
printf("sr_dishdlr()失败\n");
exit(1);
}
 其中,AON_handler()函数是我们自己定义的函数,其实现原理和呼入模式下相同,此处不再重复。
1..12 挂机
将ABCD位设置为1011表示挂机并把通道设置到示闲状态:
if(dt_settssig(dti,DTB_ABIT|DTB_CBIT|DTB_DBIT,DTA_SETMSK)==-1)
{
printf("%s: dt_settssig()失败.\n", voxname);
return 1;
}
1.13 退出系统
return 0;

2 同步模式D/300SC-E1呼出程序
这里依然使用Dialogic公司的例子程序,希望详细的阅读其源代码。
2.1 源代码
/**************************************************************
 * Dialout from D/300SC-E1 Demo programs for Windows NT
 * Dialogic Corporation, Beijing
 * All Rights Reserved
 * April, 1997
 * Environment: Windows NT 3.51 / Later
 * Multithreaded Synchronous Mode
 * Compiler: Visual C++ 4.0
 **************************************************************/

/**************************************************************
 This program has two method to detect the CPE hangup signal;
 one is hangup_detection thread, 
 and the other is hangup_detect handler
 you can specify either of them
 **************************************************************/
#include<windows.h>
#include<stdlib.h>
#include<stdio.h>
#include<fcntl.h>
#include<string.h>
#include<srllib.h>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -