Hörbuchmodus Von - Bis mit Fortschritt Speicherung

Wenn jede Person ihre eigene Hörbuch-Karte hat, richtig?

Gut, das mit den mehreren Hörern des gleichen Hörspiels hatte ich noch nicht bedacht.

Ja, das war der Plan.
Wobei die 20 als Grenze ein erster Beispielwert ist. Man könnte auch bspw. 50 nehmen und wäre bei der 3 Bytes Variante auch nur bei 150 Bytes ingesamt.
Was wäre denn eine sinnvolle Grenze? 20? 50? 100? Ich habe da noch keine Erfahrung, da wir nicht so viele Nutzer und Hörbücher haben.

  • Eine Information, welche Hörbuchfortschritte gespeichert sind, könnte man vllt. im seriellen Monitor ausgeben. Eine Audio-Ansage fände ich unnötig.
  • Eine Nutzerentscheidung an dieser Stelle einzubeziehen ist nicht vorgesehen. Wenn eine Karte aufgelegt wird, die sehr lange nicht mehr gehört wurde (sodass ihr Fortschritt aus dem Speicher rausgeschoben wurde), fängt das Hörspiel wieder von vorn an - wenn man sich nach dieser vermeintlich langen Zeit noch an den Fortschritt erinnert, kann man immer noch manuell die Kapitel vorspringen.
  • Der Speicher wird auch nicht komplett gelöscht, sondern immer nur durch neue Hörbücher verändert.

Nicht allein, das stimmt.
Aber die zur UUID passende Konfiguration lade ich ja, wenn die Karte aufgelegt wird.
Auf diese Weise wäre die Funktion

  • Mehrere Nutzer des gleichen Hörbuches mit unterschiedlichem Fortschritt

realisierbar.
Allerdings bräuchte die Variante mit der UUID eben 9 Bytes pro Datensatz.
Wenn der EEPROM nicht groß anderweitig gebraucht wird, könnte man trotzdem immerhin 100 Fortschritte (900 Bytes) speichern.

Ist das bei deinen oder irgendwelchen Karten anders? Wenn die Karte weg ist, ist sie weg, ist sie weg.
Ohne Konfiguration auf einer Karte kann gar nichts abgespielt werden, egal ob mit oder ohne Fortschritt. (Konfigurationen aus dem EEPROM (Shortcuts) mal ausgenommen).

Genau.
Aber das muss nicht der Nutzer machen, das macht der Tonuino selbst.
Im Details:
Wenn das erste Mal ein neuer Titel für die aktuelle Karte angespielt wird:

  1. Alle Fortschritte sortieren, sodass der Fortschritt der aktuellen Karte der neueste ist (bspw. der letzte einer FIFO-Reihe)
  2. Den neuesten Fortschritt speichern

Wenn ein weiteres Mal ein neuer Titel für die gleiche Karte angespielt wird:

  1. Den neuesten Fortschritt speichern (Sortiert sind sie ja bereits, da es die gleiche Karte ist)

Hmm, wie wahrscheinlich ist es, dass man >10.000 oder gar 100.000 Titel hat/hört?!
Wenn das im Bereich des Möglichen liegt, wäre es wohl sinnvoller den EEPROM nur zu nutzen/schreiben, wenn keine Karte aufgelegt ist.

Genau jeder hat seine eigene Karte.

in meiner Anwendung kann man die Karte bei Verlust neu erstellen und sie greift auf den alten Speicherplatz zu.

Mir ist klar das „20“ nur ein angenommener Wert ist.
Es ist auch irrelevant wie viele das am Ende sind. Für dich mögen 20 genug sein, für einen anderen könnten 100 schon kanpp werden.

Auch der Zeitraum in dem die Speicherplätze befüllt werden ist nicht ab zu sehen.
Das kann in wenigen Tagen passieren. Dann ist es schon relevant ob ein „alter“ Platz gelöscht wird.

Wenn man einen kleinen Bereich im Speicher gut auslastet und die Box ein paar Jahre läuft, kann die Grenze sicher ein Problem werden. Aber dann muss halt ein neuer Arduino her.

Da wäre das Beschreiben des RFID Tags schon besser. Auch wenn man nicht im EEPROM puffert.
Die sind billig und austauschbar.
Im fall der AiO wäre es schade wenn man den EEPROM verheizt.

Mann muss auch kein Speicherhandling betreiben und nichts organisieren.

Nur abfangen, dass die Karte nicht von der Box genommen wird.

1 „Gefällt mir“

Da mein TonUINO-Nutzer sowohl zuhause als auch bei Oma und Opa eine Box stehen hat und sich schon das ein oder andere Mal gewundert hat, dass er bei Oma und Opa mit der selben Karten nicht an der gleichen Stelle im Hörbuch startet wie zuhause, finde auch ich die Idee mit dem Speicherstand auf der Karte recht spannend.
Erste Versuche habe ich schon gestartet.
@marco-117 's Fork ist da schon gut ausgestattet, und konnte mir einiges an Arbeit abnehmen. Ich konnte erst die writeCard() Funktion nicht ohne Fehler aufrufen, aber mit der regelmäßigen Abfrage des RFID-Readers von @mcgreg 's Stop-when-Card-away-Funktion klappt das Schreiben des Fortschritts auf den Tag reibungslos!
Da ich einige Anregungen aus dem Forum bei mir integiert habe (u.a. Hörbuch-reset, letzte Karte auf shortcut playtaste…) und ich eher mit copy und paste „programmiere“ macht mir das alles es natürlich nicht unbedingt leichter oder übersichtlich :rofl:
Versuche mir jetzt gerade zu überlegen, was ich überhaupt möchte, was passiert, falls die Karte nicht aufliegt und ob eine Alternative für mich überhaupt nötig ist.
Denn z.Zt. läuft es bei mir so, dass der Speicherstand immer geschrieben wird sobald eine Karte (wieder) aufliegt. Beim Fehlen der Karte wird der Speicherstand eben „übersprungen“.
Bei mcgreg gibt es schon die cases card away, card back, new card. Da kann man aber sicher drauf aufbauen.

2 „Gefällt mir“

Genau, das wäre meiner Meinung nach die beste Lösung. Wenn ich ein Buch (wirklich ein echtes Buch) lese und vergesse mein Lesezeichen an die aktuelle Seite zu legen, habe ich eben den vorletzten Stand des Fortschritts. Genau so wäre das wenn man die Karte beim beenden des Hörbuchs nicht aufgelegt hat. Außerdem kann dann jeder der das Buch gerade hört seine eigene Karte haben und seinen eigenen Fortschritt speichern.

Da die Grund-Idee mit dem Hörbuch von bis von marco-117 ist und er das in seinem Fork integriert hat und auch sein Fork die mcgreg Erweiterung nutzt, habe ich ihm meine Code-Schnipseleien zugeschickt.
Ich kann bei Bedarf versuchen, meine Anpassungen, nur auf die reine dev/main bezogen, zu säubern und hier bereit zu stellen.
Aber wie oben erwähnt, war ich nicht wirklich ordentlich und augeräumt beim Einpflegen der vielen guten Ideen hier aus dem Forum. Muss sehen, ob ich das sauber hin bekomme :woozy_face:

1 „Gefällt mir“

Das fände ich super. So könnte jeder (oder ich :see_no_evil:) genau diese Funktion in die eigene Software einbauen. Säubern kann man sie dann noch, wenn notwendig :wink: .

Ich nutze bei mir den Hörbuch-von-bis-Modus als Modus 10 zusätzlich zum regulären Hörbuch-Modus (Modus 5 aus der main).
Habe die Speicherung auf der Karte bisher nur im von-bis-Modus „eingepflegt“. Der Modus 5 speichert weiterhin im EEPROM.
Werde mich ran setzen und die Einzel-Teile zusammen suchen.

2 „Gefällt mir“

So, fange dann mal an :wink:
Ich hoffe ich vergesse nichts! Habe bisher nur den reinen „Abspiel-Betrieb“ ohne Modifier oder sonstiges getestet!
Zeilenangaben beziehen auf die main-Version heruntergeladen am 11.01.2021 14:24 Uhr.

in:
struct folderSettings {

  1. unter:
    uint8_t special2; (Zeile37)
    einfügen:
    uint8_t audiobookMem;

  2. nach:
    struct adminSettings { ... };

einfügen:

static bool hasCard = false;
static byte lastCardUid[4];
static byte retries;
static bool lastCardWasUL;
static bool forgetLastCard=false;
const byte PCS_NO_CHANGE = 0;    // no change detected since last pollCard() call
const byte PCS_NEW_CARD = 1;     // card with new UID detected (had no card or other card before)
const byte PCS_CARD_GONE = 2;    // card is not reachable anymore
const byte PCS_CARD_IS_BACK = 3; // card was gone, and is now back again

in:
static void nextTrack(uint16_t track) {

  1. nach:
    EEPROM.update(myFolder->folder, 1); (Zeile 580)

einfügen:
forgetLastCard=true;

  1. vor:
    delay(500); (Zeile 584)

einfügen:

//Anfang_neu_Hörbuch-von-bis
 if (myFolder->mode == 10) {
    if (currentTrack != numTracksInFolder) {
      currentTrack = currentTrack + 1;
      Serial.println(F("Hörbuch Modus -> nächster Track und Fortschritt speichern"));
      Serial.println(currentTrack);
      mp3.playFolderTrack(myFolder->folder, currentTrack);
  // Fortschritt auf Karte abspeichern
      writeAudiobookMemory2RFID (currentTrack);
    } else {
  // Fortschritt zurück setzen
      writeAudiobookMemory2RFID (0);
      forgetLastCard=true;
      setstandbyTimer();
    }
  }
//Ende_neu_Hörbuch-von-bis

in:
static void previousTrack() {
vor:
delay(1000); (Zeile 627)

einfügen:

//Anfang_neu_Hörbuch-von-bis
 if (myFolder->mode == 10) {
    Serial.println(F("Hörbuch Modus -> vorheriger Track und Fortschritt speichern"));
    if (currentTrack != firstTrack) {
      currentTrack = currentTrack - 1;
    }
    Serial.println(currentTrack);
    mp3.playFolderTrack(myFolder->folder, currentTrack);
  // Fortschritt auf Karte abspeichern
    writeAudiobookMemory2RFID (currentTrack);
  }

in:
void playFolder() {
vor:
} (Zeile 933)

einfügen:

//Anfang_neu_Hörbuch-von-bis: definierten Bereich eines Ordners wiedergeben und Fortschritt merken
  if (myFolder->mode == 10) {
    Serial.println(
      F("Spezialmodus Von-Bis: Hörbuch -> definierten Bereich eines Ordners wiedergeben und Fortschritt merken"));
    Serial.print(myFolder->special);
    Serial.print(F(" bis "));
    Serial.println(myFolder->special2);
    numTracksInFolder = myFolder->special2;
    firstTrack = myFolder->special;
    currentTrack = myFolder->audioBookMem;
    if (currentTrack < firstTrack || currentTrack >= firstTrack + numTracksInFolder) {
      currentTrack = firstTrack;
    }
    mp3.playFolderTrack(myFolder->folder, currentTrack);
  }
//Ende_neu_Hörbuch-von-bis

nach:
void playShortCut(uint8_t shortCut) { ... }

vor:
void loop() { (Zeile 948)

einfügen:

  // Um festzustellen ob eine Karte entfernt wurde, muss der MFRC regelmäßig ausgelesen werden
byte pollCard()
{
  const byte maxRetries = 2;

  if (!hasCard)
  {
    if (mfrc522.PICC_IsNewCardPresent())
    {
      if (mfrc522.PICC_ReadCardSerial())
      {
        Serial.print(F("ReadRFIDSerial done"));
        if (readCard(&myCard))
        {
      bool bSameUID = !memcmp(lastCardUid, mfrc522.uid.uidByte, 4);
      if (bSameUID) {
        Serial.println(F("Same RFID"));
      }
      else {
        Serial.println(F("New RFID"));
      }
  // store info about current card
      memcpy(lastCardUid, mfrc522.uid.uidByte, 4);
      lastCardWasUL = mfrc522.PICC_GetType(mfrc522.uid.sak) == MFRC522::PICC_TYPE_MIFARE_UL;
    
      retries = maxRetries;
      hasCard = true;
      return bSameUID ? PCS_CARD_IS_BACK : PCS_NEW_CARD;
          }
          else  // readCard war nicht erfolgreich
          {
            mfrc522.PICC_HaltA();
            mfrc522.PCD_StopCrypto1();
            Serial.println(F("RFID konnte nicht gelesen werden"));
    }
    }
    }
    return PCS_NO_CHANGE;
  }
  else  // hasCard
  {
  // perform a dummy read command just to see whether the card is in range
    byte buffer[18];
    byte size = sizeof(buffer);
    
    if (mfrc522.MIFARE_Read(lastCardWasUL ? 8 : blockAddr, buffer, &size) != MFRC522::STATUS_OK)
    {
      if (retries > 0)
      {
          retries--;
      }
      else
      {
          Serial.println(F("No RFID!"));
          mfrc522.PICC_HaltA();
          mfrc522.PCD_StopCrypto1();
          hasCard = false;
          return PCS_CARD_GONE;
      }
    }
    else
    {
        retries = maxRetries;
    }
  }
  return PCS_NO_CHANGE;
}

void handleCardReader()
{
  // poll card only every 100ms
  static uint8_t lastCardPoll = 0;
  uint8_t now = millis();
  
  if (static_cast<uint8_t>(now - lastCardPoll) > 100)
  {
    lastCardPoll = now;
    switch (pollCard())
    {
    case PCS_NEW_CARD:
      onNewCard();
      break;
    case PCS_CARD_GONE:
      break;
      
    case PCS_CARD_IS_BACK:
    if (!isPlaying()) 
    {
  // nur weiterspielen wenn vorher nicht konfiguriert wurde
      if (!forgetLastCard) 
      {
          mp3.start();
          disablestandbyTimer();
      }
      else 
      {
          onNewCard();
      }
    }
      break;
    }    
  }
}

in der
void loop() {

entfernen:
do { (Zeile 949)

ersetzen:
break; (Zeile 970)

durch:
return;

ersetzen: (ab Zeile 1000)

// Spezialmodus Von-Bis für Album und Party gibt die Dateinummer relativ zur Startposition wieder
if (myFolder->mode == 8 || myFolder->mode == 9) {
  advertTrack = advertTrack - myFolder->special + 1;
}
mp3.playAdvertisement(advertTrack);

durch:

//neu_Anfang_Hörbuch-von-bis
  // Spezialmodi Von-Bis für Album, Party und Hörbuch gibt die Dateinummer relativ zur Startposition wieder
        if (myFolder->mode == 8 || myFolder->mode == 9 || myFolder->mode == 10) {
          advertTrack = advertTrack - myFolder->special + 1;
        }
        mp3.playAdvertisement(advertTrack);
//neu_Ende_Hörbuch-von-bis

nach:
// Ende der Buttons (Zeile 1092)

ersetzen: (ab Zeile 1093)

  } while (!mfrc522.PICC_IsNewCardPresent());

  // RFID Karte wurde aufgelegt

  if (!mfrc522.PICC_ReadCardSerial())
    return;

  if (readCard(&myCard) == true) {

durch:

  handleCardReader();
}

void onNewCard()
{
   forgetLastCard=false;
  // make random a little bit more "random"
  randomSeed(millis() + random(1000));

löschen: (ab Zeile 1113)

  mfrc522.PICC_HaltA();
  mfrc522.PCD_StopCrypto1();
}

nach:
void adminMenu (bool fromCard = false) { (Zeile 1117)

einfügen:
forgetLastCard=true;

in:
else if (subMenu == 9) { (Zeile 1248)

ersetzen: ab (Zeile 1256)

uint8_t special = voiceMenu(mp3.getFolderTrackCount(tempCard.nfcFolderSettings.folder), 321, 0,
                            true, tempCard.nfcFolderSettings.folder);
uint8_t special2 = voiceMenu(mp3.getFolderTrackCount(tempCard.nfcFolderSettings.folder), 322, 0,
                             true, tempCard.nfcFolderSettings.folder, special);

durch:

uint8_t special = voiceMenu(mp3.getFolderTrackCount(tempCard.nfcFolderSettings.folder), 341, 0, true, tempCard.nfcFolderSettings.folder);
uint8_t special2 = voiceMenu(mp3.getFolderTrackCount(tempCard.nfcFolderSettings.folder), 342, 0, true, tempCard.nfcFolderSettings.folder, special);

vor: (Zeile 1348)
uint8_t voiceMenu(int numberOfOptions, int startMessage, int messageOffset, bool preview = false, int previewFromFolder = 0, int defaultValue = 0, bool exitWithLongPress = false) {

einfügen:

void writeAudiobookMemory2RFID (uint8_t mem) {
  nfcTagObject audioBookMem2Card;
  audioBookMem2Card.nfcFolderSettings.folder = myFolder->folder;
  audioBookMem2Card.nfcFolderSettings.mode = myFolder->mode;
  audioBookMem2Card.nfcFolderSettings.special = myFolder->special;
  audioBookMem2Card.nfcFolderSettings.special2 = myFolder->special2;
  audioBookMem2Card.nfcFolderSettings.audioBookMem = mem;
  mp3.pause();
  do {
  } while (isPlaying());
  writeCard(audioBookMem2Card);
}

unter:
// Wiedergabemodus abfragen (Zeile 1475)

ersetzen:
theFolder->mode = voiceMenu(9, 310, 310, false, 0, 0, true);

durch:
theFolder->mode = voiceMenu(10, 310, 310, false, 0, 0, true);

unter:
if (theFolder->mode == 4) (Zeile 1483)
ersetzen:

theFolder->special = voiceMenu(mp3.getFolderTrackCount(theFolder->folder), 320, 0,
                               true, theFolder->folder);

durch:

theFolder->special = voiceMenu(mp3.getFolderTrackCount(theFolder->folder), 340, 0, true, theFolder->folder);

unter:
// Spezialmodus Von-Bis (Zeile 1492)

ersetzen:

  if (theFolder->mode == 7 || theFolder->mode == 8 || theFolder->mode == 9) {
    theFolder->special = voiceMenu(mp3.getFolderTrackCount(theFolder->folder), 321, 0,
                                   true, theFolder->folder);
    theFolder->special2 = voiceMenu(mp3.getFolderTrackCount(theFolder->folder), 322, 0,
                                    true, theFolder->folder, theFolder->special);
  }

durch:

  if (theFolder->mode == 7 || theFolder->mode == 8 || theFolder->mode == 9 || theFolder->mode == 10) {
    theFolder->special = voiceMenu(mp3.getFolderTrackCount(theFolder->folder), 341, 0, true, theFolder->folder);
    theFolder->special2 = voiceMenu(mp3.getFolderTrackCount(theFolder->folder), 342, 0, true, theFolder->folder, theFolder->special);
  }

  // Speicherplatz Hörbuch-von-bis
  if (theFolder->mode == 10) {
    theFolder->audioBookMem = 0;
  }

unter:
writeCard(newCard); (Zeile 1512)

einfügen:
forgetLastCard=true;

unter:
tempCard.nfcFolderSettings.special2 = buffer[8]; (Zeile 1628)

einfügen:
tempCard.nfcFolderSettings.audioBookMem = buffer[9];

unter: (Zeile 1651 + 1652)

    mp3.pause();
  }

einfügen:

  mfrc522.PICC_HaltA();
  mfrc522.PCD_StopCrypto1();

ersetzen:
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 (Zeile 1708)
mit:

             nfcTag.nfcFolderSettings.audioBookMem,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00

mp3-Dateien wg. neuem Modus umbenennen 320 in 340 321 in 341 und 322 in 342
neue mp3 erstellen 320 „Hörbuch von-bis und Fortschritt auf Karte speichern“

Ich nutze von der mcgreg Erweiterung nur die regelmäßige Leser-Abfrage, die Möglichkeit, die Wiedergabe bei Entfernen der Karte zu stoppen ist so nicht mit dabei. Vermutlich ginge diese Abfrage auch ewas schlanker im Code, aber das übersteigt meine Fähigkeiten.
Und der neue Modus 10 ist, wie schon gesagt, bei marco-117 entnommen.

1 „Gefällt mir“