Функция возвращающая массив

rene
Offline
Зарегистрирован: 21.01.2014

Доброго времени суток!

Некая фукции должна возвращать список файлов на SD карте в виде массива строк. Что то с наскока не удалось решить эту задачу. Это возможно?

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Можно поступить проще, передать в функцию указатель на массив строк и в функции его заполнить.
В противном случае Вам придется формировать динамически этот массив, что не всегда хорошо.
Хотя варианты могут быть разными, слишком мало информации.

rene
Offline
Зарегистрирован: 21.01.2014

Если вам не трудно, приведите пожалуйста примеры функций с указателем и без него. У меня что то не получается.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Если покажете кусок кода, где описан массив строк, тогда помогу, иначе гадать на кофейной гуще нет никакого желания. Возможно в Вашем понимании массив строк одно, а в моем - другое. Зачем гадать?

 

rene
Offline
Зарегистрирован: 21.01.2014
#include <SD.h>

void setup()
{
  int i = 0;
  Serial.begin(9600);

  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    return;
  }

  String dir[10];
  
  File root = SD.open("/");
  while(true)
  {
    File entry =  root.openNextFile();
    if (! entry) break;
    dir[i] = entry.name();
    i ++;
    entry.close();
  }
  root.close();
  
  for (int i = 0; i < 10; i ++)
  {
    Serial.print(i);
    Serial.println("\t" + dir[i]);
  }
}

void loop()
{
}

Строки с 15 по 24 необходимо вынести в функцию. Понятно что массив dir можно было объявить глобально, но меня интересую другие возможные решения, в целях так сказать саморазвития.

Попутно еще 2 вопроса. Возможно ли в данном случае массив сделать динамическим? И как узнать количество элементов в массиве? dir.length не работает

axill
Offline
Зарегистрирован: 05.09.2011

У вас могут довольно быстро и незаметно возникнуть проблемы из за нехватки памяти. Массив строк для 2048 байт памяти звучит весьма угрожающе. Рекомендую вам пересмотреть дизайн программы и делать обработку файлов по одному, считывая их имена с FAT по одному запоминая последний указатель, т.е. Логика "нашли первый", далее за раз берем "один следующий" до тех пор пока "не достигли последний"

rene
Offline
Зарегистрирован: 21.01.2014

Я так пробовал, не получилось. Дело в том, что я пытаюсь реализовать файловый веб сервер. Купил ethernet шилд, воткнул его в uno. Изначальный алгоритм был таков - ждем соединения от клиента, после которого начинаем формировать веб страницу паралельно считывая информацию с SD карты. Сама страница формируется нормально, но как только пытаюсь считывать информацию с карты, начинаются глюки, файлы то видны, то нет или частично.

Погуглив нашел информацию, что ethernet шилд не может одновременно работать и сетью и с картой, т.е. чтобы считать информацию с карты, мне надо разорвать соединение с клиентом, чего делать нельзя. Поэтому пришел к выводу что информацию о файлах надо считать при старте и хранить ее в памяти.

Вот первоначальный кусок кода, возможно я что то упустил или где то ошибся, и не надо городить строковые массивы?

  // Web сервер
  // Символ /n соответствует коду 10, т.е. LF (line feed), подача строки
  // Символ /r соответствует коду 13, т.е. CR (carriage return), возврат каретки
  // В Windows для перехода на новую строку используются пара этих символов, т.е. LF + CR

  // Прослушиваем входящие подключенния на порту 80
  EthernetClient client = server.available(); // функция при налиции подключения возвращает объект client, иначе возвращает false
  if (client) {
    client.clientIP(clIP); // самописный клас для извлечения адреса клиента
    Serial.print("Client ");
    for (int i = 0; i < 4; i ++)
    {
      Serial.print(clIP[i], DEC);
      if (i < 3) Serial.print(".");
    }
    Serial.println(" connected");

    boolean currentLineIsBlank = true;
    while (client.connected()) { // цикл пока есть соединение

      // Данная проверка необходимо для получения клиентского запроса
      // ответа на него и выхода из цикла
      if (client.available()) { // если от клиента поступают данные
        char c = client.read(); // читаем входящие от клиента символы
        // Serial.write(c); // то что пришло от клиента

        // Если дошли до конца строки (получили символ новой строки LF)
        // и строка пустая (т.е. по сути получили два подряд идущих LF LF)
        // клиентский запрос HTTP закончился и можно отправлять ответ.
        // Иначе говоря, ждем когда клиент заткнется и даст возможность ответить
        if (c == '\n' && currentLineIsBlank) {

          // Отправляем клиенту стандартный HTTP заголовок
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // соединение будет закрыто после завершения ответа
          client.println("Refresh: 60");  // автоматическое обновление страницы каждые 1 мин.
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");

          // Тело страницы         
          root = SD.open("/");
          while(true)
          {
            File entry =  root.openNextFile();
            if (! entry) break;
            String en = entry.name();
            client.print("<a href=" + en + ">");
            client.print(en);
            client.println("</a>");
            entry.close();
          }
          root.close();
          client.println("</html>");
          break;
        }

        if (c == '\n') {
          currentLineIsBlank = true; // началась новая строка, считаем ее пустой
        } 
        else if (c != '\r') {
          currentLineIsBlank = false; // любой входящий символ кроме LF и CR делает текущую строку не пустой
        }
      }
    }
    client.stop(); // закрывем HTTP сессию
    Serial.println("Client disonnected\n");
  }
Datak
Offline
Зарегистрирован: 09.10.2014

rene пишет:
Погуглив нашел информацию, что ethernet шилд не может одновременно работать и сетью и с картой, т.е. чтобы считать информацию с карты, мне надо разорвать соединение с клиентом

Оужос, неужели на самом деле так? Нет, я сам-то не пробовал конечно, и мало в этом понимаю, но если это так - в печку нафиг такой шилд.

rene пишет:
Поэтому пришел к выводу что информацию о файлах надо считать при старте и хранить ее в памяти.

А чем это поможет? Тогда уж сами файлы надо в памяти хранить, а не информацию о них.
Не, я тоже считаю что тут всю систему надо менять. :)

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

Datak пишет:

Оужос, неужели на самом деле так? Нет, я сам-то не пробовал конечно, и мало в этом понимаю, но если это так - в печку нафиг такой шилд.

Если бы Вы потрудились хотя бы почитать описание шилда - у Вас бы не возникало таких вопросов. Да, оно там by design так работает.

axill
Offline
Зарегистрирован: 05.09.2011

rene пишет:

Погуглив нашел информацию, что ethernet шилд не может одновременно работать и сетью и с картой, т.е. чтобы считать информацию с карты, мне надо разорвать соединение с клиентом, чего делать нельзя. Поэтому пришел к выводу что информацию о файлах надо считать при старте и хранить ее в памяти.

Мне думается вы ошибаетесь в том, что нельзя одновременно держать активное соединение и работать с SD картой. У ethernet shield бала проблема в работе с SD по той причине, что у чипа wiznet5100 есть баг по работе по SPI интерфейсу из-за которого по сути этот чип не освобождает шину SPI даже когда не выбран кристал (CS). Однако этот баг чипа давно пофикисили установив логическую микросхему на последней версии ethernet shield. Если у вас последняя то все должно работать на ура.

в крайнем случае можно подключить отдельно SD карту и работать с ней по программной шине SPI

NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013

Делал такой же серв -  возникали проблемы только с получением списка файлов при одновременной записи в этой же директории(производилась запись лога по времени). Сами файлы всегла отдавались как положенно и если открывать другую папку то список также отображался корректно. Работало это дело на стандартном EthernetShield W5100 с SD Card на меге 2560. Я пришол к выводу что проблема в самой библиотеке - где то не обнуляется состояние - ведь работа с поддирикториями шла без проблем. До первой процедуры записи в файл(после перезагрузки) - список показывался так как должен показываться.

Вобщем если решите делать массив то придется ограничить максимальную длинну имени файла и максимальное количество файлов в обрабатываемой папке, потому что С плохо работает с динамическими массивами.

char fs_cache[100][10];//отожрет 1 кб драгоценной памяти.

С другой стороны если файлы нормально читаются в любое время то в каждой папке можно создать ".index" файл CSV формата и туда все запихать при сканировани папок, потом просто читать этот файл.

axill
Offline
Зарегистрирован: 05.09.2011

Си прекрасно работает с динамическими переменными;) это МК плохеет из-за малого размера оперативки

и если у меги ее 8кб то у UNO в 4 раза меньше

и память нужна не только переменным, а еще и на програмный стек. К тому же ардуино использует не Си, а Си++, а это дополнительный расход памяти на скрытые переменные

Datak
Offline
Зарегистрирован: 09.10.2014

Andrey_Y_Ostanovsky пишет:
Если бы Вы потрудились хотя бы почитать описание шилда - у Вас бы не возникало таких вопросов. Да, оно там by design так работает.
Я так-то сильно ленивый, да, трудиться не люблю. :) Но раз уж влез - пришлось погуглить, куда деваться.
Цитата:
Отметим, что поскольку W5100 и карта SD разделяют шину SPI, только одновременно работать они не могут
Окончательно и бесповоротно. В оригинале всё как-то помягче было.
Цитата:
Note that because the W5100 and SD card share the SPI bus, only one can be active at a time.

Поскольку W5100 and SD разделяют одну шину SPI, они не могут быть активны одновременно.

Думаю, имеется в виду именно активность на шине SPI. В это я охотно верю, да.

Но ещё раз говорю - сам ничего не пробовал, поэтому ни на чём не настаиваю.
Если не прав - прошу прощенья. :)

axill
Offline
Зарегистрирован: 05.09.2011

МК всю работу делает последовательно, так что з за того, что на шине SPI одновременно может быть активно только одно устройство проблем вообще никаких нет.

NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013

Писали же что W5100 любит быть единственнным у микроконтроллера на шине. Аппаратный баг его.

axill
Offline
Зарегистрирован: 05.09.2011

NeiroN пишет:

Писали же что W5100 любит быть единственнным у микроконтроллера на шине. Аппаратный баг его.

на последних шилдах этот баг исправлен так как рекомендовано производителем чипа

rene
Offline
Зарегистрирован: 21.01.2014

Разобрался в чем дело, у меня и без всяких массивов памяти не хватало, потому и не работал скетч. Отключил библиотеку часов реального времени, все забегало как положено, теперь вот думаю, откуда время брать, может по NTP?

Всем спасибо за помощь!