258 lines
6.4 KiB
C++
258 lines
6.4 KiB
C++
/**
|
|
|
|
*/
|
|
|
|
|
|
#include "GD5800_Serial.h"
|
|
|
|
|
|
|
|
void GD5800_Serial::play()
|
|
{
|
|
this->sendCommand(0x01);
|
|
}
|
|
|
|
void GD5800_Serial::restart()
|
|
{
|
|
byte oldVolume = this->getVolume();
|
|
this->setVolume(0);
|
|
this->next();
|
|
this->pause();
|
|
this->setVolume(oldVolume);
|
|
this->prev();
|
|
}
|
|
|
|
void GD5800_Serial::pause()
|
|
{
|
|
this->sendCommand(0x02);
|
|
}
|
|
|
|
void GD5800_Serial::next()
|
|
{
|
|
this->sendCommand(0x03);
|
|
}
|
|
|
|
void GD5800_Serial::prev()
|
|
{
|
|
this->sendCommand(0x04);
|
|
}
|
|
void GD5800_Serial::fastReverse()
|
|
{
|
|
this->sendCommand(0x0B);
|
|
}
|
|
|
|
void GD5800_Serial::fastForward()
|
|
{
|
|
this->sendCommand(0x0A);
|
|
}
|
|
|
|
void GD5800_Serial::playFileByIndexNumber(unsigned int fileNumber)
|
|
{
|
|
this->sendCommand(0x41, (fileNumber>>8) & 0xFF, fileNumber & (byte)0xFF);
|
|
}
|
|
|
|
|
|
void GD5800_Serial::volumeUp()
|
|
{
|
|
this->sendCommand(0x05);
|
|
}
|
|
|
|
void GD5800_Serial::volumeDn()
|
|
{
|
|
this->sendCommand(0x06);
|
|
}
|
|
|
|
void GD5800_Serial::setVolume(byte volumeFrom0To30)
|
|
{
|
|
this->sendCommand(0x31, volumeFrom0To30);
|
|
}
|
|
|
|
void GD5800_Serial::setEqualizer(byte equalizerMode)
|
|
{
|
|
this->sendCommand(0x32, equalizerMode);
|
|
}
|
|
|
|
void GD5800_Serial::setLoopMode(byte loopMode)
|
|
{
|
|
this->sendCommand(0x33, loopMode);
|
|
}
|
|
|
|
|
|
|
|
|
|
byte GD5800_Serial::getStatus()
|
|
{
|
|
byte statTotal = 0;
|
|
byte stat = 0;
|
|
do
|
|
{
|
|
statTotal = 0;
|
|
for(byte x = 0; x < MP3_STATUS_CHECKS_IN_AGREEMENT; x++)
|
|
{
|
|
stat = this->sendCommandWithUnsignedIntResponse(0x42);
|
|
if(stat == 0) return 0; // STOP is fairly reliable
|
|
statTotal += stat;
|
|
}
|
|
|
|
} while (statTotal != 1 * MP3_STATUS_CHECKS_IN_AGREEMENT && statTotal != 2 * MP3_STATUS_CHECKS_IN_AGREEMENT);
|
|
|
|
return statTotal / MP3_STATUS_CHECKS_IN_AGREEMENT;
|
|
}
|
|
|
|
byte GD5800_Serial::getVolume() { return this->sendCommandWithUnsignedIntResponse(0x11); }
|
|
byte GD5800_Serial::getEqualizer() { return this->sendCommandWithUnsignedIntResponse(0x44); }
|
|
byte GD5800_Serial::getLoopMode() { return this->sendCommandWithUnsignedIntResponse(0x13); }
|
|
|
|
unsigned int GD5800_Serial::countFiles()
|
|
{
|
|
|
|
return this->sendCommandWithUnsignedIntResponse(0x16);
|
|
}
|
|
|
|
unsigned int GD5800_Serial::currentFileIndexNumber()
|
|
{
|
|
|
|
return this->sendCommandWithUnsignedIntResponse(0x1A);
|
|
}
|
|
|
|
|
|
|
|
// Used for the status commands, they mostly return an 8 to 16 bit integer
|
|
// and take no arguments
|
|
unsigned int GD5800_Serial::sendCommandWithUnsignedIntResponse(byte command)
|
|
{
|
|
char buffer[5];
|
|
this->sendCommand(command, 0, 0, buffer, sizeof(buffer));
|
|
return (unsigned int) strtoul(buffer, NULL, 16);
|
|
}
|
|
|
|
void GD5800_Serial::sendCommand(byte command)
|
|
{
|
|
this->sendCommand(command, 0, 0, 0, 0);
|
|
}
|
|
|
|
void GD5800_Serial::sendCommand(byte command, byte arg1)
|
|
{
|
|
this->sendCommand(command, arg1, 0, 0, 0);
|
|
}
|
|
|
|
void GD5800_Serial::sendCommand(byte command, byte arg1, byte arg2)
|
|
{
|
|
this->sendCommand(command, arg1, arg2, 0, 0);
|
|
}
|
|
|
|
void GD5800_Serial::sendCommand(byte command, byte arg1, byte arg2, char *responseBuffer, unsigned int bufferLength)
|
|
{
|
|
|
|
|
|
// Command structure
|
|
// [7E][number bytes following including command and terminator][command byte][?arg1][?arg2][EF]
|
|
|
|
// Most commands do not have arguments
|
|
byte args = 0;
|
|
|
|
// These ones do
|
|
switch(command)
|
|
{
|
|
case 0x41: args = 2; break;//指定曲目
|
|
case 0x31: args = 1; break;//指定音量
|
|
case 0x32: args = 1; break;//指定EQ
|
|
case 0x09: args = 1; break;//指定设备
|
|
case 0x33: args = 1; break;//循环播放
|
|
default :args=1;break;
|
|
}
|
|
|
|
#if MP3_DEBUG
|
|
char buf[4];
|
|
Serial.println();
|
|
Serial.print("7E ");
|
|
itoa(2+args, buf, 16); Serial.print(buf); Serial.print(" "); memset(buf, 0, sizeof(buf));
|
|
itoa(command, buf, 16); Serial.print(buf); Serial.print(" "); memset(buf, 0, sizeof(buf));
|
|
if(args>=1) itoa(arg1, buf, 16); Serial.print(buf); Serial.print(" "); memset(buf, 0, sizeof(buf));
|
|
if(args>=2) itoa(arg2, buf, 16); Serial.print(buf); Serial.print(" "); memset(buf, 0, sizeof(buf));
|
|
Serial.print("EF");
|
|
#endif
|
|
|
|
// The device appears to send some sort of status information (namely "STOP" when it stops playing)
|
|
// just discard this right before we send the command
|
|
while(this->waitUntilAvailable(10)) this->read();
|
|
|
|
this->write((byte)0x7E);
|
|
this->write(2+args);
|
|
this->write(command);
|
|
if(args>=1) this->write(arg1);
|
|
if(args==2) this->write(arg2);
|
|
this->write((byte)0xEF);
|
|
|
|
|
|
unsigned int i = 0;
|
|
char j = 0;
|
|
if(responseBuffer && bufferLength)
|
|
{
|
|
memset(responseBuffer, 0, bufferLength);
|
|
}
|
|
|
|
// Allow some time for the device to process what we did and
|
|
// respond, up to 1 second, but typically only a few ms.
|
|
this->waitUntilAvailable(1000);
|
|
|
|
|
|
#if MP3_DEBUG
|
|
Serial.print(" ==> [");
|
|
#endif
|
|
|
|
while(this->waitUntilAvailable(150))
|
|
{
|
|
j = (char)this->read();
|
|
|
|
#if MP3_DEBUG
|
|
Serial.print(j);
|
|
#endif
|
|
if(responseBuffer && (i<(bufferLength-1)))
|
|
{
|
|
responseBuffer[i++] = j;
|
|
}
|
|
}
|
|
|
|
#if MP3_DEBUG
|
|
Serial.print("]");
|
|
Serial.println();
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
// as readBytes with terminator character
|
|
// terminates if length characters have been read, timeout, or if the terminator character detected
|
|
// returns the number of characters placed in the buffer (0 means no valid data found)
|
|
|
|
size_t GD5800_Serial::readBytesUntilAndIncluding(char terminator, char *buffer, size_t length, byte maxOneLineOnly)
|
|
{
|
|
if (length < 1) return 0;
|
|
size_t index = 0;
|
|
while (index < length) {
|
|
int c = timedRead();
|
|
if (c < 0) break;
|
|
*buffer++ = (char)c;
|
|
index++;
|
|
if(c == terminator) break;
|
|
if(maxOneLineOnly && ( c == '\n') ) break;
|
|
}
|
|
return index; // return number of characters, not including null terminator
|
|
}
|
|
|
|
|
|
// Waits until data becomes available, or a timeout occurs
|
|
int GD5800_Serial::waitUntilAvailable(unsigned long maxWaitTime)
|
|
{
|
|
unsigned long startTime;
|
|
int c = 0;
|
|
startTime = millis();
|
|
do {
|
|
c = this->available();
|
|
if (c) break;
|
|
} while(millis() - startTime < maxWaitTime);
|
|
|
|
return c;
|
|
}
|