GPRS-串口数据透明传输

 2011-2-23         

        GPRS通讯和串口通讯都是工控领域使用极为频繁的数据传输方式,而实际工程中经常需要在GPRS和串口之间进行数据的透明传输,即:将串口终端设备传输过来的各种数据通过GPRS发送到另一设备,或者将GPRS终端设备传输过来的数据通过串口转发。利用英利开发资料光盘中的GPRS、以太网和串口示例程序,可以很容易地开发这样一个GPRS-串口数据透明传输的应用例程。

 

        在英利开发资料光盘的“应用开发软件”-“典型应用”中,有一个名为“gprs232”的文件夹,就是GPRS-串口数据透明传输的示例工程文件。该例程包括了串口、以太网和GPRS操作,以多线程方式实现,程序流程如下:
        1、初始化串口并启动串口数据处理线程
        2、打开GPRS并建立连接
        3、建立TCP连接,启动网络数据处理线程并进行数据透明传输

 

1、准备工作

        在测试和使用该例程之前,需进行如下准备工作:

 

        1、将英利工控主板的调试串口连接到开发主机,然后将英利工控主板的串口ttyS2(程序默认。如果使用其他串口,请参照程序代码,在命令行带入相关参数)与实验用PC机的串口连接(开发主机的COM1往往和英利工控主板的调试串口连接,用于通过超级终端操作英利工控主板。因此如果开发主机还有一个完好的串口,可以将此串口连接到ttyS2;否则建议客户另找一台PC机连接ttyS2,以便于测试该例程。本文中的“实验用PC机”就是指连接ttyS2的PC机)。

 

        2、将实验用PC机、开发主机和英利工控主板都接入实验室内网,并确保实验室内网和公共局域网的连接都正确无误。

 

        3、将ETA300与英利工控主板连接好,将实验用SIM卡装在ETA300上面。

 

        4、将英利工控主板/mnt/nandflash文件夹下userinfo.txt文件中的默认网关改为0,即如下:
              DefaultGateway='0'
              如果不进行这个修改,则系统默认会通过以太网,而非GPRS传输数据。

 

        5、通过实验室的网关路由器,为实验用PC机分配一个端口,并记下该网关路由器的外网IP地址。

 

        6、将英利开发资料光盘“工具软件”中的“串口调试助手”和文件夹“TCPTest_Linux”复制到实验用PC机上,启动串口调试助手和“TCPTest_Linux”中的TCPTest。TCPTest启动以后将套接字类型选择为服务器,服务器名称填入实验用PC机的内网IP地址,服务器端口填入之前为实验用PC机分配的端口号,然后选择侦听,如下图所示。

 

GPRS-串口数据透明传输TCP服务器

 

2、例程测试

        以上6步准备完毕以后,在开发主机上启动超级终端,为英利工控主板上电,启动sourcery g++并编译gprs232工程文件,通过超级终端将应用程序下载到英利工控主板的/mnt/nandflash文件夹中,并输入如下命令运行程序:
        [root@EM9X60 /mnt/nandflash]#  ./gprs232  50

 

        由于GPRS模块首次上电连接速度可能比较慢,因此此处设置了参数50(等待50秒。该项设置与用户使用的SIM卡有关。如果50秒以后仍然无法连接,可以将这个时间再加长)。一旦首次连接成功以后,只要不断开电源,再次运行该程序的时候可以不设置这个参数,直接如下运行即可:
        [root@EM9X60 /mnt/nandflash]#  ./gprs232

 

        此后系统自动进行初始化和连接,过程中用户可以看到ETA300上的SYNC灯闪动,表示找到SIM卡以及连网,同时超级终端会显示相应的运行信息。连接成功以后,超级终端最后一行信息显示:TCP Connect Success;同时,实验用PC机上TCP Test的消息栏也从不可编辑的灰色状态变为可以输入信息状态,如下图所示。

 

GPRS-串口数据透明传输TCP服务器

 

        此后通过串口调试助手发送信息,可以看到信息显示在TCP Test的“接收的信息”栏中,通过TCP Test发送的信息则显示在串口调试助手的接收区中。发送/接收数据的过程中,ETA300的SYNC灯会闪动,表示数据正通过GPRS发送/接收。如果SYNC灯没有闪动,则数据并不是通过GPRS发送/接收。此时需检查userinfo.txt的默认网关是否配置为0。

 

3、程序说明

        该例程的主程序参见光盘中的源文件。本例程以多线程方式实现,串口、TCP数据收发由各自独立的线程完成,这样不但能够充分发挥嵌入式Linux多任务操作系统的优势、实时处理数据,同时有利于减少系统开销、提高系统资源利用效率。其中主程序部分需要用户自行填写参数的是以下两个地方:

        // 此处填写网关路由器的外网IP地址
        strcpy( ServerIP, '222.212.15.128' );
        // 此处填写通过实验室的网关路由器为实验用PC机分配的端口号
        TCPClntManager.AddTCPClientObject( ServerIP, 7051 );

 

        数据处理分别在串口数据处理线程ReceiveThreadFunc和TCP数据处理线程SocketThreadFunc中进行。

 

        串口部分:

        // 声明外部变量TCPClntManager类
        extern class CTCPClientManager TCPClntManager;

        int CSerial::ReceiveThreadFunc(void* lparam)
        {
                // 得到CSerial实例指针
                CSerial *pSer = (CSerial*)lparam;
                .
                .
                .
                if (ret > 0)
                {
                        // 判断是否读事件
                        if (FD_ISSET(pSer->m_fd,&fdRead))
                        {
                                // data available, so get it! 
                                pSer->m_DatLen = read( pSer->m_fd, pSer->DatBuf, 100 );
                                // 接收串口数据处理函数
                                if( pSer->m_DatLen > 0 )
                                {
                                        pSer->PackagePro( pSer->DatBuf, pSer->m_DatLen );
                                }
                                // 处理完毕
                        }
                }
        }

        // 接收串口数据处理函数
        int CSerial::PackagePro( char* Buf, int len )
        {
                // 将接收的数据发送至TCP服务器
                CTCPClient* pTCPClnt;
                Buf[len] = 0;

                // 检测TCP连接是否打开
                if( TCPClntManager.m_TCPClientInfo[0].ConnState == csOPEN )
                {
                        pTCPClnt = (CTCPClient*)TCPClntManager.m_TCPClientInfo[0].pTCPClient;
                        // 调用CTCPClient类的发送函数将串口接收到的数据发送到TCP服务器
                        pTCPClnt->SendData( Buf, len );
                } 
                return 1;
        }

 

        TCP部分:

        // 声明外部变量CSerial类
        extern class CSerial m_Serial;

        // TCP数据处理线程
        int CTCPClient::SocketThreadFunc( void* lparam )
        { 
                CTCPClient *pSocket;
                // 得到CTCPClient实例指针
                pSocket = (CTCPClient*)lparam;
                .
                .
                .
                if (ret > 0)
                {
                        .
                        .
                        .
                        else
                        {
                                // 对接收的数据进行处理
                                pSocket->RecvBuf[pSocket->m_nRecvLen] = 0;
                                // printf( 'RCV:%s\n', pSocket->RecvBuf);
                                // 调用CSerial类的发送函数将GPRS接收到的数据发送到串口调试助手 
                                m_Serial.WritePort( pSocket->RecvBuf, pSocket->m_nRecvLen );
                                // pSocket->SendData( pSocket->RecvBuf, pSocket->m_nRecvLen );
                                // 处理完毕
                        }
                }
        }