alexdos 0 28 апреля, 2014 Опубликовано 28 апреля, 2014 (изменено) · Жалоба А как обходите, просто конечный автомат парсера настраиваете на поиск ">" без обрамления \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; Изменено 28 апреля, 2014 пользователем alexdos Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
IvanPletnev 0 28 апреля, 2014 Опубликовано 28 апреля, 2014 · Жалоба Не-а. Надо сначала "пропихнуть" автомат в следующее состояние, которое будет ждать прихода именно Ок. Вот - 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". Единственное что портит всю картину это приглашение к вводу данных "> ", но и это обходится очень просто. Это Вы в прерывании всё делаете? Если так, то приличный такой обработчик в прерывании будет крутиться. А если нет, тогда опять не ясно, как конец сообщения определить? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alexdos 0 28 апреля, 2014 Опубликовано 28 апреля, 2014 (изменено) · Жалоба Это Вы в прерывании всё делаете? Если так, то приличный такой обработчик в прерывании будет крутиться. А если нет, тогда опять не ясно, как конец сообщения определить? Да нет, в прерывании я мало что делаю /* завершим текстовую строку*/ 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; } Изменено 28 апреля, 2014 пользователем alexdos Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Radik_1983 0 29 апреля, 2014 Опубликовано 29 апреля, 2014 · Жалоба Мне как раз мультисокет и не нужен, мне достаточно одного соединения. Значит ли это, что мне лучше воспользоваться прозрачным режимом? И второе. Намекните, если можно, про устройство Вашего оптимизированного парсера. Как он работает? В прозрачном режиме проще: могут придти только данные. Устройство парсера 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; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tdocs.su 0 29 апреля, 2014 Опубликовано 29 апреля, 2014 · Жалоба Вспомнил. Делал еще какую-то буферизацию для хвоста сообщения, остававшегося неразобранным с прошлого "сеанса". Т.е. то, что приходило и оказывалось неполным, не игнорировалось, а сохранялось в tile, а потом, когда дополнялось, разбиралось полностью. Жаль вот кодов не осталось, а то бы сейчас проблем не было. Но кодам почти 20 лет уже, все хранилось в архивах, а потом винда эти архивы грохнула. Работало все безупречно... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
lotor 0 30 апреля, 2014 Опубликовано 30 апреля, 2014 · Жалоба Вспомнил. Делал еще какую-то буферизацию для хвоста сообщения, остававшегося неразобранным с прошлого "сеанса". Неразобранное обязательно надо проверять. У меня конечный автомат парсера помимо ожидаемых сообщений еще и проверяет на unsolicted. И если таковые имеются - вызываются их обработчики. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться