|
SIM900. Прием команд от TCP сервера., Как исключить коллизии в порту при приеме внешних команд? |
|
|
|
Apr 22 2014, 16:50
|
Участник

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

|
Здравствуйте!
Разрабатываю устройство, которое собирает различные данные с датчиков и с периодичностью в одну минуту отправляет их на сервер посредством SIM900. Использую обычный режим AT-команд, не transparent, то есть команда AT+CIPSEND, приходит приглашение ">", отсылаю в порт строку, дожидаюсь SEND OK, всё. В данный момент добился надежной отсылки данных. Встал вопрос приёма команд от сервера. Все в общем, работает, за исключением случая, когда микроконтроллер ждет ответа от SIM900 и в этот момент приходит команда от сервера. Аппаратное управление потоком в этом случае вряд ли подойдет.. Подскажите, пожалуйста, кто как справился с этой проблемой?
|
|
|
|
3 страниц
< 1 2 3
|
 |
Ответов
(30 - 35)
|
Apr 28 2014, 14:56
|
Местный
  
Группа: Участник
Сообщений: 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
|
|
|
|
|
Apr 28 2014, 15:38
|
Участник

Группа: Участник
Сообщений: 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". Единственное что портит всю картину это приглашение к вводу данных "> ", но и это обходится очень просто. Это Вы в прерывании всё делаете? Если так, то приличный такой обработчик в прерывании будет крутиться. А если нет, тогда опять не ясно, как конец сообщения определить?
|
|
|
|
|
Apr 28 2014, 17:45
|
Местный
  
Группа: Участник
Сообщений: 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
|
|
|
|
|
Apr 29 2014, 04:07
|
Частый гость
 
Группа: Участник
Сообщений: 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; }
|
|
|
|
|
Apr 29 2014, 04:14
|
Частый гость
 
Группа: Участник
Сообщений: 143
Регистрация: 27-02-14
Из: Москва
Пользователь №: 80 728

|
Вспомнил. Делал еще какую-то буферизацию для хвоста сообщения, остававшегося неразобранным с прошлого "сеанса". Т.е. то, что приходило и оказывалось неполным, не игнорировалось, а сохранялось в tile, а потом, когда дополнялось, разбиралось полностью. Жаль вот кодов не осталось, а то бы сейчас проблем не было. Но кодам почти 20 лет уже, все хранилось в архивах, а потом винда эти архивы грохнула. Работало все безупречно...
--------------------
|
|
|
|
|
Apr 30 2014, 10:46
|
Местный
  
Группа: Свой
Сообщений: 476
Регистрация: 3-07-07
Из: Санкт-Петербург
Пользователь №: 28 866

|
Цитата(tdocs.su @ Apr 29 2014, 08:14)  Вспомнил. Делал еще какую-то буферизацию для хвоста сообщения, остававшегося неразобранным с прошлого "сеанса". Неразобранное обязательно надо проверять. У меня конечный автомат парсера помимо ожидаемых сообщений еще и проверяет на unsolicted. И если таковые имеются - вызываются их обработчики.
--------------------
Ковырял чукча отверткой в ухе, звук в телевизоре и пропал.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|