diff --git a/xiao-dfplayer/xiao-dfplayer/xiao-dfplayer.ino b/xiao-dfplayer/xiao-dfplayer/xiao-dfplayer.ino index c49afe2..dd95024 100644 --- a/xiao-dfplayer/xiao-dfplayer/xiao-dfplayer.ino +++ b/xiao-dfplayer/xiao-dfplayer/xiao-dfplayer.ino @@ -1,80 +1,210 @@ /*************************************************** -DFPlayer - A Mini MP3 Player For Arduino - - - *************************************************** - This example shows the basic function of library for DFPlayer. - - Created 2016-12-07 - By [Angelo qiao](Angelo.qiao@dfrobot.com) - - GNU Lesser General Public License. - See for details. - All above must be included in any redistribution - ****************************************************/ + DFPlayer Mini - serial console control (Seeed XIAO nRF52840) -/***********Notice and Trouble shooting*************** - 1.Connection and Diagram can be found here - - 2.This code is tested on Arduino Uno, Leonardo, Mega boards. + Hardware Serial1 link to the DFPlayer Mini: + XIAO D7 (RX) <- DFPlayer TX (add a divider/level shifter if the + DFPlayer runs at 5V - nRF52 is not 5V tolerant) + XIAO D6 (TX) -> 1k -> DFPlayer RX + common ground; feed DFPlayer VCC from 5V with a >=470uF cap at the module. + + Open the Serial Monitor at 115200 baud, line ending = Newline, and type + commands (see "help"). Based on the DFRobot DFPlayerMini example (LGPL). ****************************************************/ #include "Arduino.h" +#include +#include +#include #include "DFRobotDFPlayerMini.h" -//#if (defined(ARDUINO_Seeed_XIAO_nRF52840_Sense)) -#include // for Serial +#include // for Serial (USB CDC) #define FPSerial Serial1 // D7 <- DFPlayer TX, D6 -> DFPlayer RX -// #elif (defined(ARDUINO_AVR_UNO) || defined(ESP8266)) // Using a soft serial port -// #include -// SoftwareSerial softSerial(/*rx =*/4, /*tx =*/5); -// #define FPSerial softSerial -// #else -// #define FPSerial Serial1 -// #endif DFRobotDFPlayerMini myDFPlayer; + +int currentVolume = 20; // shadow of the DFPlayer volume (0..30) +bool dfOnline = false; + +char cmdBuf[64]; +uint8_t cmdLen = 0; + void printDetail(uint8_t type, int value); +void printHelp(); +void printStatus(); +void handleLine(char *line); void setup() { - // Open serial communications and wait for port to open: Serial.begin(115200); uint32_t t0 = millis(); - while (!Serial && millis() - t0 < 3000) { - delay(10); // for nrf52840 with native usb - Serial.println(F("Initializing serial...")); - } + while (!Serial && millis() - t0 < 3000) delay(10); // headless-safe FPSerial.begin(9600); - delay(1500); // let the DFPlayer boot + delay(1500); // let the DFPlayer boot - if (!myDFPlayer.begin(FPSerial, /*isACK=*/true, /*doReset=*/true)) { - Serial.println(F("DFPlayer not responding - check wiring / power / SD")); - delay(5000); - Serial.println(F("DFPlayer not responding - check wiring / power / SD")); - // fall through instead of hanging, so you can still debug + dfOnline = myDFPlayer.begin(FPSerial, /*isACK=*/true, /*doReset=*/true); + if (dfOnline) { + Serial.println(F("DFPlayer online.")); + } else { + Serial.println(F("WARNING: DFPlayer did not answer begin() - check wiring / power / SD.")); + Serial.println(F("Commands are still sent; status feedback may be missing.")); } - myDFPlayer.volume(20); + + myDFPlayer.volume(currentVolume); delay(50); - myDFPlayer.play(1); + myDFPlayer.play(1); // play the first track on boot (optional) + + printHelp(); + Serial.print(F("> ")); } void loop() { - static unsigned long timer = millis(); - - if (millis() - timer > 3000) { - timer = millis(); - myDFPlayer.next(); //Play next mp3 every 3 second. + // ---- read a line from the USB serial console ---- + while (Serial.available()) { + char c = (char)Serial.read(); + if (c == '\n' || c == '\r') { + if (cmdLen) { + cmdBuf[cmdLen] = '\0'; + handleLine(cmdBuf); + cmdLen = 0; + Serial.print(F("> ")); + } + continue; + } + if (cmdLen < sizeof(cmdBuf) - 1) { + cmdBuf[cmdLen++] = c; + } else { + cmdLen = 0; // overrun - drop the line + Serial.println(F("\n(input too long)")); + } } - + + // ---- surface DFPlayer events / errors ---- if (myDFPlayer.available()) { - printDetail(myDFPlayer.readType(), myDFPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states. + printDetail(myDFPlayer.readType(), myDFPlayer.read()); } } +static void strlwr_(char *s) { for (; *s; ++s) *s = tolower((unsigned char)*s); } + +void handleLine(char *line) +{ + strlwr_(line); + char *cmd = strtok(line, " \t"); + char *arg1 = strtok(NULL, " \t"); + char *arg2 = strtok(NULL, " \t"); + if (!cmd) return; + int n1 = arg1 ? atoi(arg1) : -1; + + if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) { + printHelp(); + } + else if (!strcmp(cmd, "status") || !strcmp(cmd, "stat")) { + printStatus(); + } + else if (!strcmp(cmd, "play")) { + if (n1 > 0) { myDFPlayer.play(n1); Serial.print(F("play track ")); Serial.println(n1); } + else { myDFPlayer.start(); Serial.println(F("play / resume")); } + } + else if (!strcmp(cmd, "pause")) { + myDFPlayer.pause(); Serial.println(F("paused")); + } + else if (!strcmp(cmd, "resume") || !strcmp(cmd, "start")) { + myDFPlayer.start(); Serial.println(F("resumed")); + } + else if (!strcmp(cmd, "stop")) { + myDFPlayer.stop(); Serial.println(F("stopped")); + } + else if (!strcmp(cmd, "next")) { + myDFPlayer.next(); Serial.println(F("next")); + } + else if (!strcmp(cmd, "prev") || !strcmp(cmd, "previous")) { + myDFPlayer.previous(); Serial.println(F("previous")); + } + else if (!strcmp(cmd, "vol") || !strcmp(cmd, "volume") || !strcmp(cmd, "v")) { + if (arg1 && (!strcmp(arg1, "up") || !strcmp(arg1, "+"))) currentVolume = min(30, currentVolume + 1); + else if (arg1 && (!strcmp(arg1, "down") || !strcmp(arg1, "-"))) currentVolume = max(0, currentVolume - 1); + else if (n1 >= 0) currentVolume = constrain(n1, 0, 30); + myDFPlayer.volume(currentVolume); + Serial.print(F("volume = ")); Serial.println(currentVolume); + } + else if (!strcmp(cmd, "+")) { + currentVolume = min(30, currentVolume + 1); + myDFPlayer.volume(currentVolume); + Serial.print(F("volume = ")); Serial.println(currentVolume); + } + else if (!strcmp(cmd, "-")) { + currentVolume = max(0, currentVolume - 1); + myDFPlayer.volume(currentVolume); + Serial.print(F("volume = ")); Serial.println(currentVolume); + } + else if (!strcmp(cmd, "loop")) { + if (n1 > 0) { myDFPlayer.loop(n1); Serial.print(F("loop track ")); Serial.println(n1); } + else Serial.println(F("usage: loop ")); + } + else if (!strcmp(cmd, "folder")) { + if (arg1 && arg2) { + myDFPlayer.playFolder(atoi(arg1), atoi(arg2)); + Serial.print(F("folder ")); Serial.print(atoi(arg1)); + Serial.print(F(" file ")); Serial.println(atoi(arg2)); + } else { + Serial.println(F("usage: folder ")); + } + } + else if (!strcmp(cmd, "eq")) { + int eq = -1; + if (arg1 && !strcmp(arg1, "normal")) eq = DFPLAYER_EQ_NORMAL; + else if (arg1 && !strcmp(arg1, "pop")) eq = DFPLAYER_EQ_POP; + else if (arg1 && !strcmp(arg1, "rock")) eq = DFPLAYER_EQ_ROCK; + else if (arg1 && !strcmp(arg1, "jazz")) eq = DFPLAYER_EQ_JAZZ; + else if (arg1 && !strcmp(arg1, "classic")) eq = DFPLAYER_EQ_CLASSIC; + else if (arg1 && !strcmp(arg1, "bass")) eq = DFPLAYER_EQ_BASS; + if (eq >= 0) { myDFPlayer.EQ(eq); Serial.print(F("eq ")); Serial.println(arg1); } + else Serial.println(F("usage: eq normal|pop|rock|jazz|classic|bass")); + } + else if (!strcmp(cmd, "reset")) { + myDFPlayer.reset(); + Serial.println(F("reset - waiting ~2s")); + delay(2000); + myDFPlayer.volume(currentVolume); + } + else { + Serial.print(F("unknown command: ")); Serial.println(cmd); + Serial.println(F("type 'help'")); + } +} + +void printHelp() +{ + Serial.println(F("--- DFPlayer console --------------------------------------")); + Serial.println(F(" play [n] play track n, or resume if no number")); + Serial.println(F(" pause pause playback")); + Serial.println(F(" resume resume playback")); + Serial.println(F(" stop stop playback")); + Serial.println(F(" next / prev skip track")); + Serial.println(F(" vol [n|up|down] set volume 0..30 (no arg = show)")); + Serial.println(F(" + / - volume up / down by 1")); + Serial.println(F(" loop [n] play track n on repeat")); + Serial.println(F(" folder play /ff/nnn.mp3")); + Serial.println(F(" eq normal|pop|rock|jazz|classic|bass")); + Serial.println(F(" reset re-init the DFPlayer")); + Serial.println(F(" status state / volume / file counts")); + Serial.println(F(" help this list")); + Serial.println(F("----------------------------------------------------------")); +} + +void printStatus() +{ + Serial.print(F("begin() ok : ")); Serial.println(dfOnline ? F("yes") : F("no")); + Serial.print(F("volume (shadow) : ")); Serial.println(currentVolume); + Serial.print(F("volume (device) : ")); Serial.println(myDFPlayer.readVolume()); + Serial.print(F("state : ")); Serial.println(myDFPlayer.readState()); + Serial.print(F("files on card : ")); Serial.println(myDFPlayer.readFileCounts()); + Serial.print(F("current file : ")); Serial.println(myDFPlayer.readCurrentFileNumber()); +} + void printDetail(uint8_t type, int value){ switch (type) { case TimeOut: @@ -134,5 +264,4 @@ void printDetail(uint8_t type, int value){ default: break; } - }