Парсинг строки адреса Arduino в режиме веб-сервера
- Войдите на сайт для отправки комментариев
Чт, 11/04/2013 - 09:47
Имею arduino nano и enc28j60 модуль к нему. Мой проект - это очередная ethernet метеостанция, но не суть )
В процедуре Loop идет обработа запросов и выдача результатов:
void loop()
{
char* httpurl;
if (httpurl = e.serviceRequest())
{
if (strcmp(httpurl, "") == 0)
{
e.print("<A HREF='/'><H1>nano v3</H1></A>");
e.print("<br>");
e.print("<A HREF='?=temp'>Show Temperature</A>");
e.print("<br>");
e.print("<A HREF='?=ip'>IP Settings</A>");
e.print("<br>");
e.print("<A HREF='?=relay'>Relay Switch</A>");
}
if (strcmp(httpurl, "?=ip") == 0)
{
e.print("<html>");
e.print("<head>");
e.print("</head>");
e.print("<body>");
e.print("<A HREF='/'><H1>nano v3</H1></A>");
e.print("<br> IP (loaded from ROM): <br>");
e.print("<form name = 'form1' action = 'setip' method = 'get'>");
e.print("ip: <input type = 'a' name = 'aaa' value = ");
e.print(EEPROM.read(0));
e.print(">");
e.print(". <input type = 'b'; name = 'bbb' value = ");
e.print(EEPROM.read(1));
e.print(">");
e.print(". <input type = 'c'; name = 'ccc' value = ");
e.print(EEPROM.read(2));
e.print(">");
e.print(". <input type = 'd'; name = 'ddd' value = ");
e.print(EEPROM.read(3));
e.print(">");
e.print("<br>");
e.print("<input type ='submit'; value = Apply >");
e.print("</form>");
e.print("</body>");
e.print("</html>");
}
e.respond();
}
При запросе http://ip-адрес/?=ip выдается страничка с 4 полями и загруженными в нее значениями из eeprom. Если вписать свои значения нажать на кнопку Apply, то сформируется ссылка вида:
http://192.168.0.33/setip?aaa=192&bbb=168&ccc=0&ddd=34
Соответственно в httpurl передается значение:
setip?aaa=192&bbb=168&ccc=0&ddd=34
Задача вытянуть числа 192, 168, 0 и 34 в arduino для внутренней обработки - сохранения в eeprom. Есть библиотека TextFinder, но она не работает с моей библиотекой ethernet-модуля.
Также не совсем понимаю, как из char* httpurl преобразовать в String.
Логику работы парсинга себе представляю себе так:
1. поиск по маске, например, "aaa="
2. вычленение значения после выражения до символа "&" или окончания строки или можно что-то в стиле 3 символа после найденного значения+применение функции atoi
Если бы вы первые слова своей темы "Парсинг строки" вбили в поиск в верхенм правом углу, то второй же ссылкой вам выдало-бы тему где обсуждалось ровно то же самое. Причем буквально пару дней назад (а это значит что даже без поиска, просто посмотрев темы последние - можно было найти).
Разбор тестовой строки | Аппаратная платформа Arduino
Извините, подобную тему искал раньше даты создания темы от 4 апреля. Спасибо!
Единственный коммент - в той теме параметры в урле топикстартер разделяет запятыми и дветочиями. А у вас - амперсанды и знаки равно. "По стандартам" - ваш вариант более правильный/традиционный. Его легче понять просто посмотрев на урл любому веб-разработчику без доп. объяснений.
Так что там вы посмотрите только "принцип", но используйте свои разделители & и =.
>преобразовать в String.
Да просто передайте в конструктор
Но... лично я вообще предпочитаю не использовать класс String. Во первых "место", во вторых он "только в ардуине существует" и то используется редко в серьезном коде.
Так что лучше изначально привыкать работать с char* (обычные сишные строки) string
Все встроенные обычные функции сишные atoi, stkok и т.п. - работают именно с такими строками, а не String объектом.
void parseParams(char* inputString){ parsedParams=0; char* buffer=strtok(inputString,"?"); if(buffer!=NULL){ for(buffer=strtok(NULL,"&"); buffer!=NULL; buffer=strtok(NULL,"&") ) { params[parsedParams].value=buffer; parsedParams++; if(parsedParams>MAX_PARAMS-1)return; } } }Кручу-верчу функцию из найденой темы. При таком варианте возвращаются значения:
но возвращает только:
Ну во первых, не правильно "аналогию провели". Двоеточия из того кода - соотвествуют вашим знакам равно. То есть в for-ре у вас
strtok(NULL,"=")Вот вам и будет парсинг имен параметров. А не захват "имя+значение" сразу. Но, у вас начнется потеря значений.
Вы же код из строк 41-42 выкинули, а именно он отвечает за парсинг значений. Вам он тоже нужен. Только там он ищется по запятой, а у вас амперсанд.
Вообщем из того кода в ваш переход делается чере замену ":"-->"=" и ","-->"&"
Верно. Не понимаете. Но в двух словах тут не расскажешь. загуглите какой-нибудь учебник по C/C++ и почитайте разделы "указатели/ссылки" и "строки". Возможно даже несколько учебников прийдется прочитать. Тема действительна сложная для понимания (но когда понял - все просто) не каждый автор наглядно может объяснить. А тема важна. Без нее что-то сложней "мигаем диодом" - трудно. А в работе со строками - вообще никак.
P.S. И наверное луче было продолжать дисскуссию в той ветке. Что-бы "не размазывать". Тем более что я планировал на выходных туда дописать альтернативу atoi. Да и топикстартер той ветки - тоже мог бы вам подсказать. Он то понял "как оно работает". Да еще говорил что "разобрался с указателями", может подскажет где почитал (я-то уже естественно не помню где про это нормально написано).
В первоначальном виде я в функцию наоборот запихал свои & и = . Теперь все работает.
Оставлю для истории правильный вариант:
void parseParams(char* inputString){ parsedParams=0; // пока ничего не напарсили char* buffer=strtok(inputString,"?"); // лучше так проверять/пропускать вопросилово if(buffer!=NULL){ for(buffer=strtok(NULL,"="); buffer!=NULL; buffer=strtok(NULL,"=") ) { if( (buffer=strtok(NULL,"&")) !=NULL) params[parsedParams].value=atoi(buffer); else return ; parsedParams++; // отмечаем сколько удалось распарсить if(parsedParams>MAX_PARAMS-1)return; // больше нет места куда сохранять парсенное. } } }Огромное спасибо.
А где в этом правильном варианте парсинг имен параметров? или они вам не нужны?
В моем случае это не особо принципиально, но по-хорошему проверка нужна (действительно ли, к примеру передается параметр 'aaa', а не 'cdf'). Только я опять затрудняюсь с решением данной задачи.
Ну, проверять - это уже потом. Вначале грамотно выпарсить нужно. И даже умея работать со строками - есть там с чем повозится.
Вообщем в любом случае "вначали читать книжку про указатели/ссылки и строки", в любом случае это пригодится (а без понимания - даже если дадут вам готовый код - будет все рушится при малейшей попытке что-то изменить).
int strtoint(String str) // Процедура переобразования строки в число { int tempInt; char rez[str.length()+1]; str.toCharArray(rez, sizeof(rez)); tempInt = atoi(rez); return tempInt; } void parseParams(char* inputString){ parsedParams=0; // пока ничего не напарсили char* buffer=strtok(inputString,"?"); // лучше так проверять/пропускать вопросилово if(buffer!=NULL){ for(buffer=strtok(NULL,"&"); buffer!=NULL; buffer=strtok(NULL,"&") ) { String buffer1= String(buffer); params[parsedParams].name= buffer1.substring(0,buffer1.indexOf('=')); //достаем имя params[parsedParams].value=strtoint(buffer1.substring(buffer1.indexOf('=')+1)); //достаем значение в integer parsedParams++; // отмечаем сколько удалось распарсить } if(parsedParams>MAX_PARAMS-1)return; // больше нет места куда сохранять парсенное. } }Пока сделал такой костыль. Выдает структуру struct port_param_t {String name;int value;};
// структра описывающие наш параметр struct port_param_t{String name; int value;}; #define MAX_PARAMS 20 // сколько параметров максимально мы умеем парсить port_param_t params[MAX_PARAMS]; // в этот массис будем сохранять наши парсенные параметры byte parsedParams=0; // сколько параметров нам удалось напарсить void setup(){ Serial.begin(9600); char* inputString="h ttp://192.168.3.5/setip?aaa=192&bbb=168&ccc=1&ddd=33"; // наши тестовые данные // выводим что собираемся парсить Serial.print("input '");Serial.print(inputString); Serial.println("'"); // парсим parseParams(inputString); // выводим что получилось printParams(); } // парсид входящую строку в массив params[] и устанавливает parsedParam в количество прочитанных элементов void parseParams(char* inputString){ parsedParams=0; // пока ничего не напарсили char* buffer=strtok(inputString,"?"); // лучше так проверять/пропускать вопросилово if(buffer!=NULL){ for(buffer=strtok(NULL,"&"); buffer!=NULL; buffer=strtok(NULL,"&") ) { String buffer1= String(buffer); params[parsedParams].name= buffer1.substring(0,buffer1.indexOf('=')); params[parsedParams].value=strtoint(buffer1.substring(buffer1.indexOf('=')+1)); parsedParams++; // отмечаем сколько удалось распарсить } if(parsedParams>MAX_PARAMS-1)return; // больше нет места куда сохранять парсенное. } } // Выводит в Serial массив parsedParams[] void printParams(){ for(byte i=0;i<parsedParams;i++){ // TODO: всю эту кучу принтов можно заменить одним sprintf Serial.print(params[i].name); Serial.print(" -> "); Serial.println(params[i].value); // Serial.print("="); // Serial.println(params[i].value,DEC); } } int strtoint(String str) // Процедура переобразования строки в число { int tempInt; char rez[str.length()+1]; str.toCharArray(rez, sizeof(rez)); tempInt = atoi(rez); return tempInt; } void loop(){ }