1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-11-22 23:56:13 +01:00

Update IO_DFPlayer.h

Rework delay between command: instead of sending null characters, which doesn't work on some chip sets, send commands from the _loop() function with a 100ms delay between consecutive commands.
This commit is contained in:
Neil McKechnie 2023-03-15 09:20:42 +00:00
parent 881463ada9
commit 325d4bce73

View File

@ -75,20 +75,9 @@ private:
bool _playing = false; bool _playing = false;
uint8_t _inputIndex = 0; uint8_t _inputIndex = 0;
unsigned long _commandSendTime; // Allows timeout processing unsigned long _commandSendTime; // Allows timeout processing
uint8_t _lastVolumeLevel = MAXVOLUME; uint8_t _requestedVolumeLevel = MAXVOLUME;
uint8_t _currentVolume = MAXVOLUME;
// When two commands are sent in quick succession, the device sometimes int _requestedSong = -1; // -1=none, 0=stop, >0=file number
// fails to execute one. A delay is required between successive commands.
// This could be implemented by buffering commands and outputting them
// from the loop() function, but it would somewhat complicate the
// driver. A simpler solution is to output a number of NUL pad characters
// between successive command strings if there isn't sufficient elapsed time
// between them. At 9600 baud, each pad character takes approximately
// 1ms to complete. Experiments indicate that the minimum number of pads
// for reliable operation is 17. This gives 17.7ms between the end of one
// command and the beginning of the next, or 28ms between successive commands
// being completed. I've allowed 20 characters, which is almost 21ms.
const int numPadCharacters = 20; // Number of pad characters between commands
public: public:
@ -148,11 +137,39 @@ protected:
} else } else
_inputIndex = 0; // Unrecognised character sequence, start again! _inputIndex = 0; // Unrecognised character sequence, start again!
} }
// Check if the initial prompt to device has timed out. Allow 5 seconds // Check if the initial prompt to device has timed out. Allow 5 seconds
if (_deviceState == DEVSTATE_INITIALISING && currentMicros - _commandSendTime > 5000000UL) { if (_deviceState == DEVSTATE_INITIALISING && currentMicros - _commandSendTime > 5000000UL) {
DIAG(F("DFPlayer device not responding on serial port")); DIAG(F("DFPlayer device not responding on serial port"));
_deviceState = DEVSTATE_FAILED; _deviceState = DEVSTATE_FAILED;
} }
// When two commands are sent in quick succession, the device will often fail to
// execute one. Testing has indicated that a delay of 100ms or more is required
// between successive commands to get reliable operation.
// If 100ms has elapsed since the last thing sent, then check if there's some output to do.
if (currentMicros - _commandSendTime > 100000UL) {
if (_currentVolume > _requestedVolumeLevel) {
// Change volume before changing song if volume is reducing.
_currentVolume = _requestedVolumeLevel;
sendPacket(0x06, _currentVolume);
_commandSendTime = currentMicros;
} else if (_requestedSong > 0) {
// Change song
sendPacket(0x03, _requestedSong);
_requestedSong = -1;
_commandSendTime = currentMicros;
} else if (_requestedSong == 0) {
sendPacket(0x16); // Stop playing
_requestedSong = -1;
_commandSendTime = currentMicros;
} else if (_currentVolume < _requestedVolumeLevel) {
// Change volume after changing song if volume is increasing.
_currentVolume = _requestedVolumeLevel;
sendPacket(0x06, _currentVolume);
_commandSendTime = currentMicros;
}
}
delayUntil(currentMicros + 10000); // Only enter every 10ms delayUntil(currentMicros + 10000); // Only enter every 10ms
} }
@ -165,14 +182,14 @@ protected:
#ifdef DIAG_IO #ifdef DIAG_IO
DIAG(F("DFPlayer: Play %d"), pin+1); DIAG(F("DFPlayer: Play %d"), pin+1);
#endif #endif
sendPacket(0x03, pin+1); _requestedSong = pin+1;
_playing = true; _playing = true;
} else { } else {
// Value 0, stop playing // Value 0, stop playing
#ifdef DIAG_IO #ifdef DIAG_IO
DIAG(F("DFPlayer: Stop")); DIAG(F("DFPlayer: Stop"));
#endif #endif
sendPacket(0x16); _requestedSong = 0; // No song
_playing = false; _playing = false;
} }
} }
@ -181,10 +198,6 @@ protected:
// Volume may be specified as second parameter to writeAnalogue. // Volume may be specified as second parameter to writeAnalogue.
// If value is zero, the player stops playing. // If value is zero, the player stops playing.
// WriteAnalogue on second pin sets the output volume. // WriteAnalogue on second pin sets the output volume.
// If starting a new file and setting volume, then avoid a short burst of loud noise by
// the following strategy:
// - If the volume is increasing, start playing the song before setting the volume,
// - If the volume is decreasing, decrease it and then start playing.
// //
void _writeAnalogue(VPIN vpin, int value, uint8_t volume=0, uint16_t=0) override { void _writeAnalogue(VPIN vpin, int value, uint8_t volume=0, uint16_t=0) override {
uint8_t pin = vpin - _firstVpin; uint8_t pin = vpin - _firstVpin;
@ -198,28 +211,18 @@ protected:
if (pin == 0) { if (pin == 0) {
// Play track // Play track
if (value > 0) { if (value > 0 && volume != 0) {
if (volume != 0) { if (volume != 0)
if (volume <= _lastVolumeLevel) _requestedVolumeLevel = volume;
sendPacket(0x06, volume); // Set volume before starting _requestedSong = value;
sendPacket(0x03, value); // Play track _playing = true;
_playing = true;
if (volume > _lastVolumeLevel)
sendPacket(0x06, volume); // Set volume after starting
_lastVolumeLevel = volume;
} else {
// Volume not changed, just play
sendPacket(0x03, value);
_playing = true;
}
} else { } else {
sendPacket(0x16); // Stop play _requestedSong = 0; // stop playing
_playing = false; _playing = false;
} }
} else if (pin == 1) { } else if (pin == 1) {
// Set volume (0-30) // Set volume (0-30)
sendPacket(0x06, value); _requestedVolumeLevel = volume;
_lastVolumeLevel = volume;
} }
} }
@ -246,7 +249,6 @@ private:
void sendPacket(uint8_t command, uint16_t arg = 0) void sendPacket(uint8_t command, uint16_t arg = 0)
{ {
unsigned long currentMillis = millis();
uint8_t out[] = { 0x7E, uint8_t out[] = { 0x7E,
0xFF, 0xFF,
06, 06,
@ -260,19 +262,8 @@ private:
setChecksum(out); setChecksum(out);
// Check how long since the last command was sent. // Output the command
// Each character takes approx 1ms at 9600 baud
unsigned long minimumGap = numPadCharacters + sizeof(out);
if (currentMillis - _commandSendTime < minimumGap) {
// Output some pad characters to add an
// artificial delay between commands
for (int i=0; i<numPadCharacters; i++)
_serial->write((uint8_t)0);
}
// Now output the command
_serial->write(out, sizeof(out)); _serial->write(out, sizeof(out));
_commandSendTime = currentMillis;
} }
uint16_t calcChecksum(uint8_t* packet) uint16_t calcChecksum(uint8_t* packet)