Chinaunix首页 | 论坛 | 博客
  • 博客访问: 101866046
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类: C/C++

2008-04-16 17:22:56

作者:陈国庆   
     本文提供了银行计算机网络报警系统触发控制的一种新方法 , 即外接报警开关 , 计算机内利用 COM 口监控报警开关状态 , 当报警开关被触发时计算机发出报警。 

     如今各银行通过计算机网络实现报警联动已经是很平常的事了 , 其报警触发方式较为常见的有两种 : 一是使用键盘 , 利用特殊键组合触发报警  二是在计算机内加上一块报警卡 , 外接报警开关 , 利用报警卡监测开关状态 , 当开关触动时触发报警。对这两种报警触发方式比较 , 报警卡方式要先进一些 , 当警况出现时 , 经常情况是歹徒强迫操作员举起双手 , 而一旦操作员双手被控 , 键盘方式将无法发出报警 , 但报警卡方式却仍可通过身体其他部位触动报警开关发出报警 , 因此 , 报警卡方式更为可靠。在日常应用中应优先选用报警卡方式。 

     但是 , 在报警卡方式中 , 报警卡要占用主板上一个卡槽 , 同时要占用一个中断及一个 I/O 地址 , 当计算机内插卡较多时容易与其他卡发生冲突 , 调整起来十分麻烦。那么 , 有没有其他的解决办法呢 ? 通过分析报警卡工作原理可以发现 , 在报警卡方式中报警卡并不是必需的 , 完全可以利用 COM 口实现报警卡的主要功能。 

    报警开关可用种类很多 , 特殊的如雷达深测式开关、红外感应式开关、脚踢式开关等 , 一般的普通开关也能用 , 但不管什么样的开关 , 在电路上其输出状态只有两种 : 通或断 , 逻辑上可定义其中一种状态为真、另一种为假。 

    " 接线盒 " 的功能就是将各 " 报警开关 " 并联起来 , 同时将各开关的合成状态通过其输出线传递给报警卡 , 是典型的多入一出设备。其输出逻辑为 :B=A1|A2|...|An, 式中 B 为 " 接线盒 " 的输出状态 ,A1 ~ An 为接在 " 接线盒 " 上各 " 报警开关 " 状态 , 定义报警态为真。 

    " 报警卡 " 主要的功能就是监控 " 接线盒 " 的输出状态 , 当 " 接线盒 " 输出为真时发出报警。由于 " 接线盒 " 在物理上的输出只有通、断两种 ," 报警卡 " 担负的任务是很简单的 , 可以通过对 COM 口的编程轻松地实现 " 报警卡 " 的主要功能。 

     本文提供了一个简单的模型 , 说明如下 : 

     模型中只有一个报警开关 ,COM 口通过信号线直接与报警开关连接 ," 信号线 " 使用普通的三芯双绞线即可 , 实际上只用到了其中的两根线芯 , 两根线芯的一端分别接在 COM 口的 2pin 和 3pin 上 , 另一端分别接在报警开关的两个输出端子上。 " 报警开关 " 用于操作员报警 , 本例中定义开关状态 " 通 " 为正常态、 " 断 " 为报警态 , 正常态定义为逻辑假、报警态定义为逻辑真 "COM 口 " 用于监控报警开关状态 , 这需要通过编程实现。 

     很显然 , 当报警开关为 " 通 ",COM 口的 2pin 和 3pin 也为联通状态 , 反之亦然。所以 , 程序中通过检测 COM 口 2pin 和 3pin 的通断状态即可判断报警开关的通断状态。 

     那么在程序中如何检测 COM 口 2pin 和 3pin 的通断状态呢 ? 我们知道 , 在 COM 口接口规范中 ,2pin 用于发送数据、 3pin 用于接收数据 , 因此我们可以定时从 2pin 发送数据 , 同时又从 3pin 接收数据 , 如果 3pin 能够接收到数据并且接收到的数据与 2pin 发送的数据一致 , 则可以判断 2pin 和 3pin 是联通的 , 反之则是断开的。另外 , 在 UNIX 系统中用户程序不能直接访问 COM 口 , 但可通过打开相应设备文件实现对 COM 口的间接访问。以 SCO UNIX 为例 , 设备文件 /dev/ttyla 指向的就是 COM 口 , 对 /dev/ttyla 的访问即是对 COM 口的访问 , 这一点在编程中需要注意。本文采用的是 C 语言 , 运行环境为 SCO UNIX Openserver 3.0 。 

     顾名思义 , 显示 /dev/ttyla 是终端设备 , 我们可以通过 UNIX 提供的多个 ioct1 ommands 系统调用对其进行控制 , 程序中需要用到的结构变量 termio 在 usr/include/sys/temio.h 头文件中定义。 termio 具体结构如下 : 

    #define NCC 8 

    struct termio { 

    unsigned short c_iflag; /* 输入模式  */ 

    unsigned short c_oflag; /*  输出模式  */ 

    unsigned short c_cflag; /*  模式控制  */ 

    unsigned short c_1flag; /*  行律模式 */ 

    char 

     c_1ine; /*  行律  */ 

    unsigned char c_cc[NCC];/* 控制字  */ 

    }; 

    termio 的 ioct1 调用格式很多 , 下面只简要介绍程序用到的格式 : 

    ioct1(fildes,command,arg) 

    struct termio *arg; 

     其中 command 参数有下列可用值 : 

    TCGETA  获取终端当前参数并将返回值保存在参数 arg 中  

    TCSETA  立即将终端参改变为 arg 中的值  

    TCSETAW  等待终端输出队列为空后将终端参数改变为 arg 中的值。 

    TCSETAF  等待终端输出队列为空后 , 清空输入队列 , 同时将终端参数改变为 arg 中的值。 

     程序每隔 5 秒种向 COM 口 2pin 发送字符 "@", 同时从 3pin 读取字符 , 读取成功则认为 2pin 和 3pin 为联通态 ( 即正常态 ), 反之为断开态 ( 报警态 ) 。为正常态时程序在控制终端上显示 "Alarm is off", 为报警态时则显示 "Alarm is on" 。程序稍加改动后加上网络传输部分即可实现网络报警联动。 

     程序清单如下 : 

    #include 

    #include 

    #include 

    #include 

    #include 

    int AlarmPort=-1; 

    struct termio PortBuf; 

    char PortBXName[20]="/dev/ttyla"

    void Alarm_d() 

    { 

    int flag,fork_ret=256; 

    charch; 

    signal(SIGALRM,Alarm_d); 

    if (!fork()) 

    {ch="@"

    flag=SEND_BYTE(AlarmPort,ch); 

    if (flag==0) exit(0); 

    else exit(1); 

    } 

    flag=RECEIVE_BYTE(AlarmPort.&ch); 

    if (flag==0 ‖ ch!="@") flag=0; 

    else flag=1; 

    wait(&fork_ret); 

    if (flag==0 ‖ fork_ret==0) 

    prinft("Alarm is on !\n"); 

    else 

    prinft("Alarm is off !\n"); 

    alarm(5);pause(); 

    } 

    /* 打开并初始化端口 , 返回端口文件句柄  */ 

    /* struct termio ComBuf: 保存端口参数用于关闭端口时恢复  */ 

    int INIT_PORT(char *PortName,struct termio * 

    ComBuf) 

    { 

    int fp,i; 

    struct termio tbuf1; 

    if 

    ((fp=open(PortName,O_RDWR|O_NDELAY))|<0){ 

    prinft("\n can not open prot[%s]\n",PortName); 

    fflush(stderr); 

    return(-1); 

    } 

    ioct1(fp,TCGETA,ComBuf); 

    ioct1(fp,TCGETA,&tbuf1); 

    tbuf1.c_iflag=0; 

    tbuf1.c_oflag=0;&= ~ OPOST; 

    tbuf1.c_cflag=0;&= ~ (CBAUD|CSIZE|PARENB); 

    tbuf1.c_cflag=0;=tbuf1.c_cflag|(B9600|CS8|CREAD|CLOCAL); 

    tbuf1.c_1flag=0;&= ~ (ICANON|ISIG|ECHO); 

    tbuf1.c_cc[VMIN]=1; 

    tbuf1.c_cc[VTIME]=0; 

    ioct1(tp,TCSETAF,&tbuf1); /* 设置端口参数  */ 

    return(fp); 

    } 

    /* 关闭端口并恢复端口原参数  */ 

    int CLOSE_PORT(int ComPort,struct termio *ComBuf) 

    { 

    ioct1(ComPort,TCSETAF,ComBuf); 

    close(ComPort); 

    return(0); 

    } 

    /*  从端口接收一字节 , 最大等待时间 2 秒 */ 

    int RECEIVE_BYTE(int ComPort,char *c) 

    { 

    int received; 

    time_t t1,t2; 

    longdiftiom; 

    t1=time(NULL); 

    do{ 

    received=read(ComPort,c,1); 

    t2=time(NULL); 

    diftim=(long)difftime(t1,t2); 

    if (diftim<0) diftim=-diftim; 

    }while((received<1)&&(diftim<(long)2)); 

    if (received<1) 

    received=0; 

    return(received); 

    } 

    /* 从端口发送一字节 , 最大等待时间 2 秒 */ 

    int SEND_BYTE(int ComPort,char c) 

    { 

    int sent; 

    time_t t1,t2; 

    longdiftim; 

    t1=time(null); 

    do{ 

    sent=write(ComPort,&c,1); 

    t2=time(NULL); 

    diftim=(long)difftime(t1,t2); 

    if (diftim<0)diftim=-diftim; 

    }while((sent<1)&&(diftim<(long)2)); 

    if (sent<1) 

    sent=0; 

    return(sent); 

    } 

    /* 与端口连接 , 返回值 :0- 成功  1- 失败 */ 

    int Connect(char *PortName) 

    { 

    if(AlarmPort<0){ 

    AlarmPort=INIT_PORT(PortName,&PortBuf); 

    if (AlarmPort<0){ 

    return(1); 

    } 

    } 

    return(0); 

    } 

    /* 与端口断开连接 */ 

    voidDisConnect() 

    { 

    int flag; 

    if(AlarmPort>0){ 

    CLOSE_PORT(AlarmPort,&PortBuf); 

    AlarmPort=-1; 

    } 

    return; 

    } 

    main() 

    { 

    charflag; 

    voidDisConnect(); 

    flag=Connect(PortBXName); 

    if (flag!=0) { 

    printf("\nChecker connect failed!\n"); 

    return(flag); 

    } 

    signal (SIGTERM,DisConnect); 

    Alarm_d(); 

    } 
阅读(252) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~