Перейти к содержанию
    

SIM900. Прием команд от TCP сервера.

А как обходите, просто конечный автомат парсера настраиваете на поиск ">" без обрамления \r\n?

Да, ожидаю с таймаутом:

 

       case While_Prigl: if ((Bufer_Rx_GPRS[0] == '>') && (Bufer_Rx_GPRS[1] == ' ')) { Main_cicle = Send_String3;}
                else if ((Ticks_20ms - curTicks) > 10)  Main_cicle = Power_off; 
                         break;

Изменено пользователем alexdos

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не-а. Надо сначала "пропихнуть" автомат в следующее состояние, которое будет ждать прихода именно Ок.

 

Вот - http://www.delphisources.ru/forum/showthread.php?t=6547 Обратите внимание, что case намного прозрачнее if. Но это его удобство, проще читать код, все видно хорошо.

А ссылку на статью давал, там есть рисунки с кодами автомата. Для возвртата в исходное состояние используется оператор goto. И под каждым case устанавливается следующее состояние.

Короче, все просто оказалось, но намучился с этим всем конкретно, когда шел не автоматным путем.

Да я ж говорю, что тоже на автоматах всё у меня

            case 0:
                ExtraBufferCopyFlag = 1; //флаг копирования нужного фрагмента буфера (со смещением)
                send_command0(CIPSTATUS);                
                gprsstate++;
                response_timeout=2000;
                break;
            case 1:
                if (!response_wait) { //если дождались ответа
                    switch (response_code) {
                        case 15: // INITIAL STATE
                            gprsstate++;
                            ready_to_send=0;
                            break;
                        case 17: // PDP DEACT STATE (Отключен сетью)
                            gprsstate = 100; //закрываем все подключения
                            ready_to_send=0;
                            break;
                        case 16: //TCP CLOSED
                            gprsstate = 12;
//                            gsm_delay=300;
                            ready_to_send=0;
                            break;
                        case 18: //CONNECT OK
                            gprsstate = 20;
                            send_flag=1;
                            break;
                        case 20: //CONNECTING
                            gprsstate = 30;
                            break;
                        case 3:
                            gprsstate=30;
                            break;
                    }
                }

Ну и так далее.

 

Тоже определял конец строки по таймауту. Работало.

Потом перешел по \r\n. По \r\n оказалось более работоспособно, и нет никакой необходимости в знании сколько их будет в ответе. К примеру посмотрим на строку \r\nOK\r\nблаблабла\r\n, по первому \n мы видим что это начало строки (так как количество принятых байтов равно 2). По второму получаем ответ OK. По третьему получаем ответ блаблабла. Поэтому при разборе ответов, задача сводится к проверке "наборов байтов находящихся между \r\n". Единственное что портит всю картину это приглашение к вводу данных "> ", но и это обходится очень просто.

 

Это Вы в прерывании всё делаете? Если так, то приличный такой обработчик в прерывании будет крутиться. А если нет, тогда опять не ясно, как конец сообщения определить?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это Вы в прерывании всё делаете? Если так, то приличный такой обработчик в прерывании будет крутиться. А если нет, тогда опять не ясно, как конец сообщения определить?

Да нет, в прерывании я мало что делаю

/* завершим текстовую строку*/
           if(Bufer_Rx_GPRS[Count_Byte_Rx_GPRS - 1] == '\r')
                      {
                         Bufer_Rx_GPRS[Count_Byte_Rx_GPRS - 1] = 0;
                         strncpy(Bufer_Rx_GPRS_Parser, Bufer_Rx_GPRS, Count_Byte_Rx_GPRS);    /* скопируем строку в буфер парсера*/
                        }
                     else 
                      {
                         Bufer_Rx_GPRS[Count_Byte_Rx_GPRS] = 0;
             strncpy(Bufer_Rx_GPRS_Parser, Bufer_Rx_GPRS, Count_Byte_Rx_GPRS + 1);    /* скопируем строку в буфер парсерв*/                            
                        }

           Count_Byte_Rx_GPRS = 0;
           GPRS_rxgap = 1;                        
                  }    
                 else Bufer_Rx_GPRS[Count_Byte_Rx_GPRS++] = GPRS_Byte_in; /* принятый байт сохраним в приемный буфер */
         if (Count_Byte_Rx_GPRS >= 512) Count_Byte_Rx_GPRS = 0;
        }

Изменено пользователем alexdos

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Мне как раз мультисокет и не нужен, мне достаточно одного соединения. Значит ли это, что мне лучше воспользоваться прозрачным режимом?

И второе. Намекните, если можно, про устройство Вашего оптимизированного парсера. Как он работает?

В прозрачном режиме проще: могут придти только данные.

Устройство парсера

typedef enum  
{
  ANSWER_PARAM_TYPE_UNKNOWN  =0,   // Тип параметра не определился
  ANSWER_PARAM_TYPE_STRING   =1,   // Строка выделенная кавычками
  ANSWER_PARAM_TYPE_CONSTANT =2,   // Строка - константа, заменяем на значение их дефйна
  ANSWER_PARAM_TYPE_INTEGER  =3,   // Целое 
  ANSWER_PARAM_TYPE_LIST     =4,   // Список возможных значений - строка в круглых скобках
  ANSWER_PARAM_TYPE_COMMAND  =5    // Заголовок-опознаватель команды
} TEnum_AnswerParamType;

typedef struct
{
  TEnum_AnswerParamType ParamType;
  uint8_t IsCmd;
  char* Value;
  uint16_t IntVal;
  uint16_t Len;
} TStruct_AnswerParam;
char* GetAnswerParam(char * Buf, TStruct_AnswerParam *AnswerParam);

На вход подается указатель на входную строку и на заполняемую структуру. На выходе возвращает указатель на следующий за последним обработанным байт. Можно вызывать циклически для разбора всей команды. CR LF заменяется на \0.

char* GetAnswerParam(char * Buf, TStruct_AnswerParam *AnswerParam)
{
  AnswerParam->ParamType = ANSWER_PARAM_TYPE_UNKNOWN;
  AnswerParam->IsCmd = 0;
  int8_t BracketCnt=0;
  int8_t QuotesCnt=0;

  uint8_t FlagNewParam=1;
  uint8_t FlagCmd=0;

  uint16_t Len=0;
  char tmp;

  Buf=ReMapRxBufferPoint(Buf);
  AnswerParam->IntVal = 0;
  AnswerParam->Value =Buf;

  do
  {
     switch (*Buf)
     {
        case ':':
           FlagCmd=1;
           break;
        case ' ':
           if (FlagCmd)
           {
              AnswerParam->IsCmd=1;
              Buf++;
              Buf=ReMapRxBufferPoint(Buf);
           }
           else
           {
              FlagCmd=0;
              break;
           }
           Len++;
        case ',':
           if ((BracketCnt)||(QuotesCnt%2))
           {
              FlagCmd=0;
              break;
           }
        case 0:
        {
           if ((AnswerParam->ParamType == ANSWER_PARAM_TYPE_LIST)&&BracketCnt)
              AnswerParam->ParamType = ANSWER_PARAM_TYPE_UNKNOWN;
           if ((AnswerParam->ParamType == ANSWER_PARAM_TYPE_STRING)&&(*ReMapRxBufferPoint(Buf-1)!='\"'))
              AnswerParam->ParamType = ANSWER_PARAM_TYPE_UNKNOWN;

        if ((AnswerParam->ParamType == ANSWER_PARAM_TYPE_CONSTANT)||(AnswerParam->ParamType == ANSWER_PARAM_TYPE_STRING))
           {  

              if (AnswerParam->IsCmd)
                 Len-=2;
              AnswerParam->IntVal=0;
              AnswerParam->Len=Len;
              for (uint8_t i=1; i<(sizeof(strCmdArray)/sizeof(strCmdArray[0])); i++)
              {
                 if (AnswerParam->ParamType == ANSWER_PARAM_TYPE_CONSTANT)
                 {
                    if (Len == strCmdArray[i].Len)
                       if (CompareStrFStr(AnswerParam->Value, strCmdArray[i].Val))
                       {
                          AnswerParam->IntVal = strCmdArray[i].Code;
                          break;
                       }
                 }
                 else
                 {
                    if (Len-2 == strCmdArray[i].Len)
                       if (CompareStrFStr(AnswerParam->Value+1, strCmdArray[i].Val))
                       {
                          AnswerParam->IntVal = strCmdArray[i].Code;
                          break;
                       }
                 }

              }

              if (AnswerParam->IntVal == 0)
              {


              }

           }
           return Buf;
        }
        case '(':
        {
           if (FlagNewParam)
           {   
              AnswerParam->ParamType = ANSWER_PARAM_TYPE_LIST;
              AnswerParam->Value = Buf;
           }
           if ((AnswerParam->ParamType == ANSWER_PARAM_TYPE_INTEGER)
              ||(AnswerParam->ParamType == ANSWER_PARAM_TYPE_CONSTANT))
              AnswerParam->ParamType = ANSWER_PARAM_TYPE_UNKNOWN;

           BracketCnt++;
           break;
        }
        case ')':
        {
           if ((AnswerParam->ParamType == ANSWER_PARAM_TYPE_INTEGER)
              ||(AnswerParam->ParamType == ANSWER_PARAM_TYPE_CONSTANT))
              AnswerParam->ParamType = ANSWER_PARAM_TYPE_UNKNOWN;
           BracketCnt--;
           break;
        }
        case '\"':
        {
           if (FlagNewParam)
           {   
              AnswerParam->ParamType = ANSWER_PARAM_TYPE_STRING;
              AnswerParam->Value = Buf;
           }
           if ((AnswerParam->ParamType == ANSWER_PARAM_TYPE_INTEGER)
              ||(AnswerParam->ParamType == ANSWER_PARAM_TYPE_CONSTANT))
              AnswerParam->ParamType = ANSWER_PARAM_TYPE_UNKNOWN;
           QuotesCnt++;
           break;
        }
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
        {
           if (FlagNewParam)
           {   
              AnswerParam->ParamType = ANSWER_PARAM_TYPE_INTEGER;
              AnswerParam->Value = Buf;
           }
           if (AnswerParam->ParamType == ANSWER_PARAM_TYPE_INTEGER)
           {
              AnswerParam->IntVal = AnswerParam->IntVal * 10;
              AnswerParam->IntVal += *Buf-0x30;
           }


           break;
        }
        default:
        {
           if (FlagNewParam)
           {   
              AnswerParam->ParamType = ANSWER_PARAM_TYPE_CONSTANT;
              AnswerParam->Value = Buf;
           }

           if (AnswerParam->ParamType == ANSWER_PARAM_TYPE_INTEGER)
              AnswerParam->ParamType = ANSWER_PARAM_TYPE_CONSTANT;
        }
     }

     if (*Buf!=' ') FlagNewParam=0;
     if (*Buf!=':') FlagCmd=0;
     tmp=*Buf;
     if (!((tmp==' ')&&(FlagNewParam)))
        Len++;

     Buf++;
     Buf=ReMapRxBufferPoint(Buf); // Пересчет указателя, т.к буфер кольцевой 
  }
  while (tmp);

  return Buf;
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вспомнил. Делал еще какую-то буферизацию для хвоста сообщения, остававшегося неразобранным с прошлого "сеанса". Т.е. то, что приходило и оказывалось неполным, не игнорировалось, а сохранялось в tile, а потом, когда дополнялось, разбиралось полностью. Жаль вот кодов не осталось, а то бы сейчас проблем не было. Но кодам почти 20 лет уже, все хранилось в архивах, а потом винда эти архивы грохнула. Работало все безупречно...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вспомнил. Делал еще какую-то буферизацию для хвоста сообщения, остававшегося неразобранным с прошлого "сеанса".

Неразобранное обязательно надо проверять. У меня конечный автомат парсера помимо ожидаемых сообщений еще и проверяет на unsolicted. И если таковые имеются - вызываются их обработчики.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...