Универсальный парсинг запросов

Модератор: Alex

Ответить
ledmax
Сообщения: 88
Зарегистрирован: Сб окт 24, 2015 9:56 pm
Благодарил (а): 11 раз
Поблагодарили: 8 раз

Универсальный парсинг запросов

Сообщение ledmax » Чт мар 03, 2016 3:00 pm

Задача - парсить GET запросы по сетке в формате VALUENAME=VALUE и присваивать значения переменным с именем идентичным запросам. - Что бы потом было легко и понятно использовать их в любом месте программы.

Получилась вот такая штука:

enum_helper_pre.h

Код: Выделить всё

#ifndef delimiter 
    #define delimiter , 
#endif 
 
 
#ifndef enumeration_begin 
    #define enumeration_begin(arg) enum arg { 
#endif 
 
#ifndef enumeration_end 
    #ifdef last_enumerator 
        #define enumeration_end delimiter last_enumerator } 
    #else 
        #define enumeration_end } 
    #endif 
#endif 
 
#ifndef declare_member 
    #define declare_member(arg) arg 
#endif 
 
#ifndef member_value 
    #define member_value(arg) = arg 
#endif   
valuename.h

Код: Выделить всё

#include "enum_helper_pre.h" 
 
enumeration_begin(valuename) 
declare_member(LIGHT) delimiter 
declare_member(TEMP) delimiter 
declare_member(DOOR) delimiter 
declare_member(MAX_VAR) 
enumeration_end; 
 
#include "enum_helper_post.h"  
Тут указываем все переменные

enum_helper_post.h

Код: Выделить всё

#undef delimiter 
#undef enumeration_begin 
#undef enumeration_end 
#undef last_enumerator 
#undef declare_member 
#undef member_value  
Ну и сам запрос:

Код: Выделить всё

#include <stdio.h>

#define enumeration_begin(arg) const char* const arg##_strs[]={
#define declare_member(arg) #arg

#include "valuename.h"

#include "valuename.h"

int values[MAX_VAR]; //глобальнай массив переменных

//Парсим полученные данные
  else if (StrContains(HTTP_req, "GET /PARAM&")) {
    sendXmlAnswer(cl);
    strtok(HTTP_req, "$"); //вид запроса $PARAM$LIGHT=1
    char* data = strtok(NULL, "$"); //второй параметр - наша пара
    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; //присваиваем переменной с индексом == индекс enum , полученное значение

}
}
В итоге мы получаем массив глобальных переменных values[] значения которых можно можно вызывать просто по названию паременных которые мы парсили, например

values[LIGHT] будет равно полученному значению при парсинге $PARAM$LIGHT=1

+ можно выводить по индексу + можно выводить само название переменной

Serial.print(values);
Serial.print( valuename_strs);

Кто, что думает по этому поводу?_ :)
Последний раз редактировалось ledmax Вс мар 06, 2016 1:55 am, всего редактировалось 1 раз.
ledmax
Сообщения: 88
Зарегистрирован: Сб окт 24, 2015 9:56 pm
Благодарил (а): 11 раз
Поблагодарили: 8 раз

Re: Универсальный парсинг запросов

Сообщение ledmax » Чт мар 03, 2016 3:36 pm

Ну и + на основе этого можно сделать опрос состояния переменных в два клика. По моему получился довольно таки универсальный механизм для общения АМС с внешним миром.
В этот массив можно запихать все входы/выходы платы
ledmax
Сообщения: 88
Зарегистрирован: Сб окт 24, 2015 9:56 pm
Благодарил (а): 11 раз
Поблагодарили: 8 раз

Re: Универсальный парсинг запросов

Сообщение ledmax » Вс мар 06, 2016 2:13 am

У меня на Ардуине используются 16 входов (пины с 38 по 54) и 16 выходов (пины с 22 по 37) всё подключено через плату оптронной развязки. Правда я немного запутался когда городил развязку и по этому фактические выходы с платы расположены в обратной последовательности относительно Ардуины. Ну впрочем это не важно - вы можете присвоить выходу любой пин.

Идея в том, что бы все входы/выходы располагались в одном месте. Присвоение значения 0/1 происходит из данным массива values[]. Имена переменных переменных можете присваивать любые - сейчас IN_1_GET, OUT_5_GET итд..
Менять значения переменных можно напрямую через ГЕТ запрос (с сохранением названия) либо с яваскрипта (веб мор АМС) все переменные глобальны, т.е их можно использовать в любом месте программы
Такой вариант сильно уменьшает количество кода, скорость работы (за счёт уменьшения переназначений) и делает код очень читабельным - переменные имеют положенные им названия.

Код: Выделить всё




typedef enum IN_Pins {IN_16=38, IN_15, IN_14, IN_13, IN_12, IN_11, IN_10, IN_9, IN_8, IN_7, IN_6, IN_5, IN_4, IN_3, IN_2, IN_1, MAX_IN_Pins};
typedef enum OUT_Pins {OUT_16=22, OUT_15, OUT_14, OUT_13, OUT_12, OUT_11, OUT_10, OUT_9, OUT_8, OUT_7, OUT_6, OUT_5, OUT_4, OUT_3, OUT_2, OUT_1, MAX_OUT_Pins};

void globalIOInit(){

  pinMode(IN_1, INPUT); //Arduino D54
  pinMode(IN_2, INPUT);
  pinMode(IN_3, INPUT);
  pinMode(IN_4, INPUT);
  pinMode(IN_5, INPUT);
  pinMode(IN_6, INPUT);
  pinMode(IN_7, INPUT);
  pinMode(IN_8, INPUT);
  pinMode(IN_9, INPUT);
  pinMode(IN_10, INPUT);
  pinMode(IN_11, INPUT);
  pinMode(IN_12, INPUT);
  pinMode(IN_13, INPUT);
  pinMode(IN_14, INPUT);
  pinMode(IN_15, INPUT);
  pinMode(IN_16, INPUT); //Arduino D38

  

  pinMode(OUT_1, OUTPUT); //Arduino D37
  pinMode(OUT_2, OUTPUT);
  pinMode(OUT_3, OUTPUT);
  pinMode(OUT_4, OUTPUT);
  pinMode(OUT_5, OUTPUT);
  pinMode(OUT_6, OUTPUT);
  pinMode(OUT_7, OUTPUT);
  pinMode(OUT_8, OUTPUT);
  pinMode(OUT_9, OUTPUT);
  pinMode(OUT_10, OUTPUT);
  pinMode(OUT_11, OUTPUT);
  pinMode(OUT_12, OUTPUT);
  pinMode(OUT_13, OUTPUT);
  pinMode(OUT_14, OUTPUT);
  pinMode(OUT_15, OUTPUT);
  pinMode(OUT_16, OUTPUT); //Arduino D22
  
  



  
}



void globalIOWorks(){

  if (values[IN_1_GET] == 1) {digitalWrite(IN_1, HIGH);} else {digitalWrite(IN_1, LOW);}
  if (values[IN_2_GET] == 1) {digitalWrite(IN_2, HIGH);} else {digitalWrite(IN_2, LOW);}
  if (values[IN_3_GET] == 1) {digitalWrite(IN_3, HIGH);} else {digitalWrite(IN_3, LOW);}
  if (values[IN_4_GET] == 1) {digitalWrite(IN_4, HIGH);} else {digitalWrite(IN_4, LOW);}
  if (values[IN_5_GET] == 1) {digitalWrite(IN_5, HIGH);} else {digitalWrite(IN_5, LOW);}
  if (values[IN_6_GET] == 1) {digitalWrite(IN_6, HIGH);} else {digitalWrite(IN_6, LOW);}
  if (values[IN_7_GET] == 1) {digitalWrite(IN_7, HIGH);} else {digitalWrite(IN_7, LOW);}
  if (values[IN_8_GET] == 1) {digitalWrite(IN_8, HIGH);} else {digitalWrite(IN_8, LOW);}
  if (values[IN_9_GET] == 1) {digitalWrite(IN_9, HIGH);} else {digitalWrite(IN_9, LOW);}
  if (values[IN_10_GET] == 1) {digitalWrite(IN_10, HIGH);} else {digitalWrite(IN_10, LOW);}
  if (values[IN_11_GET] == 1) {digitalWrite(IN_11, HIGH);} else {digitalWrite(IN_11, LOW);}
  if (values[IN_12_GET] == 1) {digitalWrite(IN_12, HIGH);} else {digitalWrite(IN_12, LOW);}
  if (values[IN_13_GET] == 1) {digitalWrite(IN_13, HIGH);} else {digitalWrite(IN_13, LOW);}
  if (values[IN_14_GET] == 1) {digitalWrite(IN_14, HIGH);} else {digitalWrite(IN_14, LOW);}
  if (values[IN_15_GET] == 1) {digitalWrite(IN_15, HIGH);} else {digitalWrite(IN_15, LOW);}
  if (values[IN_16_GET] == 1) {digitalWrite(IN_16, HIGH);} else {digitalWrite(IN_16, LOW);}


  if (values[OUT_1_GET] == 1) {digitalWrite(OUT_1, HIGH);} else {digitalWrite(OUT_1, LOW);}
  if (values[OUT_2_GET] == 1) {digitalWrite(OUT_2, HIGH);} else {digitalWrite(OUT_2, LOW);}
  if (values[OUT_3_GET] == 1) {digitalWrite(OUT_3, HIGH);} else {digitalWrite(OUT_3, LOW);}
  if (values[OUT_4_GET] == 1) {digitalWrite(OUT_4, HIGH);} else {digitalWrite(OUT_4, LOW);}
  if (values[OUT_5_GET] == 1) {digitalWrite(OUT_5, HIGH);} else {digitalWrite(OUT_5, LOW);}
  if (values[OUT_6_GET] == 1) {digitalWrite(OUT_6, HIGH);} else {digitalWrite(OUT_6, LOW);}
  if (values[OUT_7_GET] == 1) {digitalWrite(OUT_7, HIGH);} else {digitalWrite(OUT_7, LOW);}
  if (values[OUT_8_GET] == 1) {digitalWrite(OUT_8, HIGH);} else {digitalWrite(OUT_8, LOW);}
  if (values[OUT_9_GET] == 1) {digitalWrite(OUT_9, HIGH);} else {digitalWrite(OUT_9, LOW);}
  if (values[OUT_10_GET] == 1) {digitalWrite(OUT_10, HIGH);} else {digitalWrite(OUT_10, LOW);}
  if (values[OUT_11_GET] == 1) {digitalWrite(OUT_11, HIGH);} else {digitalWrite(OUT_11, LOW);}
  if (values[OUT_12_GET] == 1) {digitalWrite(OUT_12, HIGH);} else {digitalWrite(OUT_12, LOW);}
  if (values[OUT_13_GET] == 1) {digitalWrite(OUT_13, HIGH);} else {digitalWrite(OUT_13, LOW);}
  if (values[OUT_14_GET] == 1) {digitalWrite(OUT_14, HIGH);} else {digitalWrite(OUT_14, LOW);}
  if (values[OUT_15_GET] == 1) {digitalWrite(OUT_15, HIGH);} else {digitalWrite(OUT_15, LOW);}
  if (values[OUT_16_GET] == 1) {digitalWrite(OUT_16, HIGH);} else {digitalWrite(OUT_16, LOW);}



  
}
 
SPbDima
Сообщения: 113
Зарегистрирован: Пн окт 19, 2015 8:27 am
Благодарил (а): 9 раз
Поблагодарили: 21 раз

Re: Универсальный парсинг запросов

Сообщение SPbDima » Вт мар 29, 2016 1:30 pm

Чего-то много кода, можно ужать на 90%
Сразу бросилась странность кода в глаза:
Почему используется $, а не стандартный разделитель & ?
    strtok(HTTP_req, "$"); //вид запроса $PARAM$LIGHT=1 -правильно ?PARAM$LIGHT=1
    char* data = strtok(NULL, "$"); //второй параметр - наша пара -по текущему описанию второй параметр PARAM

Рекомендую добавлять в конец рандомное число(как сделано у Алекса) и тогда получится запрос:

Код: Выделить всё

 ?PARAM&LIGHT=1&<рандом> 
P.S.: странный шрифт у форума. Бесит внешний вид амперсанда.
ledmax
Сообщения: 88
Зарегистрирован: Сб окт 24, 2015 9:56 pm
Благодарил (а): 11 раз
Поблагодарили: 8 раз

Re: Универсальный парсинг запросов

Сообщение ledmax » Ср ноя 16, 2016 10:34 am

По поводу запросов согласен, можно поменять..
Чего-то много кода, можно ужать на 90%
Что вы имеете в виду?
Если это
if (values[IN_1_GET] == 1) {digitalWrite(IN_1, HIGH);} else {digitalWrite(IN_1, LOW);}
То я расписывал для удобства.. Получается что то вроде декларирования входов выходов на ПЛЦ. Указываете все I/O в одном месте и используете где угодно в программе. На моей практике такой подход показал себя с хорошей стороны - после 4 месяцев работы, мне потребовалось изменить код и я очень быстро разобрался во всём.. А если искать переменные по всему коду, то можно шею сломать(

Ну если есть предложения по рационализации, то буду рад услышать.
Ответить