ещё раз про strtok

ledmax
Offline
Зарегистрирован: 01.03.2016

Добрый день,

Помогите разобраться, почему не работает данный код:

Задача - разбирать полученную строку сначала на пары "переменная = значение", затем уже сами пары. Запрос может содержать любое количество пар.

else if(StrContains(HTTP_req, "GET /GTX?")) { //вид запроса GET /GTX?OUT_CircuPumpON=0&MHC_T_boil2=35&% HTTP/1.1
   // sendXmlAnswer(cl);
      
         int i = 1;
         strtok(HTTP_req, "?"); // убираем GET /GTX
         char* httpreq = strtok(NULL, "%");// выделяем строку от ? до %
         strtok(httpreq, "&"); //Первая пара
              while (httpreq != NULL){   //Крутим пока не закончатся пары
                parsecom(i, httpreq);
                httpreq = strtok(NULL, "&");
                i++;
                }
                
      }

И функция разбора пар:

 void parsecom(int number, char* data){
        Serial.print(number);
        Serial.print(" ");
        Serial.print(data);Serial.print("\n");

           
            char* Valuename = strtok(data, "="); 
            const char *lp_ptr = strtok(NULL, "=");
            int value = atoi(lp_ptr); 

         for (byte i = 0; i < MAX_VAR; i++) {//сравниваем Valuename c нашими переменными
          if (!strcmp(Valuename, valuename_strs[i])) {
            values[i] = value;
            Serial.print( valuename_strs[i]);
            Serial.print(": ");
            Serial.print(values[i]);
            Serial.print("\n");
          }
        }  
      }

Если из функции убрать 

            char* Valuename = strtok(data, "="); 
            const char *lp_ptr = strtok(NULL, "=");
            int value = atoi(lp_ptr); 

То, на выходе в сериал мы получаем красивые пары с номером 1 OUT_CircuPumpON=0 ; 2 MHC_T_boil2=35 итд..

Но если начинаем разбирать пары внутри функции, то работает только первая пара и в цикл  while программа даже не заходит, т.е. условие httpreq != NULL ложное. Из за чего это происходит? как strtok в функции влияет на выполнение когда основного кода?

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

могу показать как я работаю со строками запроса. без strtok

глоб переменные

char _rele1[] = "rele1"; // название
int int_rele1 = 0; // состояние реле
int Pin_rele1 = 13;    // Светодиод подключен к выходы 13

функция чтения строки

void read_serial()// читаем все что пришло в сериал
{ 
 String str_serial = "";
 bool  flag_read_complet = false;
 bool  flag_komand_complet = false;
 while (Serial.available()) 
  {  //сохраняем входную строку в переменную str_serial
   int ch = Serial.read();
    if(char(ch) == '<') {flag_read_complet = true;}
   else if(char(ch) == '>') {flag_read_complet = false;flag_komand_complet = true;}
   else if(flag_read_complet) {str_serial += char(ch);}
   delay(3);        
  }
 //Serial.println(parseGetRequest(str_serial,_rele1));
     Serial1.print("str_serial read=");
    Serial1.println(str_serial);
 if(flag_komand_complet)
 {
   for_major_rele1(parseGetRequest(str_serial,_rele1));    
 }    
  str_serial = "";// входящая строка по сериал обработана (очистим) 
} 

дальше разбор идет вот в чем

for_major_rele1(parseGetRequest(str_serial,_rele1));  

вот что делают эти две функции

int parseGetRequest(String & str_inn, char* namePin)// примим входящую строку (String) и параметр (char), 
{ //вернем целое положительное число (int) после = если такой параметр есть, если нет то вернет -1
 int bedIndex = str_inn.indexOf("rele1");
  if (bedIndex > -1)
  {
    String bedString = str_inn.substring(bedIndex + strlen(namePin) + 1);
    int bedRangeValue = bedString.toInt();
    return bedRangeValue;  
  }
  else
  {
    return -1;  
  }
}

а эта функция меняет на новое значение если оно не совпадает со старым которое было

void for_major_rele1(int nev_val_pin)// 
{
 if ((nev_val_pin > -1)&&(nev_val_pin != int_rele1))
 {
  digitalWrite(Pin_rele1, nev_val_pin);  //изменим статус реле (включить реле)  
  int_rele1 = nev_val_pin;   
 }
}

я не утверждаю что это правельно...

и да тут есть кое что лишнее.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

1. Не стоит запускать несколько цепочек strtok одновременно - они мешают друг другу. А у Вас они запускаются (одна внешняя, а другая внутри функции parsecom).

2. strtok гадит в строку с которой работает (помещает 0 на место найденного разделителя), это надо иметь в виду.

Я не понял. что там у Вас за фокусы вначале с ? и % - это Вы сами разберётесь. Я могу показать как разобрать строку типа 

http://www.kaka.com/page.htm?a=123&kaka=mumu&b=1&p1=eshe_parameter

на имена и значения параметров.

Вот смотрите полный, работающий пример - там делов-то ...

template  inline Print & operator << (Print &s, T n) { s.print(n); return s; }

void setup() {
	Serial.begin(115200);
	char *request = "http://www.kaka.com/page.htm?a=123&kaka=mumu&b=1&p1=eshe_parameter";

	char * pairPotinter = strtok(request, "?");
	for (pairPotinter = strtok(NULL, "="); pairPotinter; pairPotinter = strtok(NULL, "=")) {
		const char * valuePointer = strtok(NULL, "&");
		Serial << "name=" << pairPotinter << ";  value=" << valuePointer << '\n';
	}
}

void loop(void) {}

Строку 5 вставщик кода переврал. Должна выглядеть как

char *request = "http://www.kaka.com/page.htm?a=123&kaka=mumu&b=1&p1=eshe_parameter";

Результат:

name=a;  value=123
name=kaka;  value=mumu
name=b;  value=1
name=p1;  value=eshe_parameter
ledmax
Offline
Зарегистрирован: 01.03.2016

Большое спасибо!

Работает в таком виде:

else if(StrContains(HTTP_req, "GET /GTX?")) { //вид запроса GET /GTX?OUT_CircuPumpON=0&MHC_T_boil2=35 HTTP/1.1
 
  char * pairPotinter = strtok(HTTP_req, "?");
   for (pairPotinter = strtok(NULL, "="); pairPotinter; pairPotinter = strtok(NULL, "=")) {
    const char * valuePointer = strtok(NULL, "&");
    int value = atoi(valuePointer); //перводим const char * valuePointer в int value
    
        for (byte i = 0; i < MAX_VAR; i++) {//сравниваем Valuename c нашими переменными
          if (!strcmp(pairPotinter, valuename_strs[i])) {
            values[i] = value;
            Serial.print( valuename_strs[i]);
            Serial.print(": ");
            Serial.print(values[i]);
            Serial.print("\n");
          }
       }
   }
}

 

SBoris
Offline
Зарегистрирован: 01.05.2014

У меня ругается при компиляции примера ЕвгенийП. Что не так? 

Arduino:1.8.3 (Linux), Плата:"Arduino Nano, ATmega328"
 
String-parse-D:1: error: 'T' has not been declared
 template  inline Print & operator << (Print &s, T n) { s.print(n); return s; }
                                                ^
/home/Dropbox/Arduino/String-Serial/String-parse-D/String-parse-D.ino:1:10: warning: explicit instantiation shall not use 'inline' specifier [-fpermissive]
 template  inline Print & operator << (Print &s, T n) { s.print(n); return s; }
          ^
String-parse-D:1: error: 'operator<<' is not a template function
 template  inline Print & operator << (Print &s, T n) { s.print(n); return s; }
                                                   ^
String-parse-D:1: error: 'T' has not been declared
 template  inline Print & operator << (Print &s, T n) { s.print(n); return s; }
                                                 ^
/home/stable/Dropbox/Arduino/String-Serial/String-parse-D/String-parse-D.ino:1:11: warning: explicit instantiation shall not use 'inline' specifier [-fpermissive]
 template  inline Print & operator << (Print &s, T n) { s.print(n); return s; }
           ^
String-parse-D:1: error: 'operator<<' is not a template function
 template  inline Print & operator << (Print &s, T n) { s.print(n); return s; }
                                                    ^
String-parse-D:1: error: expected ';' before '{' token
 template  inline Print & operator << (Print &s, T n) { s.print(n); return s; }
                                                      ^
/home/stable/Dropbox/Arduino/String-Serial/String-parse-D/String-parse-D.ino: In function 'void setup()':
/home/stable/Dropbox/Arduino/String-Serial/String-parse-D/String-parse-D.ino:5:19: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
                   ^
String-parse-D:10: error: no match for 'operator<<' (operand types are 'HardwareSerial' and 'const char [6]')
     Serial << "name=" << pairPotinter << ";  value=" << valuePointer << '\n';
            ^
exit status 1
'T' has not been declared
 
This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.
 
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Хрен его знает куда делся кусок из первой строки. Правильная первая строка вот такая

template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }

В том посте подправить уже нельзя :(

SBoris
Offline
Зарегистрирован: 01.05.2014

Компилирует, но осталось:

SBoris пишет:

/home/stable/Dropbox/Arduino/String-Serial/String-parse-D/String-parse-D.ino: In function 'void setup()':

/home/stable/Dropbox/Arduino/String-Serial/String-parse-D/String-parse-D.ino:5:19: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
                   ^
 
Это у меня такую ошибку выдает или дело в чём то другом? 
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, Вы читать умеете? Во-первых это не ошибка, а предупреждение, а во-вторы, там же ясно написано, что автоматическое преобразование строковой константы в char * устарело.

Можете плюнуть, а можете после знака = написать (char *) - заткнётся.