Передача большого файла на ардуино

Тема в разделе "Arduino & Shields", создана пользователем gonzales, 6 фев 2017.

  1. gonzales

    gonzales Гик

    Доброго времени суток!
    Подскажите, что не так. Отправляю на ардуину файл по TCP, соответственно использую EthernetShield для работы.

    Пишу вот такой код
    Код (C++):
    #include <SPI.h>
    #include <Ethernet.h>

    #define MAX_BUFFER_SIZE 512

    byte mac[] = {
      0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
    };
    EthernetServer server(80);

    byte ip[] = {10, 0, 0, 174};

    void setup() {
      Serial.begin(9600);
      Ethernet.begin(mac, ip);
      server.begin();

      Serial.println("server is at ");
      Serial.println(Ethernet.localIP());
    }

    void loop() {
      byte filebuffer[MAX_BUFFER_SIZE];
      int filesize = 1;
      EthernetClient client = server.available();
      if (client) {
        while (client.available()) {
          int t = client.read(filebuffer, MAX_BUFFER_SIZE);
          delay(100);
          Serial.println(filesize);
          Serial.println(t);
          filesize = filesize + 1;
        }
        Serial.println("Write-OK");
        Serial.println("getfile-false");
      }
    }
    Передаю на ардуино файл
    В мониторе наблюдаю такую картину

    Код (C++):
    server is at
    10.0.0.174
    1
    512
    2
    512
    3
    512
    4
    512
    5
    512
    6
    512
    7
    512
    8
    512
    9
    512
    10
    512
    11
    512
    12
    512
    13
    512
    14
    512
    15
    512
    16
    512
    17
    512
    18
    512
    Write-OK
    getfile-false
    1
    512
    Write-OK
    getfile-false
    1
    512
    2
    512
    3
    512
    4
    276
    Write-OK
    getfile-false
     
    ТО есть, как будто while (client.available()) дает отрицательный результат, хотя файл до конца еще не прочитался.
    Может кто подскажет, что это значит и как с этим бороться?
     
  2. rkit

    rkit Гуру

    Не отрицательный результат оно возвращает, а ноль, скорее всего. Потому что не пришло еще ничего.
     
  3. gonzales

    gonzales Гик

    Ну понятно что ноль, отрицательный для меня. Считаете это нормально и надо код писать с учетом, что на входе может и не быть данных?
     
  4. rkit

    rkit Гуру

    Знаю, что это нормально. Данные не могут волшебно все разом скопироваться во входной буфер шилда.
     
  5. gonzales

    gonzales Гик

    ок, понял. А какой посоветуете размер буфера для передачи?
     
  6. mcureenab

    mcureenab Гуру

    В пределах 2кБайт, не более. Сильно большой буфер не нужен в силу того что размер аппаратного буфера в шилде ограничен.
    На чтение в слишком маленький буфер будет много накладных расходов (вызов функции тоже что-то стоит).
    Экспериментально можно установить начиная с какого размера рост производительности становится незначительным.

    Для завершения работы нужно определить признак конца файла. Это может быть символ в самом файле, а может быть завершение сеанса.

    client.connected()

    Функция client.available() говорит лишь о том, что в буфере шилда есть непрочитанные данные и их можно прочитать немедленно. Но если данных нет, это не значит, что передача завершена. Нужно подождать когда данные появятся или сеанс завершится.
     
  7. rkit

    rkit Гуру

    В меге 328 всего 2к памяти.
     
  8. gonzales

    gonzales Гик

    интересная мысль, надо попробывать.
    у меня даже блоки по 512 не залезают на флешку (уж не знаю почему), максимум 128. Вопрос на самом деле был больше по стабильности, не будет ли проблем с большим буфером в плане того, что будет искажение информации
     
  9. mcureenab

    mcureenab Гуру

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

    Нужно заметить, что read копирует в буфер столько байт, сколько шилд уже принял. Т.е. буфер может быть заполнен не до конца, хотя файл еще не закончился.
     
  10. gonzales

    gonzales Гик

    ну да, собственно read и возвращает кол-во считанных байт.

    А вот такая конструкция не работает
    Код (C++):
    #include <SPI.h>
    #include <Ethernet.h>

    #define MAX_BUFFER_SIZE 512

    byte mac[] = {
      0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
    };
    int filesize = 0;
    bool startfile = false;
    EthernetServer server(80);

    byte ip[] = {10, 0, 0, 174};

    void setup() {
      Serial.begin(9600);
      Ethernet.begin(mac, ip);
      server.begin();

      Serial.println("server is at ");
      Serial.println(Ethernet.localIP());
    }

    void loop() {
      byte filebuffer[MAX_BUFFER_SIZE];
      EthernetClient client = server.available();
      if (client.connected()==true) {
        while (client.available()) {
          startfile=true;
          int t = client.read(filebuffer, MAX_BUFFER_SIZE);
          //Serial.println(t);
          filesize = filesize + t;
        }
      }
      else {
        if (startfile==true){
          Serial.println("Write-OK");
          Serial.println(filesize);
          startfile=false;
        }
      }
    }
    В мониторе
    Код (C++):
    server is at
    10.0.0.174
    Write-OK
    1460
    Write-OK
    2920
    Write-OK
    4380
    Write-OK
    5840
    Write-OK
    7300
    Write-OK
    8760
    Write-OK
    10220
    Write-OK
    11540
     
    То есть получается соединение тоже сбрасывается, хотя на стороне клиента соединение установлено
     
  11. gonzales

    gonzales Гик

    Остается опираться на размер файла. Сначала передавать размер, а уже потом файл и сравнивать кол-во считанных байт с размером.
     
  12. mcureenab

    mcureenab Гуру

    Вы каждый раз нового клиента создаёте после того как буфер опустошился.
    Вместо
    Код (C++):
    if (client.connected()==true)
    тоже цикл нужен.
     
  13. gonzales

    gonzales Гик

    Не понял. Не затруднит поправить скетч как нужно?
     
  14. gonzales

    gonzales Гик

    не подскажете, как очистить буфер шилда после client.read()?
    У меня происходит следующая вещь, я посылаю запрос на ардуино, что сейчас буду передавать файл и размер этого файла. Программа переходит на прием файла. Файл принимается, но он битый. В нем в одном месте вместа принятых байт стоят байты из моего последнего запроса:(:(:(
    Причем стоят они не в хаотичном месте, а в строго определенном, занимают последние 13 байт (это длина моего запроса) в буфере 2048 байт. Если кинуть файл больше 4096 байта, то такая конструкция встретится 2 раза. Такое впечатление, что буфер приема шилда не очищается.
     
  15. gonzales

    gonzales Гик

    Если кидать файл напрямую, без предварительного запроса, то все ок, файл записывается правильный.
     
  16. gonzales

    gonzales Гик

    Все одолел.
    Вот рабочая процедура.
    Пишет блоками определенного размера
    Код (C++):
    void Getfile() {
      bool errorflag = false;
      byte filebuffer[MAX_BUFFER_SIZE];
      SWITCH_TO_W5100;
      EthernetClient client = server.available();
      if (client) {
        while (client.available()) {
          int t = client.read(filebuffer, MAX_BUFFER_SIZE);
          Serial.print("Client read-");
          Serial.println(t);
          SWITCH_TO_SD;
          File myFile = SD.open(uploadfilename, FILE_WRITE);
          if (myFile) {
            myFile.seek(pos);
            int t1 = myFile.write(filebuffer, t);
            delay(20);
            Serial.print("Write to SD -");
            Serial.println(t1);
            myFile.flush();
            myFile.close();
            if (t1 != t) {
              Serial.println("ERROR");
              errorflag = true;
              break;
            }
            else {
              pos = pos + t1;
              filesize = filesize + t;
              Serial.println(filesize);
              SWITCH_TO_W5100;
            }
          }
        }
       
        if (filesize == uploadfilesize && errorflag == false) {
          Serial.println("Write-OK");
          pos = 0;
          filesize = 0;
          getfile = 0;
        }
        else if (errorflag == true) {
          Serial.println("Write-ERROR");
          pos = 0;
          getfile = 0;
          filesize = 0;
        }
      }
    }
     
    ИгорьК и arkadyf нравится это.