Как правильно обработать ошибки взятые из библиотеки DFRobotDFPlayerMini, или почему у меня не получается корректно их обработать?

Я использую: w5500, arduino nano, DFPlayer Mini
Библиотеки:
ArduinoJson.h
SPI.h
Ethernet2.h
DFRobotDFPlayerMini.h
SoftwareSerial.h

В документации к библиотеки DFRobotDFPlayerMini приводится код для обработки ошибок:

void printDetail(uint8_t type, int value){
  switch (type) {
    case TimeOut:
      Serial.println(F("Время вышло"));
      break;
    case WrongStack:
      Serial.println(F("Стек неправильный!"));
      errorMp3();
      break;
    case DFPlayerCardInserted:
      Serial.println(F("Карта вставлена!"));
      if(read == 1){
         asm volatile("jmp 0x00");
         read =0;
      }
      break;
    case DFPlayerCardRemoved:
      Serial.println(F("Карта извлечена!"));
      read = 1;
      break;
    case DFPlayerCardOnline:
      Serial.println(F("Карта онлайн!"));
      if(read == 1){
         asm volatile("jmp 0x00");
         read =0;
      }
      break;
    case DFPlayerUSBInserted:
      Serial.println("USB вставлен!");
      break;
    case DFPlayerUSBRemoved:
      Serial.println("USB удален!");
      break;
    case DFPlayerPlayFinished:
      Serial.println(F("Воспроизведение завершено!"));
      break;
    case DFPlayerError:
      Serial.print(F("Ошибка DFPlayer:"));
      switch (value) {
        case Busy:
          Serial.println(F("Карта не найдена "));errorMp3();
          break;
        case Sleeping:
          Serial.println(F("Спящий "));errorMp3();
          break;
        case SerialWrongStack:
          Serial.println(F("Получите неправильный стек"));errorMp3();
          break;
        case CheckSumNotMatch:
          Serial.println(F("Контрольная сумма не совпадает "));errorMp3();
          break;
        case FileIndexOut:
          Serial.println(F("Индекс файла вышел за пределы "));errorMp3();
          break;
        case FileMismatch:
          Serial.println(F("Невозможно найти файл "));errorMp3();
          break;
        case Advertise:
          Serial.println(F("В рекламе "));errorMp3();
          break;
        default:
          break;
      }
      break;
    default:
      break;
  }

}

printDetail(myDFPlayer.readType(), myDFPlayer.read());

myDFPlayer.readType() и myDFPlayer.read() содержат в себе коды, например: myDFPlayer.readType()==3 и myDFPlayer.read()==0 означает что карта памяти не вставлена. Так и не понял, почему это имеено так работает, если внутри этой функции printDetail() обрабатываются не коды, а названия, например: DFPlayerCardRemoved - карта извлечена.

Теперь я по этим кодам пытаюсь обработать воспроизведение mp3 файла, выглядит это так:

myDFPlayer.playMp3Folder(ID);
if(myDFPlayer.readType()==3 && myDFPlayer.read()==0){
      doc["SD"] = "mp3";
      doc["MP3"] = ID;
      doc["statusText"] = "Карта памяти не вставлена! 0000";
      doc["status"] = false;
}else{
       Serial.println();
       Serial.print(myDFPlayer.readType());Serial.print("|");Serial.print(myDFPlayer.read());
       Serial.println();
       if(myDFPlayer.readType()==6 && myDFPlayer.read()==6){
           doc["SD"] = "mp3";
           doc["MP3"] = ID;
           doc["statusText"] = "Такого файла нет! 0";
           doc["status"] = false;
           doc["E1"] = myDFPlayer.readType();
           doc["E2"] = myDFPlayer.read();
       }else if(myDFPlayer.readType()==5 && myDFPlayer.read()==1){
           doc["SD"] = "mp3";
           doc["MP3"] = ID;
           doc["statusText"] = "Файл воспроизводится! 1";
           doc["status"] = true;
           doc["E1"] = myDFPlayer.readType();
           doc["E2"] = myDFPlayer.read();
       }else{
           doc["SD"] = "mp3";
           doc["MP3"] = ID;
           doc["statusText"] = "Произошла не известная ошибка!";
           doc["status"] = false;
           doc["E1"] = myDFPlayer.readType();
           doc["E2"] = myDFPlayer.read();
       }
}
serializeJsonPretty(doc,client); //Отдать инфу клиенту

Теперь, когда я включаю ардуино, и после инциализации пытаюсь открыть ссылку мойip/?dir=mp3&name=1, где name =1 это тот файл который я запускаю. В первый раз, после запуска arduino, я получаю код “4|1” что под моим подсчетам является “карта онлайн”. И не важно есть файл или нет, я всегда получаю “4|1”, если такой файл есть, плеер его воспроизводит. Повторно когда я открываю эту ссылку, я получаю либо “6|6” о чем мне говорит что файла нет, либо 5.1 что говорит о том, что файл запустился.

Теперь вопрос, почему при старте я получаю код “4|1”? и по итогу не правильную инфу о файле…

теперь я обнаружил другой косяк:
когда открываю сайт и проверяю на сайте работу get запросов, которые имеют точно такую же ссылку, только отправляются ajax запросом, у меня от куда то появляется код “5|2”… и причем если у меня файла нет, я сначала получу код “5|2” а при повторном нажатии код “6|6”

Весь код на мой скетч:

#include <ArduinoJson.h>
#include <SPI.h>
#include <Ethernet2.h>
#include "DFRobotDFPlayerMini.h"
#include <SoftwareSerial.h>
DFRobotDFPlayerMini myDFPlayer;
int type = 0;
int read = 0;
SoftwareSerial mySoftwareSerial(8, 9);
int launchMp3 = 1;  // звук при старте
int ErMp3 = 1;      // звук при ошибке
int start = 1;
int countMp3 = 0;
int total_files_cnt = 0;
int files_in_folder = 0;
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 1, 177);
EthernetServer server(80);
int startArduino = 0;
void setup() {
  startArduino = 1;
  Serial.begin(9600);
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("IP: ");
  Serial.println(Ethernet.localIP());
  mySoftwareSerial.begin(9600);
  Serial.begin(9600);

  Serial.println();
  Serial.println("Инициализация...");
  if (!myDFPlayer.begin(mySoftwareSerial)) {
    read = 1;
    Serial.println("Не удается начать:");
    Serial.println("1.Пожалуйста, еще раз проверьте подключение!");
    Serial.println("2.Пожалуйста, вставьте SD-карту!");
    //delay(1000);
  } else {
    //Получаю информацию о количестве файлов и настраиваю плеер
    total_files_cnt = myDFPlayer.readFileCounts();
    delay(300);
    files_in_folder = myDFPlayer.readFileCountsInFolder(1);
    delay(300);
    myDFPlayer.volume(30);
    myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);
    myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);
    Serial.println(F("Инициализация прошла успешно!"));
    delay(100);
    countMp3 = total_files_cnt - files_in_folder;
  }
}
int types = 0;
String ase = "";

void loop() {

  if (startArduino == 1) {
    myDFPlayer.playFolder(01, 1);
    startArduino = 0;
  }


  if (myDFPlayer.available()) {
    printDetail(myDFPlayer.readType(), myDFPlayer.read());
    // Serial.println(ase);//Вывести подробное сообщение от DFPlayer для обработки различных ошибок и состояний.  }
  }
  EthernetClient client = server.available();
  if (client) {
    boolean ok = true;
    String val;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        val += c;
        if (c == '\n') {
          //Сначала я получаю get из строки http://192.168.1.177/?dir=mp3&name=2
          /*Тут я получаю GET первого параметра*/
          int getSearch = val.indexOf("?");
          int getSearchL = val.indexOf("=");
          String GET = val.substring(getSearch + 1, getSearchL);
          //тут я получаю значение первого параметра
          int keySearch = val.indexOf("=");
          int keySearchL = val.indexOf("&");
          String DIR = val.substring(keySearch + 1, keySearchL);
          /*Тут я получаю GET второго параметра*/
          int getSearch1 = val.indexOf("&");
          int getSearchL1 = val.lastIndexOf("=");
          String GET1 = val.substring(getSearch1 + 1, getSearchL1);
          //тут я получаю значение второго параметра
          int keySearch1 = val.lastIndexOf("=");
          int keySearchL1 = val.lastIndexOf(" ");
          String key = val.substring(keySearch1 + 1, keySearchL1);
          int ID = atoi(key.c_str());

          int k = GET1.indexOf("&") + 1;  //Если нет второго параметра и я использую первый параметр
          val = "";
          /*
          GET - первый параметр 
          DIR - и его значение
          GET1- второй параметр
          ID - и его значение
          */
          JsonDocument doc;  //Переменная json
          if (GET == "dir") {
            if (DIR == "mp3") {
              //если я пытаюсь запустить файл из папки mp3
              if (GET1 == "name") {  //Проверяю название параметра
                if (ID > 0) {        //Если я пытаюсь запустить файл с названием больше чем 0000.mp3


                  Serial.print("Пытаюсь запустить файл под номером: ");
                  Serial.println(ID);

                  //пытаюсь запустить файл
                  myDFPlayer.playMp3Folder(ID);

                  if (myDFPlayer.readType() == 3 && myDFPlayer.read() == 0) {
                    //Если карта памяти не вставлена, то вывжу json инфу об этом клиенту
                    doc["SD"] = "mp3";
                    doc["MP3"] = ID;
                    doc["statusText"] = "Карта памяти не вставлена! 0000";
                    doc["status"] = false;
                  } else {
                    Serial.println();
                    Serial.print(myDFPlayer.readType());
                    Serial.print("|");
                    Serial.print(myDFPlayer.read());
                    Serial.println();


                    if (myDFPlayer.readType() == 6 && myDFPlayer.read() == 6) {
                      //Если файла нет
                      doc["SD"] = "mp3";
                      doc["MP3"] = ID;
                      doc["statusText"] = "Такого файла нет! 0";
                      doc["status"] = false;
                      doc["E1"] = myDFPlayer.readType();
                      doc["E2"] = myDFPlayer.read();
                    } else if (myDFPlayer.readType() == 5 && myDFPlayer.read() == 1) {
                      //Если файл есть
                      doc["SD"] = "mp3";
                      doc["MP3"] = ID;
                      doc["statusText"] = "Файл воспроизводится! 1";
                      doc["status"] = true;
                      doc["E1"] = myDFPlayer.readType();
                      doc["E2"] = myDFPlayer.read();
                    } else {
                      //Если что то пошло не так
                      doc["SD"] = "mp3";
                      doc["MP3"] = ID;
                      doc["statusText"] = "Произошла не известная ошибка!";
                      doc["status"] = false;
                      doc["E1"] = myDFPlayer.readType();
                      doc["E2"] = myDFPlayer.read();
                    }
                  }
                  serializeJsonPretty(doc, client);  //Отдать инфу клиенту
                } else {
                  //если пустой параметр или название файла меньше 1
                  Serial.println("пустой параметр или название файла меньше 1");
                }
              } else {
                Serial.print("Значение: ");
                Serial.print(GET1);
                Serial.print(" нет в базе данных");
                Serial.println("");
              }
            } else {
              if (k == 0) {
                int keySearch0 = DIR.indexOf("");
                int keySearchL0 = DIR.lastIndexOf(" ");
                String DIRs = DIR.substring(keySearch0, keySearchL0);
                if (DIRs == "info") {  //Тут в цикле мы выводим какую то инфу, в данном случае информацию о состоянии SD карты
                  if (myDFPlayer.readType() == 3 && myDFPlayer.read() == 0) {
                    //Если карта памяти извлечена
                    doc["SD"] = false;
                    types = 1;
                  } else {
                    if (read == 1) {
                      doc["SD"] = false;
                      types = 1;
                    } else {
                      doc["SD"] = true;
                      if (types == 1) {
                        asm volatile("jmp 0x00");
                        types = 0;
                      }
                    }
                  }
                } else {
                  doc["error"] = "Мы не можем найти такую директорию";
                }
                serializeJsonPretty(doc, client);  //Отдать инфу клиенту
                break;
              } else {
                doc["error"] = "Мы не можем найти такую директорию";
                serializeJsonPretty(doc, client);  //Отдать инфу клиенту
              }


              break;
            }
            break;
          } else {
            Serial.println("Открываю сайт");
            site(client);
            break;
          }
        }
      }
    }
    delay(1);
    client.stop();
  }
}



void site(EthernetClient client) {
  //Собственно сам сайт

  client.println("<!DOCTYPE HTML>");
  client.print("<html><head><meta charset='UTF-8'><title>Главная</title>");
  client.print(F("<style>.info{display:none;width: 250px;margin: 0 auto;min-height: 100px;position: fixed;background: #d82a2a;left: 50%;margin-left: -125px;box-shadow: 0 0 6px 5px #000;color: #fff;}.title{text-align: center;font-size: 20px;font-weight: 700;}#home1 .button{width: 241px;padding: 5px;margin: 6px 2px;background: #2a51d8;color: #fff;border: none;border-radius: 7px;box-shadow: 0 0 2px 1px #000;cursor: pointer;}.homeInfo p{padding: 0;margin: 0;}#home1,#documentation1,#settings1{ padding: 5px;}.content .activeBlock{display: block;}.content{width: 500px;margin: 0 auto;min-height: 500px;box-shadow: 0 0 6px 1px #000;}.menu{width: 100%;background: #2a51d8;}.menu{width: 100%;background: #2a51d8;}.menu span{padding: 18px 0;display: inline-block;color: #ffffff;width: 162px;text-align: center;}.menu span:hover{background: #00000026;cursor: pointer;}.menu .active{background: #00000026;}i{width: 7px;display: inline-block;}</style></head>"));
  client.print(F("<body><div class='info'></div><div class='content'>"));
  client.print(F("<div class='menu'><span onclick='menu(this)' id='home' class='active'>Главное</span><i></i><span onclick='menu(this)' id='documentation'>Документация</span><i></i><span onclick='menu(this)' id='settings'>Настройки</span></div>"));
  client.print(F("<div id='home1' class='activeBlock'>"));
  client.print(F("<div class=homeInfo><p class=title>Информация</p><p id=stmp3>Статус mp3 проигрователя: online</p><p id=sdonline>Активность карты памяти: Работает</p><p id=colMp3>Всего mp3 файлов на sd:"));
  client.print(total_files_cnt);
  client.print(F("шт.</p><p>MP3 файлов в папке mp3:"));
  client.print(countMp3);
  client.print(F("шт</p>"));
  if (files_in_folder > 0) {
    //Если нужно будет обрабатывать 01 папку
    //client.print(F("<p>MP3 файлов в папке 01:")); client.print(files_in_folder); client.print(F("шт</p>"));
  }

  client.print(F("<div><p class='title'>Тест MP3 файлов в папке mp3</p>"));

  for (int i = 1; i <= countMp3; i++) {
    client.print(F("<button class='button' onclick="
                   "\"mp3('mp3',"));
    client.print(i);
    client.print(F(")"
                   "\">Запустить аудиофайл №"));
    client.print(i);
    client.print(F("</button>"));
  }
  client.print(F("</div>"));
  client.print(F("<div  style='display:none' id='documentation1'>Документы</div>"));
  client.print(F("<div style='display:none' id='settings1'>Настройки</div>"));
  client.print(F("<script>function menu(data){var id = data.id;document.querySelector('.active').removeAttribute('class');document.querySelector('#'+id).setAttribute("
                 "\"class"
                 "\",'active');document.querySelector('.activeBlock').setAttribute('style','display: none;');document.querySelector('.activeBlock').removeAttribute('class');document.querySelector('#'+id+'1').removeAttribute('style');document.querySelector('#'+id+'1').setAttribute("
                 "\"class"
                 "\",'activeBlock');}"));
  client.print(F("function mp3(d,f){ajax({url:"
                 "\"/?dir="
                 "\"+d+"
                 "\"&name="
                 "\"+f,success: function(data){console.log(data)}});}"));
  //client.print(F("window.onload = function(){};"));
  client.print(F("var asse=0; setInterval(function (){ajax({url:'/?dir=info',success: function(data){if(data.SD==false){asse=1}if(data.SD==true){if(asse==1){location.reload();asse=0}}}});},1000);"));
  client.print(F("function ajax(e) {var url = e.url;document.querySelector('.info').innerHTML='';let xhr = new XMLHttpRequest();xhr.open('GET', url);xhr.send();xhr.responseType = 'json';xhr.onload = function() {let responseObj = xhr.response;e.success(responseObj);}}</script>"));
  client.print("</body></html");
}



void errorMp3() {  //эту функцию еще не реализовывал
  //if(myDFPlayer.readFileCountsInFolder(1)){myDFPlayer.playFolder(01,2);}
}

void printDetail(uint8_t type, int value) {  //функция ошибок
  switch (type) {
    case TimeOut:
      //Serial.println(F("Время вышло"));
      return "Время вышло";
      break;
    case WrongStack:
      //Serial.println(F("Стек неправильный!"));
      return "Стек неправильный!";
      errorMp3();
      break;
    case DFPlayerCardInserted:
      //Serial.println(F("Карта вставлена!"));
      return "Карта вставлена!";
      if (read == 1) {
        asm volatile("jmp 0x00");
        read = 0;
      }
      break;
    case DFPlayerCardRemoved:
      read = 1;
      return "Карта извлечена!";
      //Serial.println(F("Карта извлечена!"));

      break;
    case DFPlayerCardOnline:
      //Serial.println(F("Карта онлайн!"));

      if (read == 1) {
        asm volatile("jmp 0x00");
        read = 0;
      }
      return "Карта онлайн!";
      break;
    case DFPlayerUSBInserted:
      Serial.println("USB вставлен!");
      break;
    case DFPlayerUSBRemoved:
      Serial.println("USB удален!");
      break;
    case DFPlayerPlayFinished:
      return "Воспроизведение завершено!";
      Serial.println(F("Воспроизведение завершено!"));
      break;
    case DFPlayerError:
      return "Ошибка DFPlayer:";
      Serial.print(F("Ошибка DFPlayer:"));
      switch (value) {
        case Busy:
          return "Время вышло";
          Serial.println(F("Карта не найдена "));
          errorMp3();
          break;
        case Sleeping:
          Serial.println(F("Спящий "));
          errorMp3();
          return "Время вышло";
          break;
        case SerialWrongStack:
          Serial.println(F("Получите неправильный стек"));
          errorMp3();
          return "Время вышло";
          break;
        case CheckSumNotMatch:
          Serial.println(F("Контрольная сумма не совпадает "));
          errorMp3();
          return "Время вышло";
          break;
        case FileIndexOut:
          Serial.println(F("Индекс файла вышел за пределы "));
          errorMp3();
          return "Время вышло";
          break;
        case FileMismatch:
          Serial.println(F("Невозможно найти файл "));
          errorMp3();
          return "Время вышло";
          break;
        case Advertise:
          Serial.println(F("В рекламе "));
          errorMp3();
          break;
        default:
          break;
      }
      break;
    default:
      break;
  }
}


Так это вам про директиву #define надо почитать
P.S.

Спойлер

2 лайка

Вообще полезно исходный код используемой библиотеки посмотреть. Особенно если что-то не понятно))

2 лайка

А return здесь к месту?(стр.319)

в этом коде даже abort() к месту

Код честно списан из библиотеки, но зачем-то добавлен return,
который и не даёт понять, что за ошибка))

return я добавлял для эксперимента, думал вытащить название ошибки и передать клиенту. Но это так не работает и я пошел другим путем.

Я решил сделать проверки в то время, когда я обращаюсь с помощью get запроса, например:
/?dir=mp3&name=5 должен запустить 5 файл из папки mp3. Теперь в коде я делаю проверку: если в гет запрос попала директория dir и я запускаю 5 файл, то…
Далее я пытаюсь запустить, и делаю очередные проверки:

  1. вставлена ли карта памяти
  2. есть ли такой файл
  3. если есть, то выдать об этом сообщение

И все вроде как работает, только с какой то 2-5 попытки, постоянно показывает разные значения. Я устал с этим мучаться, и решил спросить тут.

По поводу самой функции ошибок, мне пока в принципе на эту функцию все равно. Так как я проверки устраиваю в обход этой функции.

Сейчас я пытаюсь понять, почему я получаю разные значения…

Сюда можно вставлять видео, к примеру с ютуба? Я б заснял видео, и объяснил бы по видео в чем именно проблема

Вот тут видео того, как введет себя скетч

Активные участники в большинстве своем не станут открывать вашу ссылку, ибо являются приверженцами правильности медленного Ютуб.

1 лайк

Если проблема только в этом, то перезлил себе на хостинг https://sa86.ru/
Судя по видео у меня выводится код предыдущего запуска. А 4.5 это карта онлайн, выводится в самом начале когда плеер запускается. И да, я пробовал ставить задержку между включением аудио и выводом кода, тоже самое

Как по мне, код , местами, трудночитаемый, я бы максимально упростил, для отладки. Потом бы добавлял частями.

Здесь, к примеру, до
types = 0;
дойти не получится…

Та тут в данном случае вообще это не нужно, так как устройство перезагружается в случае вставки карты памяти… так что переменную types можно убрать

Вот и я о том: выкинуть всё лишнее из кода, оставить лишь кусок с проблемными параметрами.

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

Погоди, до компьютера дойду и посмотрю на нем. На планшете плохо понятно.

Смотри.
Вот тут что происходит?

          //тут я получаю значение второго параметра
          int keySearch1 = val.lastIndexOf("=");
          int keySearchL1 = val.lastIndexOf(" ");

Почему не с концом строки сравниваешь? (‘\0’).
Откуда в конце строки будет пробел?

Все очень просто, в мониторе у меня выходит такая строка: dir=mp3&name=1 HTTP/1.1
И я ищу значение, то что попадает между последним = и пробелом

Почему сразу так не написать? Как BOOM может это понять?

Оказывается, был ещё и “прошлый раз”))

Попробуйте так, как советуют по ссылке, что МММ дал
стр.32

 if (!myDFPlayer.begin(mySoftwareSerial, false, true)) {
1 лайк

Да и в видео не было никаких http/1.1 в конце.
Откуда это может появиться? Такое только хедеры добавляют и атнюдь не в конце GET запроса.

Вот, самый обычный код взятый из документации к библиотеке enternet2, на конце html 1.1… пока без того кода который я скидывал. Ну там еще val очистить надо, чтобы не повторялось