GSM调制解调器响应太晚

时间:2015-11-16 07:14:46

标签: c++ serial-port gsm

我有一个gsm调制解调器,设置为:
 1. BaudRate 9600
 2.数据仓8
 3.无奇偶性  4.停止1  5.无流量控制
我的Os是Ubuntu。在发送AT命令后,我写了睡眠(2)秒来接收答案。但为什么反应太晚了?我怎么解决呢? 这是我读取数据的代码:

string PDUSMS::readstring(int fd)
{
    int n = 0,
        spot = 0;
    char buf = '\0';
    /* Whole response*/
    char response[1024];
    memset(response, '\0', sizeof response);
    n=read(fd,&response,1024);
//---------------------------
    if (n < 0) {
        std::cout << "Error reading: " << strerror(errno) << std::endl;
    }
    else if (n == 0) {
        std::cout << "Read nothing!" << std::endl;
    }
    else {
        std::cout << "Response: " << response << std::endl;
    }
    string str(response);
    return str;
//---------------------------------------------------
}

如何快速阅读。读取所有响应字符串?
这是我的全部代码:

int fd; /* File descriptor for the port */
/*
    * 'open_port()' - Open serial port 1.
    *
    * Returns the file descriptor on success or -1 on error.
    */

    int openport(void)
    {

        fd=open("/dev/ttyS1",O_RDWR|O_NOCTTY|O_NDELAY);
        if (fd==-1)
        {
            perror("open_port: unable to open port\n");
            return -1;
        }
        else
        {
            printf("open_port: succesfully open port /dev/ttyUSB0\n");
            fcntl(fd,F_SETFL,0);
            return 1;
        }
    }
   //========================================================================

   void closeport(void)
   {
       close(fd);
   }

   void configport(void)
   {

       struct termios tty;
       struct termios tty_old;
       memset (&tty, 0, sizeof tty);

       /* Error Handling */
       if ( tcgetattr ( fd, &tty ) != 0 ) {
          std::cout << "Error " << errno << " from tcgetattr: " << strerror(errno) << std::endl;
       }

       /* Save old tty parameters */
       tty_old = tty;

       /* Set Baud Rate */
       cfsetospeed (&tty, (speed_t)B9600);
       cfsetispeed (&tty, (speed_t)B9600);

       /* Setting other Port Stuff */
       tty.c_cflag     &=  ~PARENB;            // Make 8n1
       tty.c_cflag     &=  ~CSTOPB;
       tty.c_cflag     &=  ~CSIZE;
       tty.c_cflag     |=  CS8;

       tty.c_cflag     &=  ~CRTSCTS;           // no flow control
       tty.c_cc[VMIN]   =0;//  1;                  // read doesn't block
       tty.c_cc[VTIME]  = 2;// 5;                  // 0.5 seconds read timeout
       tty.c_cflag     |=  CREAD | CLOCAL;     // turn on READ & ignore ctrl lines

       /* Make raw */
       cfmakeraw(&tty);

       /* Flush Port, then applies attributes */
       tcflush( fd, TCIFLUSH );
       if ( tcsetattr ( fd, TCSANOW, &tty ) != 0) {
          std::cout << "Error " << errno << " from tcsetattr" << std::endl;
       }
   }
//------------------------------------------------------------  
string PDUSMS::SendandReciveData(string s,int fd)
{

  int i;
  string o,e,t;

  try
  {
    cout<<" we had sent:"<<s<<"\n";
    SendString(s,fd);


        sleep(1);
        o=readstring(fd);
//    for(int i=0;i<3;i++)
//     if (o.find(s)!=-1)
//     {
//         sleep(1.5);
//         o=readstring(fd);
//     }
    cout<< " we got :"<<o<<"\n";
    i = StateStr(o, s); //remove source command from the beging of string
    if (i >= 0)   //-becasause the command return back to us
      o = copy(o, s.length(), o.length() - s.length()); //return command to caller

  }
  catch(const std::exception&)
  {
    o = " ";
  }
  return o;

}

void PDUSMS::SendString(string s,int fd)
{
    char buf[255];
    strcpy(buf,s.c_str());
    write(fd, buf, s.length());
//    usleep(500);
}

string PDUSMS::readstring(int fd)
{
    int n = 0,
        spot = 0;
    char buf = '\0';

    /* Whole response*/
    char response[1024];
    memset(response, '\0', sizeof response);


    n=read(fd,&response,1024);
//---------------------------
    if (n < 0) {
        std::cout << "Error reading: " << strerror(errno) << std::endl;
    }
    else if (n == 0) {
        std::cout << "Read nothing!" << std::endl;
    }
    else {
        std::cout << "Response: " << response << std::endl;
    }
    string str(response);
    return str;
//---------------------------------------------------
}
bool PDUSMS::SendSMS(int fd,string Num,string Text,int MR,int CMR,int SMS_PART,int sms_id,int &sms_index,bool Delivery,bool MagicSMS,bool &Deliverd)
{

  string c, o, id;
  int i, l, Curr_PART, R_MR;
  string SNum, SDate, STime, PDU_Data, SMSC_Num, RTime, RDate, num1;
  ReceievedMessageKind PDU_Data_Type;
  bool sent, deliv;

  string Temp;
    MagicSMS=false;
    string result=" ";
    result=SendandReciveData("AT+CSMP=49,167,0,0\r",fd);
    result=SendandReciveData("AT+CNMI=2,2,0,1,0\r",fd);

    c = "AT+CMGS="; // at commmand for s} SMS
    o = EncodePDU(Num, Text, MR, CMR, SMS_PART, sms_id, Delivery, MagicSMS);

    c = c + IntToStr(o.length()/ 2 - 1); //Adding length of Pdu to at command
    c += "\r"; //adding <CR> to at comm &&
    Temp = SendandReciveData(c,fd); //send at command to phone
    o += (char)26; //add <CTRL-Z> to the PDU Text

    Temp = SendandReciveData(o,fd); //S} Text To The Phone

}

这是我没有睡觉的输出:

  

open_port:成功打开我们发送的端口/ dev / ttyUSB0:AT   回复:我们得到了:AT ATAT我们发送了:AT回复:

     我们得到了:

     

我们发送了:AT响应:我们得到了:O OO我们发送了:AT响应:K   我们得到了:K KK我们发送了:AT回复:

     我们得到了:

     

我们发送了:AT响应:我们得到了:我们发送的AA:AT响应:T   我们得到了:T TT我们已发送:AT响应:我们得到了:我们发送了:AT   回复:我们得到了:我们发送的AA:AT响应:我们得到了:T TT我们   已发出:AT Aesponse:Awe得到了:A我们已发送:AT回应:我们得到了   :T TT我们已发送:AT ATsponse:ATe得到:我们已发送:AT响应:A   我们得到了:我们发送的AA:AT响应:我们得到了:我们已经发送了:AT   回复:好的

     

我们得到了:好的

     

     

好的,我们已发送:AT + CSMP = 49,167,0,0回应:我们得到了:我们有   发送:AT + CNMI = 2,2,0,1,0回复:

     我们得到了:

     

我们已发送:AT + CMGS = 20响应:确定

     

好的,我们得到了:好的

     

好的,我们已发送:0031010c918939881454270000AA06f3701bce2e03回复:   我们得到了:回复:

     

O响应:K A响应:T Aesponse:AT响应:T响应:   响应:T响应:响应:T响应:响应:AT + CS   回复:MP = 49回应:,167,响应:0,0回复:T + CN回复:   MI = 2,响应:2,0,1响应:,0响应:+ CMGS响应:= 20   回应:00310回复:10c91893回复:98回复:81454   事故响应:2700回应:00AA0回复:6f370回复:1bce2   回复:e03回复:OK回复:

     

回复:确定回复:

     

确定回复:

     

回复:好的

     

回复:好的

     

回复:确定回复:

     

确定回复:

     

回复:好的

     

回复:好的

     

回复:确定回复:

     

确定回复:

     

回复:好的

     

回复:好的

     

回应:

     
    

回应:回复:     + CUSD响应:: 0,“响应:Hazin响应:e SM响应:S:2响应:0响应:9 Ria响应:l。响应:ebar响应:     asl回复:我回复:: 13623里亚尔。 Shegeftzad回复:嗯嘘     回复:狂热回应:!回应:回复:Ba s回应:homar     回复:e g响应:i回复:ry c响应:o响应:de * 44     回复:44 * 1#响应:tarh响应:e v响应:i响应:je     kh响应:od r响应:响应:dar响应:y响应:aft     k响应:oni响应:d响应:“,15响应:

  
     

响应:   + CM响应:G响应:S:21响应:8

     

O响应:K响应:响应:

     

回应:

     

回复:+ CUSD:回复:2

     

回应:

     

回复:+ CDS:回复:25

     

响应:0响应:006D响应:响应:0C9响应:1   回应:8939回复:8回复:8145回复:4回复:2751   回复:1回复:16131回复:016回复:3回复:4151   回复:1回复:1613回复:1回复:0183回复:4   回复:100回复:

2 个答案:

答案 0 :(得分:1)

输出似乎表明存在命令回声。要么在调制解调器处关闭回声,要么准备好为每个写入的命令读取2行。

您具有非规范(又称原始)模式的串行端口设置。原始读取由字节计数和/或定时终止,这对于读取行是不可靠的。当调制解调器处于命令模式时,调制解调器将其响应作为行发送。

所以你的程序需要从调制解调器读取一行(这是规范输入)。 (a)将read()放在一个循环中,该循环连接输入,直到收到行终止符, OR (b)设置规范输入而不是raw。

原始模式

为了使用非规范模式可靠地读取行,程序应该处理在返回缓冲区中间接收到的行终止符的最坏情况(而不是接收到的最后一个字符的普通情况) 。为了处理这个问题,必须在读取系统调用之间保持静态缓冲区以保持部分接收的行,并在&#34; next&#34;的行终止符之后保留输入。线。

static char response[1024] = {0};
static int offset = 0;

string PDUSMS::readline(int fd)
{
    int n;
    char line[1024];
    char *nlp;

    while ((nlp = strpbrk(&response[offset], "\n\r")) == NULL) {
        n = read(fd, &response[offset], sizeof(response) - offset - 1);
        if (n < 0) {
            std::cout << "Error reading: " << strerror(errno) << std::endl;
            continue;
        }
        offset += n;
        response[offset] = '\0';
        if (offset >= sizeof(response) - 1) {
            nlp = &response[offset - 1];
            break;
        }
    }
    std::cout << "Response: " << response << std::endl;

    /* extract a line from the buffer */
    strncpy(line, response, nlp - response + 1);
    line[nlp - response + 1] = '\0';
    /* move remnant string to beginning */
    strcpy(response, nlp + 1);
    offset = strlen(response);

    string str(line);
    return str;
}

注意:代码未经测试,基本上是C.我不了解C ++。

规范模式

根据 termios(3)的Linux手册页

  

在规范模式中:

     
      
  • 输入逐行可用。键入其中一个行分隔符时可以使用输入行(NL,EOL,EOL2;或EOF开头)   线)。除EOF外,行分隔符包含在read(2)返回的缓冲区中。

  •   
  • 启用行编辑(ERASE,KILL;如果设置了IEXTEN标志:WERASE,REPRINT,LNEXT)。 read(2)最多返回一行输入;如果read(2)请求的字节数少于当前输入行中可用的字节数,则只读取所请求的字节数,其余字符将可用于将来的读取(2)。

  •   

要在命令模式下为调制解调器配置规范模式的串行端口(而不是通用终端输入),在 configport()中删除三个语句(及其注释):

    tty.c_cc[VMIN]   =0;//  1;                  // read doesn't block
    tty.c_cc[VTIME]  = 2;// 5;                  // 0.5 seconds read timeout

   /* Make raw */
   cfmakeraw(&tty);

(务必保留CREAD | CLOCAL设置。)
并插入新的陈述:

    tty.c_iflag |= ICRNL | IGNBRK;
    tty.c_iflag &= ~(IXON | IXOFF | IXANY | INLCR);

    tty.c_lflag |= ICANON | ISIG  | IEXTEN;
    tty.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ECHOKE);

readstring()中的read()调用将返回完整的输入行(包括&#39; \ n&#39;字符)。如果调制解调器使用&#39; \ n&#39;来终止其线路。然后要小心这个配置会引入一个空白行(因为每个&#39; \ r&#39;都会被转换为&#39; \ n&#39;)。 / p>

请注意,当您的程序将调制解调器从命令模式切换到透明模式时,规范模式可能不合适。如果数据不是纯ASCII文本但包含二进制值,则程序应在调制解调器切换模式时将端口切换到原始模式。

有关参考指南,请参阅 Serial Programming Guide for POSIX Operating Systems
Setting Terminal Modes Properly

答案 1 :(得分:0)

一般来说,有关AT命令的一些建议对于在编写一行代码之前了解很有用:

    默认情况下,
  1. 调制解调器已启用回显。在设计应用程序时要考虑到这一点,特别是如果您决定逐行读取而不是实现正常的读取超时时间。

    为了禁用回显,请向调制解调器提供“ ATE0”命令

  2. AT + CMGS具有以下行为:

    • 主机发送“ AT + CMGS =”
    • 调制解调器立即发送提示字符('>')
    • 主机发送PDU或以CTRL + Z字符终止的文本
    • !一段时间取决于网络!
    • 确定

因此,不要以为立即收到OK。甚至可能要花几十秒!

  1. 您花了一些力气以PDU模式发送SMS,但也可以使用TEXT模式:
    • AT + CMGF = 1(为了切换到文本模式)
    • AT + CMGS =
      “>”待发送文本