void adminMenu(bool fromCard = false) {
disablestandbyTimer();
mp3.pause();
Serial.println(F("=== adminMenu()"));
knownCard = false;
if (fromCard == false) {
// Admin menu has been locked - it still can be trigged via admin card
if (mySettings.adminMenuLocked == 1) {
return;
}
// Pin check
else if (mySettings.adminMenuLocked == 2) {
uint8_t pin[4];
mp3.playMp3FolderTrack(991);
if (askCode(pin) == true) {
if (checkTwo(pin, mySettings.adminMenuPin) == false) {
return;
}
} else {
return;
}
}
// Match check
else if (mySettings.adminMenuLocked == 3) {
uint8_t a = random(10, 20);
uint8_t b = random(1, 10);
uint8_t c;
mp3.playMp3FolderTrack(992);
waitForTrackToFinish();
mp3.playMp3FolderTrack(a);
if (random(1, 3) == 2) {
// a + b
c = a + b;
waitForTrackToFinish();
mp3.playMp3FolderTrack(993);
} else {
// a - b
b = random(1, a);
c = a - b;
waitForTrackToFinish();
mp3.playMp3FolderTrack(994);
}
waitForTrackToFinish();
mp3.playMp3FolderTrack(b);
Serial.println(c);
uint8_t temp = voiceMenu(255, 0, 0, false);
if (temp != c) {
return;
}
}
}
int subMenu = voiceMenu(12, 900, 900, false, false, 0, true);
if (subMenu == 0)
return;
if (subMenu == 1) {
resetCard();
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1();
}
else if (subMenu == 2) {
// Maximum Volume
mySettings.maxVolume = voiceMenu(30 - mySettings.minVolume, 930, mySettings.minVolume, false, false, mySettings.maxVolume - mySettings.minVolume) + mySettings.minVolume;
}
else if (subMenu == 3) {
// Minimum Volume
mySettings.minVolume = voiceMenu(mySettings.maxVolume - 1, 931, 0, false, false, mySettings.minVolume);
}
else if (subMenu == 4) {
// Initial Volume
mySettings.initVolume = voiceMenu(mySettings.maxVolume - mySettings.minVolume + 1, 932, mySettings.minVolume - 1, false, false, mySettings.initVolume - mySettings.minVolume + 1) + mySettings.minVolume - 1;
}
else if (subMenu == 5) {
// EQ
mySettings.eq = voiceMenu(6, 920, 920, false, false, mySettings.eq);
mp3.setEq(mySettings.eq - 1);
}
else if (subMenu == 6) {
// create modifier card
nfcTagObject tempCard;
tempCard.cookie = cardCookie;
tempCard.version = 1;
tempCard.nfcFolderSettings.folder = 0;
tempCard.nfcFolderSettings.special = 0;
tempCard.nfcFolderSettings.special2 = 0;
tempCard.nfcFolderSettings.mode = voiceMenu(6, 970, 970, false, false, 0, true);
if (tempCard.nfcFolderSettings.mode != 0) {
if (tempCard.nfcFolderSettings.mode == 1) {
switch (voiceMenu(4, 960, 960)) {
case 1: tempCard.nfcFolderSettings.special = 5; break;
case 2: tempCard.nfcFolderSettings.special = 15; break;
case 3: tempCard.nfcFolderSettings.special = 30; break;
case 4: tempCard.nfcFolderSettings.special = 60; break;
}
}
mp3.playMp3FolderTrack(800);
do {
readButtons();
if (upButton.wasReleased() || downButton.wasReleased()) {
Serial.println(F("Abgebrochen!"));
mp3.playMp3FolderTrack(802);
return;
}
} while (!mfrc522.PICC_IsNewCardPresent());
// RFID Karte wurde aufgelegt
if (mfrc522.PICC_ReadCardSerial()) {
Serial.println(F("schreibe Karte..."));
writeCard(tempCard);
delay(100);
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1();
waitForTrackToFinish();
}
}
}
else if (subMenu == 7) {
uint8_t shortcut = voiceMenu(4, 940, 940);
setupFolder(&mySettings.shortCuts[shortcut - 1]);
mp3.playMp3FolderTrack(400);
}
else if (subMenu == 8) {
switch (voiceMenu(5, 960, 960)) {
case 1: mySettings.standbyTimer = 5; break;
case 2: mySettings.standbyTimer = 15; break;
case 3: mySettings.standbyTimer = 30; break;
case 4: mySettings.standbyTimer = 60; break;
case 5: mySettings.standbyTimer = 0; break;
}
}
else if (subMenu == 9) {
// Create Cards for Folder
// Ordner abfragen
nfcTagObject tempCard;
tempCard.cookie = cardCookie;
tempCard.version = 1;
tempCard.nfcFolderSettings.mode = 4;
tempCard.nfcFolderSettings.folder = voiceMenu(99, 301, 0, true);
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);
mp3.playMp3FolderTrack(936);
waitForTrackToFinish();
for (uint8_t x = special; x <= special2; x++) {
mp3.playMp3FolderTrack(x);
tempCard.nfcFolderSettings.special = x;
Serial.print(x);
Serial.println(F(" Karte auflegen"));
do {
readButtons();
if (upButton.wasReleased() || downButton.wasReleased()) {
Serial.println(F("Abgebrochen!"));
mp3.playMp3FolderTrack(802);
return;
}
} while (!mfrc522.PICC_IsNewCardPresent());
// RFID Karte wurde aufgelegt
if (mfrc522.PICC_ReadCardSerial()) {
Serial.println(F("schreibe Karte..."));
writeCard(tempCard);
delay(100);
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1();
waitForTrackToFinish();
}
}
}
else if (subMenu == 10) {
// Invert Functions for Up/Down Buttons
int temp = voiceMenu(2, 933, 933, false);
if (temp == 2) {
mySettings.invertVolumeButtons = true;
}
else {
mySettings.invertVolumeButtons = false;
}
}
else if (subMenu == 11) {
Serial.println(F("Reset -> EEPROM wird gelöscht"));
for (int i = 0; i < EEPROM.length(); i++) {
EEPROM.update(i, 0);
}
resetSettings();
mp3.playMp3FolderTrack(999);
}
// lock admin menu
else if (subMenu == 12) {
int temp = voiceMenu(4, 980, 980, false);
if (temp == 1) {
mySettings.adminMenuLocked = 0;
}
else if (temp == 2) {
mySettings.adminMenuLocked = 1;
}
else if (temp == 3) {
int8_t pin[4];
mp3.playMp3FolderTrack(991);
if (askCode(pin)) {
memcpy(mySettings.adminMenuPin, pin, 4);
mySettings.adminMenuLocked = 2;
}
}
else if (temp == 4) {
mySettings.adminMenuLocked = 3;
}
}
writeSettingsToFlash();
setstandbyTimer();
}
bool askCode(uint8_t *code) {
uint8_t x = 0;
while (x < 4) {
readButtons();
if (pauseButton.pressedFor(LONG_PRESS))
break;
if (pauseButton.wasReleased())
code[x++] = 1;
if (upButton.wasReleased())
code[x++] = 2;
if (downButton.wasReleased())
code[x++] = 3;
}
return true;
}
uint8_t voiceMenu(int numberOfOptions, int startMessage, int messageOffset,
bool preview = false, int previewFromFolder = 0, int defaultValue = 0, bool exitWithLongPress = false) {
uint8_t returnValue = defaultValue;
if (startMessage != 0)
mp3.playMp3FolderTrack(startMessage);
Serial.print(F("=== voiceMenu() ("));
Serial.print(numberOfOptions);
Serial.println(F(" Options)"));
do {
if (Serial.available() > 0) {
int optionSerial = Serial.parseInt();
if (optionSerial != 0 && optionSerial <= numberOfOptions)
return optionSerial;
}
readButtons();
mp3.loop();
if (pauseButton.pressedFor(LONG_PRESS)) {
mp3.playMp3FolderTrack(802);
ignorePauseButton = true;
return defaultValue;
}
if (pauseButton.wasReleased()) {
if (returnValue != 0) {
Serial.print(F("=== "));
Serial.print(returnValue);
Serial.println(F(" ==="));
return returnValue;
}
delay(1000);
}
if (upButton.pressedFor(LONG_PRESS)) {
returnValue = min(returnValue + 10, numberOfOptions);
Serial.println(returnValue);
//mp3.pause();
mp3.playMp3FolderTrack(messageOffset + returnValue);
waitForTrackToFinish();
/*if (preview) {
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);
Serial.println(returnValue);
//mp3.pause();
mp3.playMp3FolderTrack(messageOffset + returnValue);
if (preview) {
waitForTrackToFinish();
if (previewFromFolder == 0) {
mp3.playFolderTrack(returnValue, 1);
} else {
mp3.playFolderTrack(previewFromFolder, returnValue);
}
delay(1000);
}
} else {
ignoreUpButton = false;
}
}
if (downButton.pressedFor(LONG_PRESS)) {
returnValue = max(returnValue - 10, 1);
Serial.println(returnValue);
//mp3.pause();
mp3.playMp3FolderTrack(messageOffset + returnValue);
waitForTrackToFinish();
/*if (preview) {
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);
Serial.println(returnValue);
//mp3.pause();
mp3.playMp3FolderTrack(messageOffset + returnValue);
if (preview) {
waitForTrackToFinish();
if (previewFromFolder == 0) {
mp3.playFolderTrack(returnValue, 1);
}
else {
mp3.playFolderTrack(previewFromFolder, returnValue);
}
delay(1000);
}
} else {
ignoreDownButton = false;
}
}
} while (true);
}
void resetCard() {
mp3.playMp3FolderTrack(800);
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();
}
bool setupFolder(folderSettings * theFolder) {
// Ordner abfragen
theFolder->folder = voiceMenu(99, 301, 0, true, 0, 0, true);
if (theFolder->folder == 0) return false;
// Wiedergabemodus abfragen
theFolder->mode = voiceMenu(9, 310, 310, false, 0, 0, true);
if (theFolder->mode == 0) return false;
// // Hörbuchmodus -> Fortschritt im EEPROM auf 1 setzen
// EEPROM.update(theFolder->folder, 1);
// Einzelmodus -> Datei abfragen
if (theFolder->mode == 4)
theFolder->special = voiceMenu(mp3.getFolderTrackCount(theFolder->folder), 320, 0,
true, theFolder->folder);
// Admin Funktionen
if (theFolder->mode == 6) {
//theFolder->special = voiceMenu(3, 320, 320);
theFolder->folder = 0;
theFolder->mode = 255;
}
// Spezialmodus Von-Bis
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);
}
return true;
}
void setupCard() {
mp3.pause();
Serial.println(F("=== setupCard()"));
nfcTagObject newCard;
if (setupFolder(&newCard.nfcFolderSettings) == true)
{
// Karte ist konfiguriert -> speichern
mp3.pause();
do {
} while (isPlaying());
writeCard(newCard);
}
delay(1000);
}
bool readCard(nfcTagObject * nfcTag) {
nfcTagObject tempCard;
// 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
if ((piccType == MFRC522::PICC_TYPE_MIFARE_MINI ) ||
(piccType == MFRC522::PICC_TYPE_MIFARE_1K ) ||
(piccType == MFRC522::PICC_TYPE_MIFARE_4K ) )
{
Serial.println(F("Authenticating Classic using key A..."));
status = mfrc522.PCD_Authenticate(
MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
}
else if (piccType == MFRC522::PICC_TYPE_MIFARE_UL )
{
byte pACK[] = {0, 0}; //16 bit PassWord ACK returned by the tempCard
// Authenticate using key A
Serial.println(F("Authenticating MIFARE UL..."));
status = mfrc522.PCD_NTAG216_AUTH(key.keyByte, pACK);
}
if (status != MFRC522::STATUS_OK) {
Serial.print(F("PCD_Authenticate() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return false;
}
// 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
if ((piccType == MFRC522::PICC_TYPE_MIFARE_MINI ) ||
(piccType == MFRC522::PICC_TYPE_MIFARE_1K ) ||
(piccType == MFRC522::PICC_TYPE_MIFARE_4K ) )
{
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) {
Serial.print(F("MIFARE_Read() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return false;
}
}
else if (piccType == MFRC522::PICC_TYPE_MIFARE_UL )
{
byte buffer2[18];
byte size2 = sizeof(buffer2);
status = (MFRC522::StatusCode)mfrc522.MIFARE_Read(8, buffer2, &size2);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("MIFARE_Read_1() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return false;
}
memcpy(buffer, buffer2, 4);
status = (MFRC522::StatusCode)mfrc522.MIFARE_Read(9, buffer2, &size2);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("MIFARE_Read_2() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return false;
}
memcpy(buffer + 4, buffer2, 4);
status = (MFRC522::StatusCode)mfrc522.MIFARE_Read(10, buffer2, &size2);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("MIFARE_Read_3() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return false;
}
memcpy(buffer + 8, buffer2, 4);
status = (MFRC522::StatusCode)mfrc522.MIFARE_Read(11, buffer2, &size2);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("MIFARE_Read_4() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return false;
}
memcpy(buffer + 12, buffer2, 4);
}
Serial.print(F("Data on Card "));
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];
tempCard.cookie = tempCookie;
tempCard.version = buffer[4];
tempCard.nfcFolderSettings.folder = buffer[5];
tempCard.nfcFolderSettings.mode = buffer[6];
tempCard.nfcFolderSettings.special = buffer[7];
tempCard.nfcFolderSettings.special2 = buffer[8];
if (tempCard.cookie == cardCookie) {
if (activeModifier != NULL && tempCard.nfcFolderSettings.folder != 0) {
if (activeModifier->handleRFID(&tempCard) == true) {
return false;
}
}
if (tempCard.nfcFolderSettings.folder == 0) {
if (activeModifier != NULL) {
if (activeModifier->getActive() == tempCard.nfcFolderSettings.mode) {
activeModifier = NULL;
Serial.println(F("modifier removed"));
if (isPlaying()) {
mp3.playAdvertisement(261);
}
else {
mp3.start();
delay(100);
mp3.playAdvertisement(261);
delay(100);
mp3.pause();
}
delay(2000);
return false;
}
}
if (tempCard.nfcFolderSettings.mode != 0 && tempCard.nfcFolderSettings.mode != 255) {
if (isPlaying()) {
mp3.playAdvertisement(260);
}
else {
mp3.start();
delay(100);
mp3.playAdvertisement(260);
delay(100);
mp3.pause();
}
}
switch (tempCard.nfcFolderSettings.mode ) {
case 0:
case 255:
mfrc522.PICC_HaltA(); mfrc522.PCD_StopCrypto1(); adminMenu(true); break;
case 1: activeModifier = new SleepTimer(tempCard.nfcFolderSettings.special); break;
case 2: activeModifier = new FreezeDance(); break;
case 3: activeModifier = new Locked(); break;
case 4: activeModifier = new ToddlerMode(); break;
case 5: activeModifier = new KindergardenMode(); break;
case 6: activeModifier = new RepeatSingleModifier(); break;
}
delay(2000);
return false;
}
else {
memcpy(nfcTag, &tempCard, sizeof(nfcTagObject));
Serial.println( nfcTag->nfcFolderSettings.folder);
myFolder = &nfcTag->nfcFolderSettings;
Serial.println( myFolder->folder);
}
return true;
}
else {
memcpy(nfcTag, &tempCard, sizeof(nfcTagObject));
return true;
}
}
void writeCard(nfcTagObject nfcTag) {
MFRC522::PICC_Type mifareType;
byte buffer[16] = {0x13, 0x37, 0xb3, 0x47, // 0x1337 0xb347 magic cookie to
// identify our nfc tags
0x02, // version 1
nfcTag.nfcFolderSettings.folder, // the folder picked by the user
nfcTag.nfcFolderSettings.mode, // the playback mode picked by the user
nfcTag.nfcFolderSettings.special, // track or function for admin cards
nfcTag.nfcFolderSettings.special2,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
byte size = sizeof(buffer);
mifareType = mfrc522.PICC_GetType(mfrc522.uid.sak);
// Authenticate using key B
//authentificate with the card and set card specific parameters
if ((mifareType == MFRC522::PICC_TYPE_MIFARE_MINI ) ||
(mifareType == MFRC522::PICC_TYPE_MIFARE_1K ) ||
(mifareType == MFRC522::PICC_TYPE_MIFARE_4K ) )
{
Serial.println(F("Authenticating again using key A..."));
status = mfrc522.PCD_Authenticate(
MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
}
else if (mifareType == MFRC522::PICC_TYPE_MIFARE_UL )
{
byte pACK[] = {0, 0}; //16 bit PassWord ACK returned by the NFCtag
// Authenticate using key A
Serial.println(F("Authenticating UL..."));
status = mfrc522.PCD_NTAG216_AUTH(key.keyByte, pACK);
}
if (status != MFRC522::STATUS_OK) {
Serial.print(F("PCD_Authenticate() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
mp3.playMp3FolderTrack(401);
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();
if ((mifareType == MFRC522::PICC_TYPE_MIFARE_MINI ) ||
(mifareType == MFRC522::PICC_TYPE_MIFARE_1K ) ||
(mifareType == MFRC522::PICC_TYPE_MIFARE_4K ) )
{
status = (MFRC522::StatusCode)mfrc522.MIFARE_Write(blockAddr, buffer, 16);
}
else if (mifareType == MFRC522::PICC_TYPE_MIFARE_UL )
{
byte buffer2[16];
byte size2 = sizeof(buffer2);
memset(buffer2, 0, size2);
memcpy(buffer2, buffer, 4);
status = (MFRC522::StatusCode)mfrc522.MIFARE_Write(8, buffer2, 16);
memset(buffer2, 0, size2);
memcpy(buffer2, buffer + 4, 4);
status = (MFRC522::StatusCode)mfrc522.MIFARE_Write(9, buffer2, 16);
memset(buffer2, 0, size2);
memcpy(buffer2, buffer + 8, 4);
status = (MFRC522::StatusCode)mfrc522.MIFARE_Write(10, buffer2, 16);
memset(buffer2, 0, size2);
memcpy(buffer2, buffer + 12, 4);
status = (MFRC522::StatusCode)mfrc522.MIFARE_Write(11, buffer2, 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(2000);
}
/**
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);
}
}
///////////////////////////////////////// Check Bytes ///////////////////////////////////
bool checkTwo ( uint8_t a[], uint8_t b[] ) {
for ( uint8_t k = 0; k < 4; k++ ) { // Loop 4 times
if ( a[k] != b[k] ) { // IF a != b then false, because: one fails, all fail
return false;
}
}
return true;
}
Für den Fall, dass es relevant ist noch die Versionen der Bibliotheken:
DFMiniMp3 1.0.4 (1.0.6 für Experimente mit der aktuellen DEV-Version auch probiert., keine Änderung, btw. sollte dann 1.0.6 oder 1.0.7 verwendet werden?)
JC_Button 2.1.1
MFRC522 1.4.5 (Update sinnvoll/nötig?)
Nochmal vielen Dank!