Delphi之东进模拟语音卡(D160A)可复用源码

2023-05-16

  
Delphi之东进模拟语音卡(D160A)可复用源码

作者:成晓旭

Bloghttp://blog.csdn.net/cxxsoft

(声明:欢迎转载,请保证文章的完整性)

设计简介:

1、   将卡、通道分别单独进行设计与封装。

2、   所有的外部操作接口都封装在卡类这一类。

3、   在我的项目中,在卡类这一级还增加了适配器或者代理,分别实现了AdapterProxy模式;以尽可能地解耦卡设备的实现细节与具体应用业务之间的关系。因为,我们的系统中使用了几家不同的卡设备,另一方面,这些卡设备,在不同的软件系统中,又有不同的业务应用需求。

4、   当然,卡这一级,也可以实现一个统一的接口,这样对外部可以表现出相对统一的行为,以方便业务层代码的调用,比如说:在数据采集的应用中,统一的接口可以让采集控制层不必依赖于具体的采集设备和通信方式,可以一致地实现数据收发,不管通信方式是RS232RS485TCP/IPPSTN,还是别的方式或者通信设备。

5、   在通道设计中,核心的就是一个“状态机模式”,通过轮巡通道状态来管理硬件卡设备,并且,还自己设计了一个业务级的“业务状态机”,来抽象业务方面需要关心的“业务状态”,通过增加“业务状态机”这样一个中间层,以解耦业务状态与设备状态之间的依赖。(这一点,在我看到的所有卡厂商提供的各类Demo程序里面都没有这样做,这也无形中误导了很多的开发人员,我看到的所有应用软件开发的源码都是:设备细节、尤其是通道状态,与业务逻辑代码紧紧地耦合在一起,难解难分)

6、   此设计的另一个亮点是:IoC模式的应用(2004年自己在设计此类时还不知道这个概念,全凭自己的经验总结出这样的设计)。对通道进入“呼入成功”、“呼出成功”等业务状态的调用代码从通道类是解耦出来:设计一个接口,在各个业务状态的处理方法中,再调用接口方法,将具体的业务处理逻辑委托给实现此接口的对象。并且这个接口的实现是通过“依赖注入”实现IoC的。这样设计,就达到了很好的可复用性和灵活性。

7、   当然,更好的实现可以采用AOP(面向方法编程)的思想或者实现技术,这样可复用性更好,如此设计,在业务与卡方法的调用之间,耦合度将是最低的。

8、   目前的版本,没有在代码中体现接口的实现……

9、   类图(以后补上)

    10、卡类源码:

// ------------------------------------------------------------------------------
//
//       产品名称:   成晓旭的个人软件Delphi源码库
//       产品版本:   CXXSoft delphi code source lib 2.0
//       模块名称:   Delphi之东进模拟语音卡类
//       模块描述:   
//       单元文件:   unDJCard160A.pas   
//       开发作者:   成晓旭
//       备注:       任何人使用此文件时,请保留此段自述文件,谢谢!
//       开发时间:   2004-08-03
//       修改历史:   
//       修改描述:
// ------------------------------------------------------------------------------
unit unDJCard160A;

interface
uses
  Windows,
  unDJTC08a32,unDJNewSig,
  unBaseDefine,unDJ160ADefine,
  unDJChanne160A;
type
  TCXXCommCard160A 
=   class (TObject)
  
private

    ChannelNumber:Word;
    channelObject:array of TCXXDJChannel160A;
    OnCardChannelState:TTrunkStatusEvent;

    procedure Stop();
    procedure ReleaseCommDevice();
    function  GetChannelObjectOrder(
const  aChannelID:Word):Word;

  
public

    constructor Create(
const  trunkEvent:TTrunkStatusEvent);
    destructor Destroy(); 
override ;

    function  LoadCommDevice(
const  loadAll:boolean = false ):boolean;
    function  Startup():boolean;
    function  GetAFreeChannel():Word;
    function  GetChannelNumber():Word;
    function  DialPhone(
const  aChannelID:Word; const  DialPhoneNumber:PChar):boolean;
    function  HangUp(
const  aChannelID:Word):boolean;

  end;


implementation

... { TCXXCommCard160A }
constructor TCXXCommCard160A.Create(
const  trunkEvent:TTrunkStatusEvent);
begin
  ChannelNumber :
=   0 ;
  Self.OnCardChannelState :
=  trunkEvent;
end;

destructor TCXXCommCard160A.Destroy;
var
  Loop:Word;
begin
  Stop();
  
if  (Length(channelObject)  >   0 ) and (channelNumber  >   0 ) then
  begin
    
for  Loop : =   0  to ChannelNumber  -   1   do
    begin
      
if  Assigned(channelObject[Loop]) then
      begin
        channelObject[Loop].Free();
        channelObject[Loop] :
=  nil;
      end;
    end;
  end;
  ReleaseCommDevice();
end;

function TCXXCommCard160A.DialPhone(
const  aChannelID: Word;
  
const  DialPhoneNumber: PChar): boolean;
var
  K:Word;
begin
  Result :
=   false ;
  K :
=  GetChannelObjectOrder(aChannelID);
  
if  (K  <>  ErrorTrunkNumber) and (Assigned(channelObject[K])) then
  begin
    Result :
=  channelObject[K].DialPhone(DialPhoneNumber);
  end;
end;

procedure TCXXCommCard160A.ReleaseCommDevice();
begin
  DisableCard();
  FreeDrv();
end;

function TCXXCommCard160A.GetAFreeChannel(): Word;
var
  Loop:Word;
begin
  Result :
=  ErrorTrunkNumber;
  
for  Loop : =  Low(channelObject) to High(channelObject)  do
  begin
    
if  (channelObject[Loop].GetChannelType()  =  ctEmpty) then  continue ;
    
if  (channelObject[Loop].GetChannelStatus()  =  atsFree) then
    begin
      Result :
=  channelObject[Loop].GetChannelID();
      
break ;
    end;
  end;
end;

function TCXXCommCard160A.GetChannelNumber(): Word;
begin
  Result :
=  channelNumber;
end;

function TCXXCommCard160A.GetChannelObjectOrder(
  
const  aChannelID: Word): Word;
var
  Loop:Word;
begin
  Result :
=  ErrorTrunkNumber;
  
for  Loop : =  Low(channelObject) to High(channelObject)  do
  begin
    
if  (channelObject[Loop].GetChannelID  =  aChannelID) then
    begin
      Result :
=  Loop;
      
break ;
    end;
  end;
end;

function TCXXCommCard160A.HangUp(
const  aChannelID: Word): boolean;
var
  K:Word;
begin
  Result :
=   false ;
  K :
=  GetChannelObjectOrder(aChannelID);
  
if  (K  <>  ErrorTrunkNumber) and (Assigned(channelObject[K])) then
  begin
    channelObject[K].ChannelHangUp();
    Result :
=   true ;
  end;
end;

function TCXXCommCard160A.LoadCommDevice(
const  loadAll:boolean): boolean;
const
  loadEmpty 
=   true ;
var
  Loop,tempNumber:Word;
  isFlag:LongInt;
  function CheckLoadTrunk():boolean;
  begin
    Result :
=  loadAll or ((NOT loadAll) and(TChannelType(CheckChType(Loop))  <>  ctEmpty));
  end;
begin
  isFlag :
=  LoadDRV();
  Result :
=  (isFlag = 0 );
  
if  NOT Result then Exit;
  tempNumber :
=  CheckValidCh();
  Result :
=  EnableCard(tempNumber, 1024 * 8 ) = 0 ;
  
if  NOT Result then
  begin
    FreeDrv();
    Exit;
  end;
  Result :
=  Sig_Init() = 1 ;
  
if  NOT Result then Exit;
  SetBusyPara(
700 );
  SetPackRate(PACK_64KBPS );
  channelNumber :
=  tempNumber;
  SetLength(channelObject,channelNumber);
  
for  Loop : =   0  to channelNumber  -   1   do
  begin
    
if  CheckLoadTrunk() then
    begin
      channelObject[Loop] :
=  TCXXDJChannel160A.Create(OnCardChannelState);
      channelObject[Loop].CreateCommChannel(Loop);
    end;
  end;
end;

function TCXXCommCard160A.Startup(): boolean;
var
  Loop:integer;
begin
  
for  Loop : =   0  to channelNumber  -   1   do
  begin
    channelObject[Loop].Resume();
  end;
  Result :
=   true ;
end;

procedure TCXXCommCard160A.Stop();
var
  Loop:integer;
begin
  
for  Loop : =   0  to channelNumber  -   1   do
  begin
    channelObject[Loop].Suspend();
    channelObject[Loop].Terminate();
    channelObject[Loop] :
=  nil;
  end;
end;

end.
11、              通道类源码:
// ------------------------------------------------------------------------------
//
//       产品名称:   成晓旭的个人软件Delphi源码库
//       产品版本:   CXXSoft delphi code source lib 2.0
//       模块名称:   Delphi之东进模拟语音卡通道类
//       模块描述:   
//       单元文件:   unDJChanne160A.pas   
//       开发作者:   成晓旭
//       备注:       任何人使用此文件时,请保留此段自述文件,谢谢!
//       开发时间:   2004-08-03
//       修改历史:   
//       修改描述:
// ------------------------------------------------------------------------------
unit unDJChanne160A;

interface

uses
  Windows,Classes,SysUtils,
  unBaseDefine,unDJ160ADefine,
  unDJTC08a32,unDJNewSig;
Type
  TCXXDJChannel160A 
=   class (TThread)
  
// TCXXDJChannel160A = class(TObject)
   private
    channelType:TChannelType;
    oldChannelState,channelState:TTrunkState;
    channelID:Word;
    phoneNumber:
string ;
    dtmfString:
string ;

    isConntectd:boolean;

    isDialOut:boolean;
    aTrunkState:TTrunkStatus;
    
    procedure InformTrunkStatus(
const  aMsgFlag: TLVOperateFlag);

    procedure ClearTrunkStatus();
    function  CheckSigHangup():boolean;
    function  CheckCallIn():boolean;
    function  SwitchOnCallIn():boolean;

    procedure ProcessCallInSuccess();
    procedure ProcessDialSuccess();

    procedure ProcessCheckDialSend();
  
protected
    procedure Execute(); 
override ;
  
public
    strMessage:
string ;
    OnChannelState:TTrunkStatusEvent;

    constructor Create(
const  trunkEvent:TTrunkStatusEvent);
    destructor Destroy();
override ;

    procedure CreateCommChannel(
const  aChennelID: Word);
    procedure ChannelProcessor();

    function  GetChannelID():Word;
    function  GetChannelStatus():TTrunkState;
    function  GetChannelType():TChannelType;
    function  DialPhone(
const  DialPhoneNumber:PChar):boolean;overload;
    function  DialPhone(
const  DialPhoneNumber:PChar; const  PreDialNumber:PChar):boolean;overload;
    procedure ChannelHangUp();

    function  GetDialOut():boolean;
  end;
implementation

... { TCXXDJChannel160A }

procedure TCXXDJChannel160A.ChannelHangUp();
begin
  isDialOut :
=   false ;
  StopSigCheck(channelID);
  HangUp(channelID);
  Sig_ResetCheck(channelID);
  StartSigCheck(channelID);
  InitDTMFBuf(channelID);
  ClearTrunkStatus();
  InformTrunkStatus(lvofUpdate);
end;

procedure TCXXDJChannel160A.ChannelProcessor();
var
  dState:Word;
begin
  PUSH_PLAY();
  FeedSigFunc();
  CheckCallIn();
    
case  channelState of
    atsFree:
    begin
      
//
    end;
    atsCallIning:
    begin
      SwitchOnCallIn();
    end;
    atsCallInSuccess:
    begin
      
if  CheckSigHangup() then Exit;
      ProcessCallInSuccess();
    end;
    atsCheckSendDial:
    begin
      ProcessCheckDialSend();
    end;
    atsDialing:
    begin
      dState :
=  Sig_CheckDial(channelID);
      
case  dState of
  
//       S_NORESULT:
        S_CONNECT:
        begin
          channelState :
=  atsDialSuccess;
          isConntectd :
=   true ;
        end;
        S_BUSY,
        S_NOBODY,
        S_NODIALSIG,
        S_NOSIGNAL:
        begin
          channelState :
=  atsHangOff;
        end;
      end;
      strMessage :
=   ' 拨号中... ' ;
    end;
    atsDialSuccess:
    begin
      
if  CheckSigHangup() then Exit;
      ProcessDialSuccess();
      strMessage :
=   ' 拨号成功 ' ;
    end;
    atsHangOff:
    begin
      ChannelHangUp();
    end;
    end;
    
if  (oldChannelState  <>  channelState) then
    begin
      oldChannelState :
=  channelState;
      InformTrunkStatus(lvofUpdate);
    end;
end;

function TCXXDJChannel160A.CheckCallIn(): boolean;
begin
  Result :
=  RingDetect(channelID);
  
if  Result then
  begin
    OffHook(channelID);
    
if  isDialOut then
      channelState :
=  atsDialSuccess
    
else
      channelState :
=  atsCallIning;
  end;
end;

function TCXXDJChannel160A.CheckSigHangup(): boolean;
begin
  Result :
=   false ;
  
if  (Sig_CheckBusy(channelID) = 1 ) then
  begin
    strMessage :
=   ' 对方已挂机 ' ;
    InformTrunkStatus(lvofUpdate);
    StopPlayFile(channelID);
    channelState :
=  atsHangOff;
    Result :
=   true ;
  end;
end;

procedure TCXXDJChannel160A.ClearTrunkStatus();
begin
  channelState :
=  atsFree;
  oldChannelState :
=  channelState;
  phoneNumber :
=   '' ;
  dtmfString :
=   '' ;
  strMessage :
=   '' ;
  isConntectd :
=   false ;
end;

constructor TCXXDJChannel160A.Create(
const  trunkEvent:TTrunkStatusEvent);
begin
  Self.OnChannelState :
=  trunkEvent;
  Self.FreeOnTerminate :
=   true ;
  inherited Create(
true );
end;


destructor TCXXDJChannel160A.Destroy;
begin
  Suspend();
  ChannelHangUp();
  
// inherited Destroy();
end;

function TCXXDJChannel160A.DialPhone(
const  DialPhoneNumber:PChar;
  
const  PreDialNumber:PChar): boolean;
begin
  isDialOut :
=   true ;
  phoneNumber :
=  DialPhoneNumber;
  OffHook(channelID);
  InitDTMFBuf(channelID);
  Result :
=  Sig_StartDial(channelID,DialPhoneNumber,PreDialNumber, 0 ) = 1 ;
  channelState :
=  atsCheckSendDial;
end;

function TCXXDJChannel160A.DialPhone(
  
const  DialPhoneNumber: PChar): boolean;
begin
  Result :
=  DialPhone(DialPhoneNumber, '' );
end;

procedure TCXXDJChannel160A.Execute;
begin
  
while  NOT Terminated  do
  begin
    Synchronize(ChannelProcessor);
    Sleep(
10 );
  end;
end;

function TCXXDJChannel160A.GetChannelID(): Word;
begin
  Result :
=  channelID;
end;

function TCXXDJChannel160A.GetChannelStatus(): TTrunkState;
begin
  Result :
=  channelState;
end;

procedure TCXXDJChannel160A.InformTrunkStatus(
const  aMsgFlag: TLVOperateFlag);
begin
  aTrunkState.lvFlag :
=  aMsgFlag;
  aTrunkState.TrunkID :
=  IntToStr(channelID);
  aTrunkState.TrunkType :
=  channelType;
  aTrunkState.TrunkTypeStr :
=  ChannelTypeString[channelType];
  aTrunkState.TrunkStep :
=  channelState;
  aTrunkState.TrunkStepStr :
=  TrunkStateString[channelState];
  aTrunkState.TrunkPhone :
=  phoneNumber;
  aTrunkState.TrunkData :
=  dtmfString;
  OnChannelState(aTrunkState);
end;

procedure TCXXDJChannel160A.ProcessCallInSuccess();
begin

end;

function TCXXDJChannel160A.SwitchOnCallIn(): boolean;
begin
  OffHook(channelID);
  InitDTMFBuf(channelID);
  StartSigCheck(channelID);
  channelState :
=  atsCallInSuccess;
  Result :
=   true ;
end;

procedure TCXXDJChannel160A.ProcessDialSuccess();
begin

end;

procedure TCXXDJChannel160A.CreateCommChannel(
const  aChennelID: Word);
begin
  channelID :
=  aChennelID;
  channelType :
=  TChannelType(CheckChType(channelID));
  ClearTrunkStatus();
  InformTrunkStatus(lvofAdd);
end;

function TCXXDJChannel160A.GetChannelType(): TChannelType;
begin
  Result :
=  channelType;
end;

function TCXXDJChannel160A.GetDialOut(): boolean;
begin
  Result :
=  isDialOut;
end;

procedure TCXXDJChannel160A.ProcessCheckDialSend();
begin
  
if (CheckSendEnd(channelID)  =   1 ) then
  begin
    StartSigCheck(channelID);
    channelState :
=  atsDialing;
  end;
end;

end.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Delphi之东进模拟语音卡(D160A)可复用源码 的相关文章

随机推荐

  • 【C语言编程】古典问题:韩信点兵

    题目 韩信有一队兵 xff0c 他想知道有多少人 xff0c 便让士兵排队报数 xff1a 按从1至5报数 xff0c 最末一个士兵报的数为1 xff1b 按从1至6报数 xff0c 最末一个士兵报的数为5 xff1b 按从1至7报数 xf
  • 【ChatGPT】使用ChatGPT进行51单片机程序编程体验

    背景 最近ChatGPT大火 xff0c 笔者尝试使用它进行了51单片机编程尝试 ChatGPT是一种由OpenAI训练的大型语言模型 xff0c 具有强大的自然语言处理能力和生成代码的能力 使用ChatGPT进行51单片机编程 xff0c
  • 【C语言】两个乒乓球队进行比赛,各出三人。甲队为a,b,c三人,乙队为x,y,z三人。排出比赛名单

    题目 两个乒乓球队进行比赛 xff0c 各出三人 甲队为a b c三人 xff0c 乙队为x y z三人 已抽签决定 比赛名单 有人向队员打听比赛的名单 a说他不和x比 xff0c c说他不和x z比 xff0c 请编程序找出三队赛手的名单
  • 【C语言】输出所有的水仙花数

    题目 输出所有的水仙花数 xff0c 所谓的 水仙花数 指一个3位数 xff0c 其各个数字的立方和等于该数本身 例如 xff0c 153是水仙花数 xff0c 因为153 61 1X1X1 43 5X5X5 43 3X3X3 思路 1 首
  • 【C语言】switch语句中的各case及default间顺序关系

    题目 xff1a switch语句中各个case和default出现先后次序不影响程序执行结果 本题目的答案有一定的争议性 xff0c 因为对于switch语句中 xff0c 各case和default的顺序是否对程序执行结果有影响还是取决
  • js实现节流和防抖

    代码实现 防抖 xff1a 就是指连续触发事件但是在设定的一段时间内中只执行最后后一次 xff0c 例如 xff1a 设定1000毫秒执行 xff0c 当你触发事件了 xff0c 他会1000毫秒后执行 xff0c 但是在还剩500毫秒的时
  • publisher与subscriber话题的消息类型md5sum不一致问题

    ERROR 1604235557 591296096 Client range vision fusion 01 wants topic detection vision objects to have datatype md5sum au
  • Ubuntu18.04下px4+MAVROSM+QGC地面站安装教程及避坑指南

    下面安装建立在已经安装好了ROS的基础 xff0c 未安装ROS的请先按照下面教程安装ROSROS 安装教程 目录 一 安装px4 toolchain 二 编译PX4固件 三 mavros and mavlink 安装 四 修改gazebo
  • Linux实用工具/软件

    一 录屏 Kazam 参考 xff1a Linux截图和屏幕视频录制软件Kazam 简书 二 播放器 VLC 推荐理由 xff1a 跨平台播放器 xff0c 支持H264等高清算法压缩格式 h264压缩比是200 1 xff0c 一般的第三
  • Ubuntu 安装boost

    boost是扩展的C 43 43 标准库 查看电脑默认安装的boost版本 xff1a dpkg S usr include boost version hpp 很多程序需要boost xff0c 但是版本可能不是ubuntu系统默认安装的
  • linux+python自动备份数据库

    linux 43 python自动备份数据库 1 在linux上安装mysqldump xff1a yum y install holland mysqldump noarch 2 编写python脚本 xff1a usr bin pyth
  • python基于Tkinter实现学生信息管理系统

    一 功能点介绍 xff08 毕设设计 xff09 1 添加学生成绩 xff1a 管理员可以在系统中添加学生的成绩信息 xff0c 包括学生姓名 学号 课程名称 成绩等 2 删除学生成绩 xff1a 管理员可以根据学生的学号或者姓名删除学生的
  • 感想京东

    xfeff xfeff 现在网上购物已经是家常便饭 xff0c 大多数人们都已接受了网购这种方式 xff0c 而能够给人们提供网购的网站也很多 xff0c 而我从好几年前就开始在京东网购物了 xff0c 因此京东商城的每一次发展 xff0c
  • 2014年度总结

    时光转眼即逝 xff0c 从还是懵懵懂懂的孩子一下子变成了已步入社会的工作者 回首2014年 xff0c 有欢乐 xff0c 有泪水 xff0c 有付出 xff0c 有收获等等 xff01 想起2014的自己还是一个刚步入工作岗位才半年 x
  • 将tensorflow训练好的模型移植到android

    将tensorflow训练好的模型移植到android上 说明 本文将描述如何将一个训练好的模型植入到android设备上 xff0c 并且在android设备上输入待处理数据 xff0c 通过模型 xff0c 获取输出数据 通过一个例子
  • FreeRTOS 启动第一个线程的步骤

    FreeRTOS 启动第一个线程的步骤 从main函数开始 初始化完成之后 通过SVC指令的中断函数来 初始化成需要的寄存器值 才能正常运行线程 1 启动第一个线程函数prvStartFirstTask 调用prvStartFirstTas
  • C#委托与事件的本质区别

    C 委托与事件的本质区别 从定义上说 xff0c 委托被编译器编译成一个类 xff0c 所以它可以像类一样在任何地方定义 xff0c 而事件被编译成一个委托类型的私有字段和两个公有add 和 remove 方法 xff08 有点类似于属性的
  • 文章千古事、得失寸心知

    文章千古事 得失寸心知 这些年 xff0c 读过的技术经典图书 成晓旭 xff1a 欢迎转载 行千里路 读万卷书 xff1b 历数十项目 编百万代码 十来年风雨IT路 xff0c 上百本沉寂专业书 佛说 xff1a 一花一世界 一叶一菩提
  • PX4+QGC+jmavsim软件在环仿真

    一 环境修改 参考官方手册jMAVSim 仿真模拟 PX4 Developer Guide xff0c 以上环境基于上一篇内容 xff0c 未完成ROS 43 jmavsim 43 QGC环境搭建的请移步Ubuntu18 04下px4 43
  • Delphi之东进模拟语音卡(D160A)可复用源码

    Delphi之东进模拟语音卡 D160A 可复用源码 作者 xff1a 成晓旭 Blog xff1a http blog csdn net cxxsoft 声明 xff1a 欢迎转载 xff0c 请保证文章的完整性 设计简介 xff1a 1