Странное поведение памяти на меге

Тема в разделе "Arduino & Shields", создана пользователем Vetrinus, 28 апр 2016.

  1. Vetrinus

    Vetrinus Гик

    Здравствуйте!
    Есть у меня мега и ethernet shield к ней. Проблема в том, что мне необходимо сохранять приходящий http запрос полностью. Но, когда я увеличиваю размер буфера char[HTTP_req] контроллер начинает либо перезагружается на этапе записи байтов в буфер, либо просто виснет и ни на что не реагирует.
    Код прилагаю ниже:
    Код (C++):
    #include <SPI.h>
    #include <Ethernet.h>
    #include <SD.h>
    #define REQ_BUF_SZ 126 //Экспериментально подобраный, максимально возможный размер буфера, при котором все работает. Если вписать, допустим, 200, то картина будет совсем другой.

    File webFile;
    char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
    char req_index = 0; // index into HTTP_req buffer
    byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
    IPAddress ip(192, 168, 0, 177);

    EthernetServer server(80);

    void setup() {
      Ethernet.begin(mac, ip);
      server.begin();
      (!SD.begin(4));
      Serial.begin(9600);
    }

    void loop() {
      // listen for incoming clients
      EthernetClient client = server.available();
      if (client) {
        Serial.println("New client");
        // an http request ends with a blank line
        boolean currentLineIsBlank = true;
        while (client.connected()) {
          if (client.available()) {
            char c = client.read();
            Serial.print(c);
            if (req_index < (REQ_BUF_SZ - 1)) {
              HTTP_req[req_index] = c; // save HTTP request character
              req_index++;
            }
            if (c == '\n' && currentLineIsBlank) {
              Serial.println("Request saved...");
              Serial.print("strlen(HTTP_req)= ");
              Serial.println(strlen(HTTP_req));
              Serial.println("Seeking hash...");
              if (StrContains(HTTP_req, "Authorization: Basic bG9naW46cGFzc3dvcmQ=")) {
                Serial.println("Client authorized");
                if (StrContains(HTTP_req, "GET / ")) {
                   client.println("HTTP/1.1 200 OK");
                client.println("Content-Type: text/html");
                client.println("Connnection: close");
                client.println();
                  Serial.println("opening SD...");
                  webFile = SD.open("index.htm");
                  if (webFile) {
                    Serial.println("Index.htm opened");
                  }
                }
                  else if (StrContains(HTTP_req, "GET /UI.css")) {
                    webFile = SD.open("UI.css");
                    if (webFile) {
                      Serial.println("CSS file opened");
                      //client.println("Content-type: text/css");
                      //client.println("Connection: close");
                      client.println();
                    }

                  }
                  else if (StrContains(HTTP_req, "GET /script.js")) {
                    webFile = SD.open("script.js");
                    if (webFile) {
                      Serial.println("js file opened");
                      client.println("HTTP/1.1 200 OK");
                      client.println("Content-type: application/javascript");
                      client.println("Connection: close");
                      client.println();
                    }

                  }
                    else if (StrContains(HTTP_req, "GET /favicon.ico")) {
                      client.println("HTTP/1.1 404 Not Found");
                      client.println();
                    }
             
                if (webFile) {
                  while (webFile.available()) {
                    client.write(webFile.read()); // send web page to client
                  }
                  webFile.close();
                }
              }
              else {
                client.println(F("HTTP/1.1 401 Unauthorized"));
                client.println(F("WWW-Authenticate: Basic realm=\"Web Control Panel\""));
                Serial.println("Client not authorized");
              }
              Serial.println("Clear HTTP_req");
              Serial.println();
              req_index = 0;
              StrClear(HTTP_req, REQ_BUF_SZ);
              break;
            }
            if (c == '\n') {
              // you're starting a new line
              currentLineIsBlank = true;
            }
            else if (c != '\r') {
              // you've gotten a character on the current line
              currentLineIsBlank = false;
            }
          }
        }
        // give the web browser time to receive the data
        delay(1);
        // close the connection:
        client.stop();
      }
    }

    void StrClear(char *str, char length)
    {
      for (int i = 0; i < length; i++) {
        str[i] = 0;
      }
    }

    char StrContains(char *str, const char *sfind)
    {
      char found = 0;
      char index = 0;
      char len;

      len = strlen(str);
      Serial.println("StrContains invoked");
      if (strlen(sfind) > len) {
        Serial.println("strlen(sfind)> len");
        return 0;
      }
      while (index < len) {
        if (str[index] == sfind[found]) {
          found++;
          if (strlen(sfind) == found) {
            return 1;
          }
        }
        else {
          found = 0;
        }
        index++;
      }
      return 0;
    }
     
    Последнее редактирование: 28 апр 2016
  2. Vetrinus

    Vetrinus Гик

    Приведу вывод COM порта при размере буфера в 500 байт:
    Код (C++):

    New client
    GET / HTTP/1.1
    Host: 192.168.0.177
    Connection: keep-alive
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Upg
    Причем, сколько контроллер не перезагружай, всегда чтение запроса остановится именно на этом месте.

    А вот, при размере буфера 126:
    Код (C++):
    New client
    GET / HTTP/1.1
    Host: 192.168.0.177
    Connection: keep-alive
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36
    Accept-Encoding: gzip, deflate, sdch
    Accept-Language: ru
    X-Compress: null

    Request saved...
    strlen(HTTP_req)= 125
    Seeking hash...
    StrContains invoked
    Client not authorized
    Clear HTTP_req

    New client
    GET / HTTP/1.1
    Host: 192.168.0.177
    Connection: keep-alive
    Authorization: Basic bG9naW46cGFzc3dvcmQ=
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/
    *;q=0.8
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36
    Accept-Encoding: gzip, deflate, sdch
    Accept-Language: ru
    X-Compress: null

    Request saved...
    strlen(HTTP_req)= 125
    Seeking hash...
    StrContains invoked
    Client authorized
    StrContains invoked
    opening SD...
    Index.htm opened
    Clear HTTP_req

    New client
    GET /UI.css HTTP/1.1
    Host: 192.168.0.177
    Connection: keep-alive
    Authorization: Basic bG9naW46cGFzc3dvcmQ=
    Accept: text/css,*/*;q=0.1
    User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36
    Referer: http://192.168.0.177/
    Accept-Encoding: gzip, deflate, sdch
    Accept-Language: ru
    X-Compress: null

    Request saved...
    strlen(HTTP_req)= 125
    Seeking hash...
    StrContains invoked
    Client authorized
    StrContains invoked
    StrContains invoked
    CSS file opened
    Clear HTTP_req

    New client
    GET /script.js HTTP/1.1
    Host: 192.168.0.177
    Connection: keep-alive
    Authorization: Basic bG9naW46cGFzc3dvcmQ=
    Accept: */
    *
    User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36
    Referer: http://192.168.0.177/
    Accept-Encoding: gzip, deflate, sdch
    Accept-Language: ru
    X-Compress: null

    Request saved...
    strlen(HTTP_req)= 125
    Seeking hash...
    StrContains invoked
    Client authorized
    StrContains invoked
    StrContains invoked
    StrContains invoked
    js file opened
    Clear HTTP_req

    New client
    GET /favicon.ico HTTP/1.1
    Host: 192.168.0.177
    Connection: keep-alive
    Authorization: Basic bG9naW46cGFzc3dvcmQ=
    User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36
    Accept: */*
    Referer: http://192.168.0.177/
    Accept-Encoding: gzip, deflate, sdch
    Accept-Language: ru
    X-Compress: null

    Request saved...
    strlen(HTTP_req)= 125
    Seeking hash...
    StrContains invoked
    Client authorized
    StrContains invoked
    StrContains invoked
    StrContains invoked
    StrContains invoked
    Clear HTTP_req
     
  3. Vetrinus

    Vetrinus Гик

    Кстати, при компилировании с размером буфера 500, компилятор выдает предупреждение:
    Not_Working_Global.ino:97:40: warning: overflow in implicit constant conversion [-Woverflow]
    Я не очень понимаю синтаксис этого, поэтому привожу ниже содержимое 94 и 40 строк:
    В 40 строке вывод в ком порт и ничего больше.
    а вот в 97 уже интересней:
    Код (C++):
    StrClear(HTTP_req, REQ_BUF_SZ);

    void StrClear(char *str, char length)
    {
      for (int i = 0; i < length; i++) {
        str[i] = 0;
      }
    }
     
  4. Vetrinus

    Vetrinus Гик

    Все, понял. Значит, нужно заменить тип данных в буфере. Кстати, на что? Что еще может хранить символы? Похоже, придется создать еще один массив. Да хотя блин. Ну вот объясните мне, что может помешать контроллеру выделить в памяти участок под 500 переменных типа char? Я ведь не в саму переменную пишу значение, которое выходит за рамки ее битности. Был бы рад учлышать чьи-нибудь комментарии по этому поводу
     
  5. Vetrinus

    Vetrinus Гик

    Попытка изменить тип данных внутри массива на беззнаковый (unsigned char) потерпела фиаско.
    Похоже, придется создавать еще 2 аналогичных буфера, следить за тем, чтобы в буферах оставались только полные строки, без "обрезаний", и уже в этих буферах искать необходимый мне хеш
     
  6. Vetrinus

    Vetrinus Гик

    Короче, сделаю так..
    При чтении байтов с шилда я буду сохранять в буфер строку, смотреть, есть ли в ней полезная мне информация, и , если есть, сохранять. Если нет, то удалять. Таким образом проблема с размером буфера отпадает.
     
  7. Vetrinus

    Vetrinus Гик

    Но мнение кого-нибудь знающего касательно этой ситуации я все равно хотел бы услышать
     
  8. Tomasina

    Tomasina Сушитель лампочек Модератор

    у тебя и так памяти не хватает, а ты хочешь создать еще два буфера. Где их хранить?
     
  9. AlexU

    AlexU Гуру

    У функции 'StrClear' второй параметр 'length' имеет тип 'char', который не пригоден для хранения числа 500. Вот компилятор и ругается.
    Менять надо не тип данных буфера, а тип параметра 'length' в функци, например, на 'int'.

    При компиляции с большим буфером, что в конце выдает компилятор?
     
  10. AlexVS

    AlexVS Гик

    Для того что бы уменьшить кол-во занимаемой ОЗУ замените все строки типа
    Serial.println("Request saved...");
    а так же
    client.println("Content-Type: text/html");
    на
    Serial.println(F("Request saved..."));
    и соответственно
    client.println(F("Content-Type: text/html"));
     
  11. Vetrinus

    Vetrinus Гик

    Вот, обычный размер буфера:
    Код (C++):
    Sketch uses 23 728 bytes (9%) of program storage space. Maximum is 253 952 bytes.
    Global variables use 1 673 bytes (20%) of dynamic memory, leaving 6 519 bytes for local variables. Maximum is 8 192 bytes.
     
    Вот увеличенный
    Код (C++):
    Sketch uses 23 724 bytes (9%) of program storage space. Maximum is 253 952 bytes.
    Global variables use 2 047 bytes (24%) of dynamic memory, leaving 6 145 bytes for local variables. Maximum is 8 192 bytes.
    Не понимаю, в чем проблема-то... Ну не может мне не хватать памяти.
     
  12. Vetrinus

    Vetrinus Гик

    А есть у кого мега с ethernet shieldом? Просто, чтобы проверить симптомы. Может у меня с железом что-то не то