реклама на сайте
подробности

 
 
> SIM900. Прием команд от TCP сервера., Как исключить коллизии в порту при приеме внешних команд?
Иван Плетнев
сообщение Apr 22 2014, 16:50
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 29
Регистрация: 12-04-14
Пользователь №: 81 340



Здравствуйте!

Разрабатываю устройство, которое собирает различные данные с датчиков и с периодичностью в одну минуту отправляет их на сервер посредством SIM900. Использую обычный режим AT-команд, не transparent, то есть команда AT+CIPSEND, приходит приглашение ">", отсылаю в порт строку, дожидаюсь SEND OK, всё. В данный момент добился надежной отсылки данных. Встал вопрос приёма команд от сервера. Все в общем, работает, за исключением случая, когда микроконтроллер ждет ответа от SIM900 и в этот момент приходит команда от сервера. Аппаратное управление потоком в этом случае вряд ли подойдет..
Подскажите, пожалуйста, кто как справился с этой проблемой?
Go to the top of the page
 
+Quote Post
3 страниц V  < 1 2 3  
Start new topic
Ответов (30 - 35)
alexdos
сообщение Apr 28 2014, 14:56
Сообщение #31


Местный
***

Группа: Участник
Сообщений: 339
Регистрация: 10-07-08
Из: Херсон
Пользователь №: 38 856



Цитата(Lotor @ Apr 28 2014, 15:38) *
А как обходите, просто конечный автомат парсера настраиваете на поиск ">" без обрамления \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 - Apr 28 2014, 14:57
Go to the top of the page
 
+Quote Post
Иван Плетнев
сообщение Apr 28 2014, 15:38
Сообщение #32


Участник
*

Группа: Участник
Сообщений: 29
Регистрация: 12-04-14
Пользователь №: 81 340



Цитата(tdocs.su @ Apr 28 2014, 14:11) *
Не-а. Надо сначала "пропихнуть" автомат в следующее состояние, которое будет ждать прихода именно Ок.

Вот - 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;
                    }
                }

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

Цитата(alexdos @ Apr 28 2014, 14:28) *
Тоже определял конец строки по таймауту. Работало.
Потом перешел по \r\n. По \r\n оказалось более работоспособно, и нет никакой необходимости в знании сколько их будет в ответе. К примеру посмотрим на строку \r\nOK\r\nблаблабла\r\n, по первому \n мы видим что это начало строки (так как количество принятых байтов равно 2). По второму получаем ответ OK. По третьему получаем ответ блаблабла. Поэтому при разборе ответов, задача сводится к проверке "наборов байтов находящихся между \r\n". Единственное что портит всю картину это приглашение к вводу данных "> ", но и это обходится очень просто.


Это Вы в прерывании всё делаете? Если так, то приличный такой обработчик в прерывании будет крутиться. А если нет, тогда опять не ясно, как конец сообщения определить?
Go to the top of the page
 
+Quote Post
alexdos
сообщение Apr 28 2014, 17:45
Сообщение #33


Местный
***

Группа: Участник
Сообщений: 339
Регистрация: 10-07-08
Из: Херсон
Пользователь №: 38 856



Цитата(Иван Плетнев @ Apr 28 2014, 18:38) *
Это Вы в прерывании всё делаете? Если так, то приличный такой обработчик в прерывании будет крутиться. А если нет, тогда опять не ясно, как конец сообщения определить?

Да нет, в прерывании я мало что делаю
Код
/* завершим текстовую строку*/
           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 - Apr 28 2014, 17:46
Go to the top of the page
 
+Quote Post
RadikX
сообщение Apr 29 2014, 04:07
Сообщение #34


Частый гость
**

Группа: Участник
Сообщений: 125
Регистрация: 13-04-11
Из: Суровый Челябинск
Пользователь №: 64 337



Цитата(Иван Плетнев @ Apr 27 2014, 20:21) *
Мне как раз мультисокет и не нужен, мне достаточно одного соединения. Значит ли это, что мне лучше воспользоваться прозрачным режимом?
И второе. Намекните, если можно, про устройство Вашего оптимизированного парсера. Как он работает?

В прозрачном режиме проще: могут придти только данные.
Устройство парсера
CODE
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.
CODE
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;
}
Go to the top of the page
 
+Quote Post
tdocs.su
сообщение Apr 29 2014, 04:14
Сообщение #35


Частый гость
**

Группа: Участник
Сообщений: 143
Регистрация: 27-02-14
Из: Москва
Пользователь №: 80 728



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


--------------------
Go to the top of the page
 
+Quote Post
Lotor
сообщение Apr 30 2014, 10:46
Сообщение #36


Местный
***

Группа: Свой
Сообщений: 476
Регистрация: 3-07-07
Из: Санкт-Петербург
Пользователь №: 28 866



Цитата(tdocs.su @ Apr 29 2014, 08:14) *
Вспомнил. Делал еще какую-то буферизацию для хвоста сообщения, остававшегося неразобранным с прошлого "сеанса".

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


--------------------
Ковырял чукча отверткой в ухе, звук в телевизоре и пропал.
Go to the top of the page
 
+Quote Post

3 страниц V  < 1 2 3
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th August 2025 - 16:40
Рейтинг@Mail.ru


Страница сгенерированна за 0.01424 секунд с 7
ELECTRONIX ©2004-2016