diff --git a/SD-Karte/mp3/0401_error.mp3 b/SD-Karte/mp3/0401_error.mp3 new file mode 100644 index 0000000..b6e4cca Binary files /dev/null and b/SD-Karte/mp3/0401_error.mp3 differ diff --git a/TonUINO/Tonuino.ino b/TonUINO/Tonuino.ino new file mode 100644 index 0000000..1a17221 --- /dev/null +++ b/TonUINO/Tonuino.ino @@ -0,0 +1,559 @@ +#include +#include +#include +#include +#include +#include + +// DFPlayer Mini +SoftwareSerial mySoftwareSerial(2, 3); // RX, TX +uint16_t numTracksInFolder; +uint16_t track; + +// this object stores nfc tag data +struct nfcTagObject { + uint32_t cookie; + uint8_t version; + uint8_t folder; + uint8_t mode; + uint8_t special; +}; + +nfcTagObject myCard; + +static void nextTrack(); +int voiceMenu(int numberOfOptions, int startMessage, int messageOffset, + bool preview = false, int previewFromFolder = 0); + +bool knownCard = false; + +// implement a notification class, +// its member methods will get called +// +class Mp3Notify { +public: + static void OnError(uint16_t errorCode) { + // see DfMp3_Error for code meaning + Serial.println(); + Serial.print("Com Error "); + Serial.println(errorCode); + } + static void OnPlayFinished(uint16_t track) { + Serial.print("Track beendet"); + Serial.println(track); + delay(100); + nextTrack(); + } + static void OnCardOnline(uint16_t code) { + Serial.println(F("SD Karte online ")); + } + static void OnCardInserted(uint16_t code) { + Serial.println(F("SD Karte bereit ")); + } + static void OnCardRemoved(uint16_t code) { + Serial.println(F("SD Karte entfernt ")); + } +}; + +static DFMiniMp3 mp3(mySoftwareSerial); + +// Leider kann das Modul keine Queue abspielen. +static void nextTrack() { + if (knownCard == false) + // Wenn eine neue Karte angelernt wird soll das Ende eines Tracks nicht + // verarbeitet werden + return; + + if (myCard.mode == 1) { + Serial.println(F("Hörspielmodus ist aktiv -> Strom sparen")); + mp3.sleep(); + } + if (myCard.mode == 2) { + if (track != numTracksInFolder) { + track = track + 1; + mp3.playFolderTrack(myCard.folder, track); + Serial.print(F("Albummodus ist aktiv -> nächster Track: ")); + Serial.print(track); + } else + mp3.sleep(); + } + if (myCard.mode == 3) { + track = random(1, numTracksInFolder + 1); + Serial.print(F("Party Modus ist aktiv -> zufälligen Track spielen: ")); + Serial.println(track); + mp3.playFolderTrack(myCard.folder, track); + } + if (myCard.mode == 4) { + Serial.println(F("Einzel Modus aktiv -> Strom sparen")); + mp3.sleep(); + } + if (myCard.mode == 5) { + if (track != numTracksInFolder) { + track = track + 1; + Serial.print(F("Hörbuch Modus ist aktiv -> nächster Track und " + "Fortschritt speichern")); + Serial.println(track); + mp3.playFolderTrack(myCard.folder, track); + // Fortschritt im EEPROM abspeichern + EEPROM.write(myCard.folder, track); + } else + mp3.sleep(); + } +} + +static void previousTrack() { + if (myCard.mode == 1) { + Serial.println(F("Hörspielmodus ist aktiv -> Track von vorne spielen")); + mp3.playFolderTrack(myCard.folder, track); + } + if (myCard.mode == 2) { + Serial.println(F("Albummodus ist aktiv -> vorheriger Track")); + if (track != 1) { + track = track - 1; + } + mp3.playFolderTrack(myCard.folder, track); + } + if (myCard.mode == 3) { + Serial.println(F("Party Modus ist aktiv -> Track von vorne spielen")); + mp3.playFolderTrack(myCard.folder, track); + } + if (myCard.mode == 4) { + Serial.println(F("Einzel Modus aktiv -> Track von vorne spielen")); + mp3.playFolderTrack(myCard.folder, track); + } + if (myCard.mode == 5) { + Serial.println(F("Hörbuch Modus ist aktiv -> vorheriger Track und " + "Fortschritt speichern")); + if (track != 1) { + track = track - 1; + } + mp3.playFolderTrack(myCard.folder, track); + // Fortschritt im EEPROM abspeichern + EEPROM.write(myCard.folder, track); + } +} + +// MFRC522 +#define RST_PIN 9 // Configurable, see typical pin layout above +#define SS_PIN 10 // Configurable, see typical pin layout above +MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 +MFRC522::MIFARE_Key key; +bool successRead; +byte sector = 1; +byte blockAddr = 4; +byte trailerBlock = 7; +MFRC522::StatusCode status; + +#define buttonPause A0 +#define buttonUp A1 +#define buttonDown A2 +#define busyPin 4 + +#define LONG_PRESS 1000 + +Button pauseButton(buttonPause); +Button upButton(buttonUp); +Button downButton(buttonDown); +bool ignorePauseButton = false; +bool ignoreUpButton = false; +bool ignoreDownButton = false; + +uint8_t numberOfCards = 0; + +bool isPlaying() { return !digitalRead(busyPin); } + +void setup() { + + Serial.begin(115200); // Es gibt ein paar Debug Ausgaben über die serielle + // Schnittstelle + randomSeed(analogRead(A0)); // Zufallsgenerator initialisieren + + Serial.println(F("TonUINO Version 2.0")); + Serial.println(F("(c) Thorsten Voß")); + + // Knöpfe mit PullUp + pinMode(buttonPause, INPUT_PULLUP); + pinMode(buttonUp, INPUT_PULLUP); + pinMode(buttonDown, INPUT_PULLUP); + + // Busy Pin + pinMode(busyPin, INPUT); + + // DFPlayer Mini initialisieren + mp3.begin(); + mp3.setVolume(15); + + // NFC Leser initialisieren + SPI.begin(); // Init SPI bus + mfrc522.PCD_Init(); // Init MFRC522 + mfrc522 + .PCD_DumpVersionToSerial(); // Show details of PCD - MFRC522 Card Reader + for (byte i = 0; i < 6; i++) { + key.keyByte[i] = 0xFF; + } + + // RESET --- ALLE DREI KNÖPFE BEIM STARTEN GEDRÜCKT HALTEN -> alle bekannten + // Karten werden gelöscht + if (digitalRead(buttonPause) == LOW && digitalRead(buttonUp) == LOW && + digitalRead(buttonDown) == LOW) { + Serial.println(F("Reset -> EEPROM wird gelöscht")); + for (int i = 0; i < EEPROM.length(); i++) { + EEPROM.write(i, 0); + } + } + +} + +void loop() { + do { + mp3.loop(); + // Buttons werden nun über JS_Button gehandelt, dadurch kann jede Taste + // doppelt belegt werden + pauseButton.read(); + upButton.read(); + downButton.read(); + + if (pauseButton.wasReleased()) { + if (ignorePauseButton == false) + if (isPlaying()) + mp3.pause(); + else + mp3.start(); + ignorePauseButton = false; + } else if (pauseButton.pressedFor(LONG_PRESS) && + ignorePauseButton == false) { + if (isPlaying()) + mp3.playAdvertisement(track); + else { + knownCard = false; + mp3.playMp3FolderTrack(800); + Serial.println(F("Karte resetten...")); + resetCard(); + mfrc522.PICC_HaltA(); + mfrc522.PCD_StopCrypto1(); + } + ignorePauseButton = true; + } + + if (upButton.pressedFor(LONG_PRESS)) { + Serial.println(F("Volume Up")); + mp3.increaseVolume(); + ignoreUpButton = true; + } else if (upButton.wasReleased()) { + if (!ignoreUpButton) + nextTrack(); + else + ignoreUpButton = false; + } + + if (downButton.pressedFor(LONG_PRESS)) { + Serial.println(F("Volume Down")); + mp3.decreaseVolume(); + ignoreDownButton = true; + } else if (downButton.wasReleased()) { + if (!ignoreDownButton) + previousTrack(); + else + ignoreDownButton = false; + } + // Ende der Buttons + } while (!mfrc522.PICC_IsNewCardPresent()); + + // RFID Karte wurde aufgelegt + + if (!mfrc522.PICC_ReadCardSerial()) + return; + + if (readCard(&myCard) == true) { + if (myCard.cookie == 322417479 && myCard.folder != 0 && myCard.mode != 0) { + + knownCard = true; + numTracksInFolder = mp3.getFolderTrackCount(myCard.folder); + + // Hörspielmodus: eine zufällige Datei aus dem Ordner + if (myCard.mode == 1) { + Serial.println(F("Hörspielmodus -> zufälligen Track wiedergeben")); + track = random(1, numTracksInFolder + 1); + Serial.println(track); + mp3.playFolderTrack(myCard.folder, track); + } + // Album Modus: kompletten Ordner spielen + if (myCard.mode == 2) { + Serial.println(F("Album Modus -> kompletten Ordner wiedergeben")); + track = 1; + mp3.playFolderTrack(myCard.folder, track); + } + // Party Modus: Ordner in zufälliger Reihenfolge + if (myCard.mode == 3) { + Serial.println( + F("Party Modus -> Ordner in zufälliger Reihenfolge wiedergeben")); + track = random(1, numTracksInFolder + 1); + mp3.playFolderTrack(myCard.folder, track); + } + // Einzel Modus: eine Datei aus dem Ordner abspielen + if (myCard.mode == 4) { + Serial.println( + F("Einzel Modus -> eine Datei aus dem Odrdner abspielen")); + track = myCard.special; + mp3.playFolderTrack(myCard.folder, track); + } + // Hörbuch Modus: kompletten Ordner spielen und Fortschritt merken + if (myCard.mode == 5) { + Serial.println(F("Hörbuch Modus -> kompletten Ordner spielen und " + "Fortschritt merken")); + track = EEPROM.read(myCard.folder); + mp3.playFolderTrack(myCard.folder, track); + } + } + + // Neue Karte konfigurieren + else { + knownCard = false; + setupCard(); + } + } + mfrc522.PICC_HaltA(); + mfrc522.PCD_StopCrypto1(); +} + +int voiceMenu(int numberOfOptions, int startMessage, int messageOffset, + bool preview = false, int previewFromFolder = 0) { + int returnValue = 0; + if (startMessage != 0) + mp3.playMp3FolderTrack(startMessage); + do { + pauseButton.read(); + upButton.read(); + downButton.read(); + mp3.loop(); + if (pauseButton.wasPressed()) { + if (returnValue != 0) + return returnValue; + delay(1000); + } + + if (upButton.pressedFor(LONG_PRESS)) { + returnValue = min(returnValue + 10, numberOfOptions); + mp3.playMp3FolderTrack(messageOffset + returnValue); + delay(1000); + if (preview) { + do { + delay(10); + } while (isPlaying()); + if (previewFromFolder == 0) + mp3.playFolderTrack(returnValue, 1); + else + mp3.playFolderTrack(previewFromFolder, returnValue); + } + ignoreUpButton = true; + } else if (upButton.wasReleased()) { + if (!ignoreUpButton) { + returnValue = min(returnValue + 1, numberOfOptions); + mp3.playMp3FolderTrack(messageOffset + returnValue); + delay(1000); + if (preview) { + do { + delay(10); + } while (isPlaying()); + if (previewFromFolder == 0) + mp3.playFolderTrack(returnValue, 1); + else + mp3.playFolderTrack(previewFromFolder, returnValue); + } + } else + ignoreUpButton = false; + } + + if (downButton.pressedFor(LONG_PRESS)) { + returnValue = max(returnValue - 10, 1); + mp3.playMp3FolderTrack(messageOffset + returnValue); + delay(1000); + if (preview) { + do { + delay(10); + } while (isPlaying()); + if (previewFromFolder == 0) + mp3.playFolderTrack(returnValue, 1); + else + mp3.playFolderTrack(previewFromFolder, returnValue); + } + ignoreDownButton = true; + } else if (downButton.wasReleased()) { + if (!ignoreDownButton) { + returnValue = max(returnValue - 1, 1); + mp3.playMp3FolderTrack(messageOffset + returnValue); + delay(1000); + if (preview) { + do { + delay(10); + } while (isPlaying()); + if (previewFromFolder == 0) + mp3.playFolderTrack(returnValue, 1); + else + mp3.playFolderTrack(previewFromFolder, returnValue); + } + } else + ignoreDownButton = false; + } + } while (true); +} + +void resetCard() { + do { + pauseButton.read(); + upButton.read(); + downButton.read(); + + if (upButton.wasReleased() || downButton.wasReleased()) { + Serial.print(F("Abgebrochen!")); + mp3.playMp3FolderTrack(802); + return; + } + } while (!mfrc522.PICC_IsNewCardPresent()); + + if (!mfrc522.PICC_ReadCardSerial()) + return; + + Serial.print(F("Karte wird neu Konfiguriert!")); + setupCard(); +} + +void setupCard() { + mp3.pause(); + Serial.print(F("Neue Karte konfigurieren")); + + // Ordner abfragen + myCard.folder = voiceMenu(99, 300, 0, true); + + // Wiedergabemodus abfragen + myCard.mode = voiceMenu(6, 310, 310); + + // Hörbuchmodus -> Fortschritt im EEPROM auf 1 setzen + EEPROM.write(myCard.folder,1); + + // Einzelmodus -> Datei abfragen + if (myCard.mode == 4) + myCard.special = voiceMenu(mp3.getFolderTrackCount(myCard.folder), 320, 0, + true, myCard.folder); + + // Admin Funktionen + if (myCard.mode == 6) + myCard.special = voiceMenu(3, 320, 320); + + // Karte ist konfiguriert -> speichern + writeCard(myCard); +} + +bool readCard(nfcTagObject *nfcTag) { + bool returnValue = true; + // Show some details of the PICC (that is: the tag/card) + Serial.print(F("Card UID:")); + dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size); + Serial.println(); + Serial.print(F("PICC type: ")); + MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); + Serial.println(mfrc522.PICC_GetTypeName(piccType)); + + byte buffer[18]; + byte size = sizeof(buffer); + + // Authenticate using key A + Serial.println(F("Authenticating using key A...")); + status = (MFRC522::StatusCode)mfrc522.PCD_Authenticate( + MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid)); + if (status != MFRC522::STATUS_OK) { + returnValue = false; + Serial.print(F("PCD_Authenticate() failed: ")); + Serial.println(mfrc522.GetStatusCodeName(status)); + return; + } + + // Show the whole sector as it currently is + Serial.println(F("Current data in sector:")); + mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector); + Serial.println(); + + // Read data from the block + Serial.print(F("Reading data from block ")); + Serial.print(blockAddr); + Serial.println(F(" ...")); + status = (MFRC522::StatusCode)mfrc522.MIFARE_Read(blockAddr, buffer, &size); + if (status != MFRC522::STATUS_OK) { + returnValue = false; + Serial.print(F("MIFARE_Read() failed: ")); + Serial.println(mfrc522.GetStatusCodeName(status)); + } + Serial.print(F("Data in block ")); + Serial.print(blockAddr); + Serial.println(F(":")); + dump_byte_array(buffer, 16); + Serial.println(); + Serial.println(); + + uint32_t tempCookie; + tempCookie = (uint32_t)buffer[0] << 24; + tempCookie += (uint32_t)buffer[1] << 16; + tempCookie += (uint32_t)buffer[2] << 8; + tempCookie += (uint32_t)buffer[3]; + + nfcTag->cookie = tempCookie; + nfcTag->version = buffer[4]; + nfcTag->folder = buffer[5]; + nfcTag->mode = buffer[6]; + nfcTag->special = buffer[7]; + + return returnValue; +} + +void writeCard(nfcTagObject nfcTag) { + MFRC522::PICC_Type mifareType; + byte buffer[16] = {0x13, 0x37, 0xb3, 0x47, // 0x1337 0xb347 magic cookie to + // identify our nfc tags + 0x01, // version 1 + nfcTag.folder, // the folder picked by the user + nfcTag.mode, // the playback mode picked by the user + nfcTag.special, // track or function for admin cards + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + byte size = sizeof(buffer); + + mifareType = mfrc522.PICC_GetType(mfrc522.uid.sak); + + // Authenticate using key B + Serial.println(F("Authenticating again using key B...")); + status = (MFRC522::StatusCode)mfrc522.PCD_Authenticate( + MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &key, &(mfrc522.uid)); + if (status != MFRC522::STATUS_OK) { + Serial.print(F("PCD_Authenticate() failed: ")); + Serial.println(mfrc522.GetStatusCodeName(status)); + return; + } + + // Write data to the block + Serial.print(F("Writing data into block ")); + Serial.print(blockAddr); + Serial.println(F(" ...")); + dump_byte_array(buffer, 16); + Serial.println(); + status = (MFRC522::StatusCode)mfrc522.MIFARE_Write(blockAddr, buffer, 16); + if (status != MFRC522::STATUS_OK) { + Serial.print(F("MIFARE_Write() failed: ")); + Serial.println(mfrc522.GetStatusCodeName(status)); + mp3.playMp3FolderTrack(401); + } + else + mp3.playMp3FolderTrack(400); + Serial.println(); + delay(100); +} + +/** + * Helper routine to dump a byte array as hex values to Serial. + */ +void dump_byte_array(byte *buffer, byte bufferSize) { + for (byte i = 0; i < bufferSize; i++) { + Serial.print(buffer[i] < 0x10 ? " 0" : " "); + Serial.print(buffer[i], HEX); + } +} + diff --git a/Tonuino.ino b/Tonuino.ino index e48a2a5..1ce775d 100644 --- a/Tonuino.ino +++ b/Tonuino.ino @@ -441,7 +441,6 @@ void setupCard() { myCard.special = voiceMenu(3, 320, 320); // Karte ist konfiguriert -> speichern - mp3.playMp3FolderTrack(400); writeCard(myCard); } @@ -527,6 +526,7 @@ void writeCard(nfcTagObject nfcTag) { if (status != MFRC522::STATUS_OK) { Serial.print(F("PCD_Authenticate() failed: ")); Serial.println(mfrc522.GetStatusCodeName(status)); + mp3.playMp3FolderTrack(401); return; } @@ -540,7 +540,10 @@ void writeCard(nfcTagObject nfcTag) { if (status != MFRC522::STATUS_OK) { Serial.print(F("MIFARE_Write() failed: ")); Serial.println(mfrc522.GetStatusCodeName(status)); + mp3.playMp3FolderTrack(401); } + else + mp3.playMp3FolderTrack(400); Serial.println(); delay(100); } diff --git a/community/TonUINO/Tonuino.ino b/community/TonUINO/Tonuino.ino new file mode 100644 index 0000000..1a17221 --- /dev/null +++ b/community/TonUINO/Tonuino.ino @@ -0,0 +1,559 @@ +#include +#include +#include +#include +#include +#include + +// DFPlayer Mini +SoftwareSerial mySoftwareSerial(2, 3); // RX, TX +uint16_t numTracksInFolder; +uint16_t track; + +// this object stores nfc tag data +struct nfcTagObject { + uint32_t cookie; + uint8_t version; + uint8_t folder; + uint8_t mode; + uint8_t special; +}; + +nfcTagObject myCard; + +static void nextTrack(); +int voiceMenu(int numberOfOptions, int startMessage, int messageOffset, + bool preview = false, int previewFromFolder = 0); + +bool knownCard = false; + +// implement a notification class, +// its member methods will get called +// +class Mp3Notify { +public: + static void OnError(uint16_t errorCode) { + // see DfMp3_Error for code meaning + Serial.println(); + Serial.print("Com Error "); + Serial.println(errorCode); + } + static void OnPlayFinished(uint16_t track) { + Serial.print("Track beendet"); + Serial.println(track); + delay(100); + nextTrack(); + } + static void OnCardOnline(uint16_t code) { + Serial.println(F("SD Karte online ")); + } + static void OnCardInserted(uint16_t code) { + Serial.println(F("SD Karte bereit ")); + } + static void OnCardRemoved(uint16_t code) { + Serial.println(F("SD Karte entfernt ")); + } +}; + +static DFMiniMp3 mp3(mySoftwareSerial); + +// Leider kann das Modul keine Queue abspielen. +static void nextTrack() { + if (knownCard == false) + // Wenn eine neue Karte angelernt wird soll das Ende eines Tracks nicht + // verarbeitet werden + return; + + if (myCard.mode == 1) { + Serial.println(F("Hörspielmodus ist aktiv -> Strom sparen")); + mp3.sleep(); + } + if (myCard.mode == 2) { + if (track != numTracksInFolder) { + track = track + 1; + mp3.playFolderTrack(myCard.folder, track); + Serial.print(F("Albummodus ist aktiv -> nächster Track: ")); + Serial.print(track); + } else + mp3.sleep(); + } + if (myCard.mode == 3) { + track = random(1, numTracksInFolder + 1); + Serial.print(F("Party Modus ist aktiv -> zufälligen Track spielen: ")); + Serial.println(track); + mp3.playFolderTrack(myCard.folder, track); + } + if (myCard.mode == 4) { + Serial.println(F("Einzel Modus aktiv -> Strom sparen")); + mp3.sleep(); + } + if (myCard.mode == 5) { + if (track != numTracksInFolder) { + track = track + 1; + Serial.print(F("Hörbuch Modus ist aktiv -> nächster Track und " + "Fortschritt speichern")); + Serial.println(track); + mp3.playFolderTrack(myCard.folder, track); + // Fortschritt im EEPROM abspeichern + EEPROM.write(myCard.folder, track); + } else + mp3.sleep(); + } +} + +static void previousTrack() { + if (myCard.mode == 1) { + Serial.println(F("Hörspielmodus ist aktiv -> Track von vorne spielen")); + mp3.playFolderTrack(myCard.folder, track); + } + if (myCard.mode == 2) { + Serial.println(F("Albummodus ist aktiv -> vorheriger Track")); + if (track != 1) { + track = track - 1; + } + mp3.playFolderTrack(myCard.folder, track); + } + if (myCard.mode == 3) { + Serial.println(F("Party Modus ist aktiv -> Track von vorne spielen")); + mp3.playFolderTrack(myCard.folder, track); + } + if (myCard.mode == 4) { + Serial.println(F("Einzel Modus aktiv -> Track von vorne spielen")); + mp3.playFolderTrack(myCard.folder, track); + } + if (myCard.mode == 5) { + Serial.println(F("Hörbuch Modus ist aktiv -> vorheriger Track und " + "Fortschritt speichern")); + if (track != 1) { + track = track - 1; + } + mp3.playFolderTrack(myCard.folder, track); + // Fortschritt im EEPROM abspeichern + EEPROM.write(myCard.folder, track); + } +} + +// MFRC522 +#define RST_PIN 9 // Configurable, see typical pin layout above +#define SS_PIN 10 // Configurable, see typical pin layout above +MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 +MFRC522::MIFARE_Key key; +bool successRead; +byte sector = 1; +byte blockAddr = 4; +byte trailerBlock = 7; +MFRC522::StatusCode status; + +#define buttonPause A0 +#define buttonUp A1 +#define buttonDown A2 +#define busyPin 4 + +#define LONG_PRESS 1000 + +Button pauseButton(buttonPause); +Button upButton(buttonUp); +Button downButton(buttonDown); +bool ignorePauseButton = false; +bool ignoreUpButton = false; +bool ignoreDownButton = false; + +uint8_t numberOfCards = 0; + +bool isPlaying() { return !digitalRead(busyPin); } + +void setup() { + + Serial.begin(115200); // Es gibt ein paar Debug Ausgaben über die serielle + // Schnittstelle + randomSeed(analogRead(A0)); // Zufallsgenerator initialisieren + + Serial.println(F("TonUINO Version 2.0")); + Serial.println(F("(c) Thorsten Voß")); + + // Knöpfe mit PullUp + pinMode(buttonPause, INPUT_PULLUP); + pinMode(buttonUp, INPUT_PULLUP); + pinMode(buttonDown, INPUT_PULLUP); + + // Busy Pin + pinMode(busyPin, INPUT); + + // DFPlayer Mini initialisieren + mp3.begin(); + mp3.setVolume(15); + + // NFC Leser initialisieren + SPI.begin(); // Init SPI bus + mfrc522.PCD_Init(); // Init MFRC522 + mfrc522 + .PCD_DumpVersionToSerial(); // Show details of PCD - MFRC522 Card Reader + for (byte i = 0; i < 6; i++) { + key.keyByte[i] = 0xFF; + } + + // RESET --- ALLE DREI KNÖPFE BEIM STARTEN GEDRÜCKT HALTEN -> alle bekannten + // Karten werden gelöscht + if (digitalRead(buttonPause) == LOW && digitalRead(buttonUp) == LOW && + digitalRead(buttonDown) == LOW) { + Serial.println(F("Reset -> EEPROM wird gelöscht")); + for (int i = 0; i < EEPROM.length(); i++) { + EEPROM.write(i, 0); + } + } + +} + +void loop() { + do { + mp3.loop(); + // Buttons werden nun über JS_Button gehandelt, dadurch kann jede Taste + // doppelt belegt werden + pauseButton.read(); + upButton.read(); + downButton.read(); + + if (pauseButton.wasReleased()) { + if (ignorePauseButton == false) + if (isPlaying()) + mp3.pause(); + else + mp3.start(); + ignorePauseButton = false; + } else if (pauseButton.pressedFor(LONG_PRESS) && + ignorePauseButton == false) { + if (isPlaying()) + mp3.playAdvertisement(track); + else { + knownCard = false; + mp3.playMp3FolderTrack(800); + Serial.println(F("Karte resetten...")); + resetCard(); + mfrc522.PICC_HaltA(); + mfrc522.PCD_StopCrypto1(); + } + ignorePauseButton = true; + } + + if (upButton.pressedFor(LONG_PRESS)) { + Serial.println(F("Volume Up")); + mp3.increaseVolume(); + ignoreUpButton = true; + } else if (upButton.wasReleased()) { + if (!ignoreUpButton) + nextTrack(); + else + ignoreUpButton = false; + } + + if (downButton.pressedFor(LONG_PRESS)) { + Serial.println(F("Volume Down")); + mp3.decreaseVolume(); + ignoreDownButton = true; + } else if (downButton.wasReleased()) { + if (!ignoreDownButton) + previousTrack(); + else + ignoreDownButton = false; + } + // Ende der Buttons + } while (!mfrc522.PICC_IsNewCardPresent()); + + // RFID Karte wurde aufgelegt + + if (!mfrc522.PICC_ReadCardSerial()) + return; + + if (readCard(&myCard) == true) { + if (myCard.cookie == 322417479 && myCard.folder != 0 && myCard.mode != 0) { + + knownCard = true; + numTracksInFolder = mp3.getFolderTrackCount(myCard.folder); + + // Hörspielmodus: eine zufällige Datei aus dem Ordner + if (myCard.mode == 1) { + Serial.println(F("Hörspielmodus -> zufälligen Track wiedergeben")); + track = random(1, numTracksInFolder + 1); + Serial.println(track); + mp3.playFolderTrack(myCard.folder, track); + } + // Album Modus: kompletten Ordner spielen + if (myCard.mode == 2) { + Serial.println(F("Album Modus -> kompletten Ordner wiedergeben")); + track = 1; + mp3.playFolderTrack(myCard.folder, track); + } + // Party Modus: Ordner in zufälliger Reihenfolge + if (myCard.mode == 3) { + Serial.println( + F("Party Modus -> Ordner in zufälliger Reihenfolge wiedergeben")); + track = random(1, numTracksInFolder + 1); + mp3.playFolderTrack(myCard.folder, track); + } + // Einzel Modus: eine Datei aus dem Ordner abspielen + if (myCard.mode == 4) { + Serial.println( + F("Einzel Modus -> eine Datei aus dem Odrdner abspielen")); + track = myCard.special; + mp3.playFolderTrack(myCard.folder, track); + } + // Hörbuch Modus: kompletten Ordner spielen und Fortschritt merken + if (myCard.mode == 5) { + Serial.println(F("Hörbuch Modus -> kompletten Ordner spielen und " + "Fortschritt merken")); + track = EEPROM.read(myCard.folder); + mp3.playFolderTrack(myCard.folder, track); + } + } + + // Neue Karte konfigurieren + else { + knownCard = false; + setupCard(); + } + } + mfrc522.PICC_HaltA(); + mfrc522.PCD_StopCrypto1(); +} + +int voiceMenu(int numberOfOptions, int startMessage, int messageOffset, + bool preview = false, int previewFromFolder = 0) { + int returnValue = 0; + if (startMessage != 0) + mp3.playMp3FolderTrack(startMessage); + do { + pauseButton.read(); + upButton.read(); + downButton.read(); + mp3.loop(); + if (pauseButton.wasPressed()) { + if (returnValue != 0) + return returnValue; + delay(1000); + } + + if (upButton.pressedFor(LONG_PRESS)) { + returnValue = min(returnValue + 10, numberOfOptions); + mp3.playMp3FolderTrack(messageOffset + returnValue); + delay(1000); + if (preview) { + do { + delay(10); + } while (isPlaying()); + if (previewFromFolder == 0) + mp3.playFolderTrack(returnValue, 1); + else + mp3.playFolderTrack(previewFromFolder, returnValue); + } + ignoreUpButton = true; + } else if (upButton.wasReleased()) { + if (!ignoreUpButton) { + returnValue = min(returnValue + 1, numberOfOptions); + mp3.playMp3FolderTrack(messageOffset + returnValue); + delay(1000); + if (preview) { + do { + delay(10); + } while (isPlaying()); + if (previewFromFolder == 0) + mp3.playFolderTrack(returnValue, 1); + else + mp3.playFolderTrack(previewFromFolder, returnValue); + } + } else + ignoreUpButton = false; + } + + if (downButton.pressedFor(LONG_PRESS)) { + returnValue = max(returnValue - 10, 1); + mp3.playMp3FolderTrack(messageOffset + returnValue); + delay(1000); + if (preview) { + do { + delay(10); + } while (isPlaying()); + if (previewFromFolder == 0) + mp3.playFolderTrack(returnValue, 1); + else + mp3.playFolderTrack(previewFromFolder, returnValue); + } + ignoreDownButton = true; + } else if (downButton.wasReleased()) { + if (!ignoreDownButton) { + returnValue = max(returnValue - 1, 1); + mp3.playMp3FolderTrack(messageOffset + returnValue); + delay(1000); + if (preview) { + do { + delay(10); + } while (isPlaying()); + if (previewFromFolder == 0) + mp3.playFolderTrack(returnValue, 1); + else + mp3.playFolderTrack(previewFromFolder, returnValue); + } + } else + ignoreDownButton = false; + } + } while (true); +} + +void resetCard() { + do { + pauseButton.read(); + upButton.read(); + downButton.read(); + + if (upButton.wasReleased() || downButton.wasReleased()) { + Serial.print(F("Abgebrochen!")); + mp3.playMp3FolderTrack(802); + return; + } + } while (!mfrc522.PICC_IsNewCardPresent()); + + if (!mfrc522.PICC_ReadCardSerial()) + return; + + Serial.print(F("Karte wird neu Konfiguriert!")); + setupCard(); +} + +void setupCard() { + mp3.pause(); + Serial.print(F("Neue Karte konfigurieren")); + + // Ordner abfragen + myCard.folder = voiceMenu(99, 300, 0, true); + + // Wiedergabemodus abfragen + myCard.mode = voiceMenu(6, 310, 310); + + // Hörbuchmodus -> Fortschritt im EEPROM auf 1 setzen + EEPROM.write(myCard.folder,1); + + // Einzelmodus -> Datei abfragen + if (myCard.mode == 4) + myCard.special = voiceMenu(mp3.getFolderTrackCount(myCard.folder), 320, 0, + true, myCard.folder); + + // Admin Funktionen + if (myCard.mode == 6) + myCard.special = voiceMenu(3, 320, 320); + + // Karte ist konfiguriert -> speichern + writeCard(myCard); +} + +bool readCard(nfcTagObject *nfcTag) { + bool returnValue = true; + // Show some details of the PICC (that is: the tag/card) + Serial.print(F("Card UID:")); + dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size); + Serial.println(); + Serial.print(F("PICC type: ")); + MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); + Serial.println(mfrc522.PICC_GetTypeName(piccType)); + + byte buffer[18]; + byte size = sizeof(buffer); + + // Authenticate using key A + Serial.println(F("Authenticating using key A...")); + status = (MFRC522::StatusCode)mfrc522.PCD_Authenticate( + MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid)); + if (status != MFRC522::STATUS_OK) { + returnValue = false; + Serial.print(F("PCD_Authenticate() failed: ")); + Serial.println(mfrc522.GetStatusCodeName(status)); + return; + } + + // Show the whole sector as it currently is + Serial.println(F("Current data in sector:")); + mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector); + Serial.println(); + + // Read data from the block + Serial.print(F("Reading data from block ")); + Serial.print(blockAddr); + Serial.println(F(" ...")); + status = (MFRC522::StatusCode)mfrc522.MIFARE_Read(blockAddr, buffer, &size); + if (status != MFRC522::STATUS_OK) { + returnValue = false; + Serial.print(F("MIFARE_Read() failed: ")); + Serial.println(mfrc522.GetStatusCodeName(status)); + } + Serial.print(F("Data in block ")); + Serial.print(blockAddr); + Serial.println(F(":")); + dump_byte_array(buffer, 16); + Serial.println(); + Serial.println(); + + uint32_t tempCookie; + tempCookie = (uint32_t)buffer[0] << 24; + tempCookie += (uint32_t)buffer[1] << 16; + tempCookie += (uint32_t)buffer[2] << 8; + tempCookie += (uint32_t)buffer[3]; + + nfcTag->cookie = tempCookie; + nfcTag->version = buffer[4]; + nfcTag->folder = buffer[5]; + nfcTag->mode = buffer[6]; + nfcTag->special = buffer[7]; + + return returnValue; +} + +void writeCard(nfcTagObject nfcTag) { + MFRC522::PICC_Type mifareType; + byte buffer[16] = {0x13, 0x37, 0xb3, 0x47, // 0x1337 0xb347 magic cookie to + // identify our nfc tags + 0x01, // version 1 + nfcTag.folder, // the folder picked by the user + nfcTag.mode, // the playback mode picked by the user + nfcTag.special, // track or function for admin cards + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + byte size = sizeof(buffer); + + mifareType = mfrc522.PICC_GetType(mfrc522.uid.sak); + + // Authenticate using key B + Serial.println(F("Authenticating again using key B...")); + status = (MFRC522::StatusCode)mfrc522.PCD_Authenticate( + MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &key, &(mfrc522.uid)); + if (status != MFRC522::STATUS_OK) { + Serial.print(F("PCD_Authenticate() failed: ")); + Serial.println(mfrc522.GetStatusCodeName(status)); + return; + } + + // Write data to the block + Serial.print(F("Writing data into block ")); + Serial.print(blockAddr); + Serial.println(F(" ...")); + dump_byte_array(buffer, 16); + Serial.println(); + status = (MFRC522::StatusCode)mfrc522.MIFARE_Write(blockAddr, buffer, 16); + if (status != MFRC522::STATUS_OK) { + Serial.print(F("MIFARE_Write() failed: ")); + Serial.println(mfrc522.GetStatusCodeName(status)); + mp3.playMp3FolderTrack(401); + } + else + mp3.playMp3FolderTrack(400); + Serial.println(); + delay(100); +} + +/** + * Helper routine to dump a byte array as hex values to Serial. + */ +void dump_byte_array(byte *buffer, byte bufferSize) { + for (byte i = 0; i < bufferSize; i++) { + Serial.print(buffer[i] < 0x10 ? " 0" : " "); + Serial.print(buffer[i], HEX); + } +} + diff --git a/create-soundfiles.sh b/create-soundfiles.sh index 3871aa3..1d8831c 100755 --- a/create-soundfiles.sh +++ b/create-soundfiles.sh @@ -72,14 +72,14 @@ say -v Anna "Ja, Nummer ansagen." -o 0332.aiff sox 0332.aiff 0332.wav pitch 800 lame -b 128 0332.wav 0332.mp3 -#say -v Anna "Bitte lege die Karte erneut auf und warte auf die Bestätigung." -o 0400.aiff -#sox 0400.aiff 0400.wav pitch 800 -#lame -b 128 0400.wav 0400_wait_for_card.mp3 - say -v Anna "OK. Ich habe die Karte konfiguriert." -o 0400.aiff sox 0400.aiff 0400.wav pitch 800 lame -b 128 0400.wav 0400_ok.mp3 +say -v Anna "Oh weh! Das hat leider nicht geklappt!." -o 0401.aiff +sox 0401.aiff 0401.wav pitch 800 +lame -b 128 0401.wav 0401_error.mp3 + rm *.aiff rm *.wav