/*! * @file DFRobotDFPlayerMini.cpp * @brief DFPlayer - An Arduino Mini MP3 Player From DFRobot * @n Header file for DFRobot's DFPlayer * * @copyright [DFRobot]( http://www.dfrobot.com ), 2016 * @copyright GNU Lesser General Public License * * @author [Angelo](Angelo.qiao@dfrobot.com) * @version V1.0.3 * @date 2016-12-07 */ #include "DFRobotDFPlayerMini.h" void DFRobotDFPlayerMini::setTimeOut(unsigned long timeOutDuration){ _timeOutDuration = timeOutDuration; } void DFRobotDFPlayerMini::uint16ToArray(uint16_t value, uint8_t *array){ *array = (uint8_t)(value>>8); *(array+1) = (uint8_t)(value); } uint16_t DFRobotDFPlayerMini::calculateCheckSum(uint8_t *buffer){ uint16_t sum = 0; for (int i=Stack_Version; iwrite(_sending, DFPLAYER_SEND_LENGTH); _timeOutTimer = millis(); _isSending = _sending[Stack_ACK]; if (!_sending[Stack_ACK]) { //if the ack mode is off wait 10 ms after one transmition. delay(10); } } void DFRobotDFPlayerMini::sendStack(uint8_t command){ sendStack(command, 0); } void DFRobotDFPlayerMini::sendStack(uint8_t command, uint16_t argument){ _sending[Stack_Command] = command; uint16ToArray(argument, _sending+Stack_Parameter); uint16ToArray(calculateCheckSum(_sending), _sending+Stack_CheckSum); sendStack(); } void DFRobotDFPlayerMini::sendStack(uint8_t command, uint8_t argumentHigh, uint8_t argumentLow){ uint16_t buffer = argumentHigh; buffer <<= 8; sendStack(command, buffer | argumentLow); } void DFRobotDFPlayerMini::enableACK(){ _sending[Stack_ACK] = 0x01; } void DFRobotDFPlayerMini::disableACK(){ _sending[Stack_ACK] = 0x00; } bool DFRobotDFPlayerMini::waitAvailable(unsigned long duration){ unsigned long timer = millis(); if (!duration) { duration = _timeOutDuration; } while (!available()){ if (millis() - timer > duration) { return false; } delay(0); } return true; } bool DFRobotDFPlayerMini::begin(Stream &stream, bool isACK, bool doReset){ _serial = &stream; if (isACK) { enableACK(); } else{ disableACK(); } if (doReset) { reset(); waitAvailable(2000); delay(200); } else { // assume same state as with reset(): online _handleType = DFPlayerCardOnline; } return (readType() == DFPlayerCardOnline) || (readType() == DFPlayerUSBOnline) || !isACK; } uint8_t DFRobotDFPlayerMini::readType(){ _isAvailable = false; return _handleType; } uint16_t DFRobotDFPlayerMini::read(){ _isAvailable = false; return _handleParameter; } bool DFRobotDFPlayerMini::handleMessage(uint8_t type, uint16_t parameter){ _receivedIndex = 0; _handleType = type; _handleParameter = parameter; _isAvailable = true; return _isAvailable; } bool DFRobotDFPlayerMini::handleError(uint8_t type, uint16_t parameter){ handleMessage(type, parameter); _isSending = false; return false; } uint8_t DFRobotDFPlayerMini::readCommand(){ _isAvailable = false; return _handleCommand; } void DFRobotDFPlayerMini::parseStack(){ uint8_t handleCommand = *(_received + Stack_Command); if (handleCommand == 0x41) { //handle the 0x41 ack feedback as a spcecial case, in case the pollusion of _handleCommand, _handleParameter, and _handleType. _isSending = false; return; } _handleCommand = handleCommand; _handleParameter = arrayToUint16(_received + Stack_Parameter); switch (_handleCommand) { case 0x3D: handleMessage(DFPlayerPlayFinished, _handleParameter); break; case 0x3F: if (_handleParameter & 0x01) { handleMessage(DFPlayerUSBOnline, _handleParameter); } else if (_handleParameter & 0x02) { handleMessage(DFPlayerCardOnline, _handleParameter); } else if (_handleParameter & 0x03) { handleMessage(DFPlayerCardUSBOnline, _handleParameter); } break; case 0x3A: if (_handleParameter & 0x01) { handleMessage(DFPlayerUSBInserted, _handleParameter); } else if (_handleParameter & 0x02) { handleMessage(DFPlayerCardInserted, _handleParameter); } break; case 0x3B: if (_handleParameter & 0x01) { handleMessage(DFPlayerUSBRemoved, _handleParameter); } else if (_handleParameter & 0x02) { handleMessage(DFPlayerCardRemoved, _handleParameter); } break; case 0x40: handleMessage(DFPlayerError, _handleParameter); break; case 0x3C: case 0x3E: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: case 0x48: case 0x49: case 0x4B: case 0x4C: case 0x4D: case 0x4E: case 0x4F: handleMessage(DFPlayerFeedBack, _handleParameter); break; default: handleError(WrongStack); break; } } uint16_t DFRobotDFPlayerMini::arrayToUint16(uint8_t *array){ uint16_t value = *array; value <<=8; value += *(array+1); return value; } bool DFRobotDFPlayerMini::validateStack(){ return calculateCheckSum(_received) == arrayToUint16(_received+Stack_CheckSum); } bool DFRobotDFPlayerMini::available(){ while (_serial->available()) { delay(0); if (_receivedIndex == 0) { _received[Stack_Header] = _serial->read(); #ifdef _DEBUG Serial.print(F("received:")); Serial.print(_received[_receivedIndex],HEX); Serial.print(F(" ")); #endif if (_received[Stack_Header] == 0x7E) { _receivedIndex ++; } } else{ _received[_receivedIndex] = _serial->read(); #ifdef _DEBUG Serial.print(_received[_receivedIndex],HEX); Serial.print(F(" ")); #endif switch (_receivedIndex) { case Stack_Version: if (_received[_receivedIndex] != 0xFF) { return handleError(WrongStack); } break; case Stack_Length: if (_received[_receivedIndex] != 0x06) { return handleError(WrongStack); } break; case Stack_End: #ifdef _DEBUG Serial.println(); #endif if (_received[_receivedIndex] != 0xEF) { return handleError(WrongStack); } else{ if (validateStack()) { _receivedIndex = 0; parseStack(); return _isAvailable; } else{ return handleError(WrongStack); } } break; default: break; } _receivedIndex++; } } if (_isSending && (millis()-_timeOutTimer>=_timeOutDuration)) { return handleError(TimeOut); } return _isAvailable; } void DFRobotDFPlayerMini::next(){ sendStack(0x01); } void DFRobotDFPlayerMini::previous(){ sendStack(0x02); } void DFRobotDFPlayerMini::play(int fileNumber){ sendStack(0x03, fileNumber); } void DFRobotDFPlayerMini::volumeUp(){ sendStack(0x04); } void DFRobotDFPlayerMini::volumeDown(){ sendStack(0x05); } void DFRobotDFPlayerMini::volume(uint8_t volume){ sendStack(0x06, volume); } void DFRobotDFPlayerMini::EQ(uint8_t eq) { sendStack(0x07, eq); } void DFRobotDFPlayerMini::loop(int fileNumber) { sendStack(0x08, fileNumber); } void DFRobotDFPlayerMini::outputDevice(uint8_t device) { sendStack(0x09, device); delay(200); } void DFRobotDFPlayerMini::sleep(){ sendStack(0x0A); } void DFRobotDFPlayerMini::reset(){ sendStack(0x0C); } void DFRobotDFPlayerMini::start(){ sendStack(0x0D); } void DFRobotDFPlayerMini::pause(){ sendStack(0x0E); } void DFRobotDFPlayerMini::playFolder(uint8_t folderNumber, uint8_t fileNumber){ sendStack(0x0F, folderNumber, fileNumber); } void DFRobotDFPlayerMini::outputSetting(bool enable, uint8_t gain){ sendStack(0x10, enable, gain); } void DFRobotDFPlayerMini::enableLoopAll(){ sendStack(0x11, 0x01); } void DFRobotDFPlayerMini::disableLoopAll(){ sendStack(0x11, 0x00); } void DFRobotDFPlayerMini::playMp3Folder(int fileNumber){ sendStack(0x12, fileNumber); } void DFRobotDFPlayerMini::advertise(int fileNumber){ sendStack(0x13, fileNumber); } void DFRobotDFPlayerMini::playLargeFolder(uint8_t folderNumber, uint16_t fileNumber){ sendStack(0x14, (((uint16_t)folderNumber) << 12) | fileNumber); } void DFRobotDFPlayerMini::stopAdvertise(){ sendStack(0x15); } void DFRobotDFPlayerMini::stop(){ sendStack(0x16); } void DFRobotDFPlayerMini::loopFolder(int folderNumber){ sendStack(0x17, folderNumber); } void DFRobotDFPlayerMini::randomAll(){ sendStack(0x18); } void DFRobotDFPlayerMini::enableLoop(){ sendStack(0x19, 0x00); } void DFRobotDFPlayerMini::disableLoop(){ sendStack(0x19, 0x01); } void DFRobotDFPlayerMini::enableDAC(){ sendStack(0x1A, 0x00); } void DFRobotDFPlayerMini::disableDAC(){ sendStack(0x1A, 0x01); } int DFRobotDFPlayerMini::readState(){ sendStack(0x42); if (waitAvailable()) { if (readType() == DFPlayerFeedBack) { return read(); } else{ return -1; } } else{ return -1; } } int DFRobotDFPlayerMini::readVolume(){ sendStack(0x43); if (waitAvailable()) { return read(); } else{ return -1; } } int DFRobotDFPlayerMini::readEQ(){ sendStack(0x44); if (waitAvailable()) { if (readType() == DFPlayerFeedBack) { return read(); } else{ return -1; } } else{ return -1; } } int DFRobotDFPlayerMini::readFileCounts(uint8_t device){ switch (device) { case DFPLAYER_DEVICE_U_DISK: sendStack(0x47); break; case DFPLAYER_DEVICE_SD: sendStack(0x48); break; case DFPLAYER_DEVICE_FLASH: sendStack(0x49); break; default: break; } if (waitAvailable()) { if (readType() == DFPlayerFeedBack) { return read(); } else{ return -1; } } else{ return -1; } } int DFRobotDFPlayerMini::readCurrentFileNumber(uint8_t device){ switch (device) { case DFPLAYER_DEVICE_U_DISK: sendStack(0x4B); break; case DFPLAYER_DEVICE_SD: sendStack(0x4C); break; case DFPLAYER_DEVICE_FLASH: sendStack(0x4D); break; default: break; } if (waitAvailable()) { if (readType() == DFPlayerFeedBack) { return read(); } else{ return -1; } } else{ return -1; } } int DFRobotDFPlayerMini::readFileCountsInFolder(int folderNumber){ sendStack(0x4E, folderNumber); if (waitAvailable()) { if (readType() == DFPlayerFeedBack) { return read(); } else{ return -1; } } else{ return -1; } } int DFRobotDFPlayerMini::readFolderCounts(){ sendStack(0x4F); if (waitAvailable()) { if (readType() == DFPlayerFeedBack) { return read(); } else{ return -1; } } else{ return -1; } } int DFRobotDFPlayerMini::readFileCounts(){ return readFileCounts(DFPLAYER_DEVICE_SD); } int DFRobotDFPlayerMini::readCurrentFileNumber(){ return readCurrentFileNumber(DFPLAYER_DEVICE_SD); }