I’m really not sure how the read calls ever worked if they were called after a play call.
So, in trying to understand the play issue outlined in my last post, I went back to the ack issue and dug into the library code. When the ack is enabled, every DFPlayer library call first waits (with a timeout) for the last ack to be received before continuing on and sending the new command to the DFPlayer. This works fine for commands that are not read commands. For read commands the library still waits for the last ack and then waits for the data response from the DFPlayer. The problem is that the ack response is coming in before the data response. So, the ack response is being interpreted as the data response and then the actual data response gets cleared off in the next send because it is treated as an ack respose. It must be the case that older DFPlayers had the order reversed and the data response came in before the ack response. So, turning off the acks resolves this problem. Since some older posts note that this is only an issue for clones, I wonder if DFRobot has updated their chipset on their newer modules to the same chipsets used in the clones. If anyone has a really old DFRobot DFPlayer then it would be great to verify this. All you need to do is to uncomment the _DEBUG define in DFRobotDFPlayerMini.h and look to see if the ack messages are returned before the data messages when invoking a read method. The ack messages are “:7E FF 6 41 0 0 0 FE BA EF” where the 41 designates this as an acknowledgement.
However, even when the acks are disabled, if we send a play command the DFPlayer eventually responds with a “play finished” message (actually two of them for some reason). The next time we send a read command to the DFPlayer the play finished message is hanging out in the receive buffer and is interpreted as the data response to the read command. I don’t see anything in the library software that is designed to deal with this situation. So, I’m not clear on how this ever worked. If anyone has any insights here, I’d love to hear them!
Now, it is the case that when calling a read command most of these methods will do a sanity check on the data return and send back a “-1” if it doesn’t match what is expected. (For some inexplicable reason the readVolume call does not do this check, so it interprets the play finished message as valid and returns bad data.) I was thinking that I could just check the return value from the readFileCountsInFolder() call and if it’s a “-1” then call it again until I get back a good value. Well, this works for the first read call. The problem now is that we’ve sent multiple requests to the DFPlayer and these responses start buffering up. So, the next call to a read method will send the new command, wait for the response, and pull one of the previous read responses from the serial buffer. Now the response checks out as a valid data response, but the data is actually from the last read call.
Since the play finished messages can come in at any time, there is no way to anticipate when these could happen unless we always wait for play to finish. Any read calls made after a play but before the play finished is received would still be ok, but any read calls after the play finished messages will not work. If we wait for the play to finish, then we can delay a bit to make sure the play finished messages are queued and flush the receive buffer with calls to available() before calling read methods. But it’s hard for me to believe that this is how the library was intended to operate. The library could be modified to ignore play response messages, but if anyone is actually using these play finished messages to determine when play is completed (rather than the hardware busy pin) then these messages would be lost if a read call was made between the time the play completed and the user polled for the play response message.
So, short of modifying the library, I don’t see a way around this other than to just make sure that no read methods are invoked after play methods. My guess is that this is usually the way most user code is set up: get the DFPlayer configuration info during initialization and then start invoking play methods. Still, seems it should be fixed along with the ack issue. I’m really curious if anyone can validate what I’m seeing. If so, then perhaps we can all send messages to DFRobot asking them to fix the library! It looks like it hasn’t been updated in years.
Sorry for the long, complex post, but as I have seen that others have had these same problems and there has not been any good explanation, I wanted to get it all documented.