/* * Copyright 2019 Marian Buschsieweke * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level * directory for more details. */ /** * @defgroup drivers_dfplayer DFPlayer Mini MP3 Player * @ingroup drivers_multimedia * @brief Driver for the DFPlayer Mini MP3 Player * * The DFPlayer Mini is a super cheap MP3 Player that can be controlled via * UART. It can play files from SD card, USB storage devices and NOR flash. * It has an integrated 3W amplifier that can be used to build a standalone * mono speaker. Alternatively a stereo output can be used that can be * directly connected to headphones, but needs a dedicated amplifier for * connecting to passive speakers. * * ![DFPlayer pinout](https://camo.githubusercontent.com/fd6ed047e8e3ced124b32051ddfff2df9e8afe47/68747470733a2f2f63646e2e73686f706966792e636f6d2f732f66696c65732f312f313530392f313633382f66696c65732f4d50335f706c617965725f6d6f64756c655f70696e6f75745f6469616772616d2e706e67) * * File System Setup * ================= * * The SD card or USB storage devices needs to be formatted as FAT32 and the * MP3 files have to be stored using one of the following naming schemes, if * selecting the files efficiently is required: * * Numbered File Inside Numbered Folder Naming Scheme * -------------------------------------------------- * * The MP3 files have to be named with three leading decimal digits (e.g. * `001.mp3` or `042 - foo bar.mp3`) and must be placed in in folders named with * two decimal digits (e.g. `01` or `99`). The folder name numbers must be in * the range 1-99 and the file name numbers in the range 1-255. Playback of * these files can be started using the function @ref dfplayer_play_file . * * Examples of valid paths: * * - `01/001.mp3` * - `19/249 - Nothing Else Matters.mp3` * * Examples of ***INVALID*** paths: * * - `01 - Yngwie Malmsteen/042 - Leonardo.mp3` * - The folder name must only consist of two digits, additional chars are * not allowed in the folder name * - `9/42.mp3` * - Leading zeros must be added, e.g. `09/042.mp3` would be valid * - `99/359.mp3` * - Folder number out of range (1-255 is valid) * * Numbered File Inside MP3 Folder Naming Scheme * --------------------------------------------- * * The MP3 files have to be named with four decimal digits and must be placed in * the folder `"MP3"`. Subsequent characters after the four digits are ignored. * Valid names are e.g. `MP3/0001.mp3` or `MP3/0042 - My favorite song.mp3`. The * file numbers 1-9999 are valid. Playback of these files can be started using * the function @ref dfplayer_play_from_mp3 . * * Advertisements * -------------- * * MP3 files placed in the folder `"ADVERT"` named with four decimal digits * (e.g. `"0001.mp3"` or `"1337.mp3"`) can be played as advertisements: The * function @ref dfplayer_play_from_advert can be used to start their playback, * but only while a non-advertisement is currently playing. After the * advertisement the normal playback is resumed. This feature has been * implemented in the hope it is used for features like audible user feedback * to controls, rather than playing advertisements. * * Combining Naming Schemes * ------------------------ * * All of the above naming schemes can be used on the same storage device. * However, you still have to use to the functions intended to be used with * the naming scheme of a specific file in order to be able to play it. * * Track Numbers * ============= * * @warning Track numbers are a bogus unit in the DFPlayer * * Track numbers in the dfplayer revert to the number of the file in the file * system. Without preparing the medium played at a very low level, it will be * hard to map track numbers to their corresponding songs. If you started * playback using @ref dfplayer_play_file or @ref dfplayer_play_from_mp3, you * can use @ref dfplayer_get_played_file to get the currently played filed * according to the used naming scheme (see section above). * * Continuous Playback * =================== * * The are two options for achieving continuous playback with the DFPlayer Mini: * The first is to use @ref dfplayer_shuffle_all or @ref dfplayer_repeat_folder * to schedule shuffled playback of all files or repeat playback of a folder, * respectively. But keep in mind that any playback command will switch back to * normal playback mode. * * The second option is to schedule playback of the next file right after the * playback of a file has completed. This can be implemented most conveniently * by using the callback functions (see @ref dfplayer_set_callbacks). But * beware: The callbacks are called in interrupt context and the API of this * driver ***MUST ONLY*** be used in thread context. * * Known Hardware Bugs * =================== * * Device Bugs Not Handled by the Driver * ------------------------------------- * * On some versions of the DFPlayer, any UART communication with the device * during playback results in audible and unpleasant glitches. The only solution * is to not communicate with the device during playback, as the DFPlayer seems * to pause playback for some milliseconds after receiving a command. If the * busy pin of the DFPlayer is connected to your board and configured, the * function @ref dfplayer_get_state will read the busy pin to detect if the * DFPlayer is currently playing. Onlyif according to the busy pin the device is * not currently playing, the UART interface is used to detect whether the * playback is paused or stopped. Thus, @ref dfplayer_get_state can be used * without fearing to cause audio glitches, provided the busy pin is connected * and configured. You can use this to poll the state of the DPlayer and issue * the commands once playback has completed, or use the callbacks (see * @ref dfplayer_set_callbacks) to get notified when playback has completed. * * When playback of a file from the `"ADVERT"` folder is started while the * device not playing, or already playing a file from the `"ADVERT"` folder, * the command fails to execute and the DFPlayer stops all playback (if * currently playing). * * Device Bugs Handled by the Driver * --------------------------------- * * (These bugs are transparently handled by the driver, so users of the driver * can safely skip reading this section.) * * When playing a file from the MP3 folder or from the ADVERT folder, the * DFPlayer acknowledges the command before checking if the file actually * exists. If the file does not exist, a second message to indicate the failure * is send, but no second message is send on success. If the second message is * not received, the driver has to figure out by other means if this is a * communication error or indicates that the playback has started. If the * busy pin of the DFPlayer is connected and configured, it will be used to * verify that the command succeeded. Otherwise, the driver will query the * status of the device via UART to confirm that playback started, which can * cause audible glitches on some revisions. For those revisions, the busy pin * should be really used. * * When the DFPlayer completes playback of a file, the next command received * is not acknowledged, if it is a control command. Query commands are not * affected. The driver works around this bug by querying the volume prior to * issuing a control command directly after playback completed. * * Some versions of the DFPlayer are not able to handle commands send at high * frequency. A delay of 100ms is inserted after every communication with the * device to counter this. * * Some versions of the DFPlayer have a high chance of ignoring commands. The * driver tries up to @ref DFPLAYER_RETRIES (`5` be default) times the command * before giving up. For that reason, non-idempotent commands supported by the * DFPlayer (e.g. increase and decrease volume) are not exposed by the driver, * as retrying could result in them being executed more than once. There are * idempotent commands that can achieve the same (e.g. the set volume command * instead of increase or decrease volume commands) for every non-idempotent * command, so this doesn't restrict the feature set of the driver. * * @{ * * @file * @brief DFPlayer Mini Device Driver * * @author Marian Buschsieweke */ #ifndef DFPLAYER_H #define DFPLAYER_H #include #include #include "dfplayer_params.h" #include "dfplayer_types.h" #ifdef __cplusplus extern "C" { #endif /** * @brief The number of milliseconds to wait after receiving playback of file * has completed before starting playback of the next file */ #define DFPLAYER_WAIT_MS (100U) #ifdef MODULE_AUTO_INIT_MULTIMEDIA extern dfplayer_t dfplayer_devs[DFPLAYER_NUMOF]; /** * @brief Get an auto-initialized DFPlayer Mini device descriptor by number * @param num Number of the DFPlayer Mini device descriptor to get * @return The DFPlayer Mini device descriptor at index @p num * @retval `NULL` @p num is out of range * * A value of `0` for @p num is used to retrieve the first device descriptor. */ static inline dfplayer_t * dfplayer_get(unsigned num) { if (num < DFPLAYER_NUMOF) { return &dfplayer_devs[num]; } return NULL; } #endif /* MODULE_AUTO_INIT_MULTIMEDIA */ /** * @brief Initialize a DFPlayer Mini device descriptor * * @param dev Device descriptor to initialized * @param params Connection parameters to initialize with * * @retval 0 Success * @retval -EINVAL Invalid parameters * @retval -EIO Failed to initialize UART interface / GPIO pin * @retval -ETIMEDOUT Response of the DFPlayer timed out */ int dfplayer_init(dfplayer_t *dev, const dfplayer_params_t *params); /** * @brief Get the set of available playback sources of the given DFPlayer * * @param dev Device descriptor of the DFPlayer Mini check * * @return The set of playback sources currently available * @retval 0 If @p dev is `NULL` or no source is available */ dfplayer_source_set_t dfplayer_get_sources(dfplayer_t *dev); /** * @brief Set/clear the event callbacks of the DFPlayer Mini * * @param dev Device descriptor of the DFPlayer to update * @param cb_done Function to call when playback of a file/track completed * @param cb_src Function to call when a source was inserted/ejected * * @retval 0 Success * @retval -EINVAL Called with invalid parameter * * Calling with `NULL` for @p cb_done and/or for @p cb_src clears the * corresponding callback functions. * * @warning The callbacks are called from interrupt context */ int dfplayer_set_callbacks(dfplayer_t *dev, dfplayer_cb_done_t cb_done, dfplayer_cb_src_t cb_src); /** * @brief Start playing the next song in the currently used naming scheme * * @param dev Device descriptor of the DFPlayer to control * * @retval 0 Success * @retval -EINVAL Called with invalid parameter * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out * @retval -ERANGE The next song is out of range (depending to the * currently used naming scheme) * @retval -ENOENT No such file * * If previously @ref dfplayer_play_file was used to start playback of * file "42/113.mp3", this call will try to start "42/114.mp3". If previously * @ref dfplayer_play_from_mp3 was used to start playback of file * "MP3/1337.mp3", this call will try to start "MP3/1338.mp3". */ static inline int dfplayer_next(dfplayer_t *dev); /** * @brief Start playing the previous song in the currently used naming scheme * * @param dev Device descriptor of the DFPlayer to control * * @retval 0 Success * @retval -EINVAL Called with invalid parameter * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out * @retval -ERANGE The next song is out of range (depending to the * currently used naming scheme) * @retval -ENOENT No such file * * If previously @ref dfplayer_play_file was used to start playback of * file "42/113.mp3", this call will try to start "42/112.mp3". If previously * @ref dfplayer_play_from_mp3 was used to start playback of file * "MP3/1337.mp3", this call will try to start "MP3/1336.mp3". */ static inline int dfplayer_prev(dfplayer_t *dev); /** * @brief Step forward/backward following the currently used naming scheme * * @param dev Device descriptor of the DFPlayer to control * @param step Steps to take (negative for previous files) * * @retval 0 Success * @retval -EINVAL Called with invalid parameter * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out * @retval -ERANGE The next song is out of range (depending to the * currently used naming scheme) * @retval -ENOENT No such file * * Calling with a value of `1` for @p step is equivalent to @ref dfplayer_next, * calling with a value of `-1` for @p step is equivalent to @ref dfplayer_prev. * A value of `0` will restart the currently played song */ int dfplayer_step(dfplayer_t *dev, int step); /** * @brief Sets the volume to the given value * * @param dev Device descriptor of the DFPlayer to control * @param volume Volume to set (max 30) * * @retval 0 Success * @retval -EINVAL Called with invalid parameters * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out * * If @p volume is greater than the maximum allowed volume of 30, 30 will be * send instead. */ static inline int dfplayer_set_volume(dfplayer_t *dev, uint8_t volume); /** * @brief Apply the given equalizer setting * * @param dev Device descriptor of the DFPlayer to control * @param equalizer The equalizer setting to apply * * @retval 0 Success * @retval -EINVAL Called with invalid parameters * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out */ static inline int dfplayer_set_equalizer(dfplayer_t *dev, dfplayer_eq_t equalizer); /** * @brief Apply the given source * * @param dev Device descriptor of the DFPlayer to control * @param src The source to use for playback * * @retval 0 Success * @retval -EINVAL Called with invalid parameters * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out */ static inline int dfplayer_set_source(dfplayer_t *dev, dfplayer_source_t src); /** * @brief Enter standby mode * * @param dev Device descriptor of the DFPlayer to control * * @retval 0 Success * @retval -EINVAL Called with invalid parameters * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out */ static inline int dfplayer_enter_standby(dfplayer_t *dev); /** * @brief Exit standby mode * * @param dev Device descriptor of the DFPlayer to control * * @retval 0 Success * @retval -EINVAL Called with invalid parameters * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out */ static inline int dfplayer_exit_standby(dfplayer_t *dev); /** * @brief Start/resume playing * * @param dev Device descriptor of the DFPlayer to control * * @retval 0 Success * @retval -EINVAL Called with invalid parameter * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out */ static inline int dfplayer_play(dfplayer_t *dev); /** * @brief Pause the playback * * @param dev Device descriptor of the DFPlayer to control * * @retval 0 Success * @retval -EINVAL Called with invalid parameter * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out */ static inline int dfplayer_pause(dfplayer_t *dev); /** * @brief Start playing the specified file in the specified folder * * @param dev Device descriptor of the DFPlayer to control * @param folder Number of the folder * @param file Number of the file * * @retval 0 Success * @retval -EINVAL Called with invalid parameters (see precondition) * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out * @retval -ENOENT Specified file and/or folder does not exist * * @pre `0 < folder <= 100` and `file > 0` * * E.g. when called with @p folder set to `9` and @p file set to `42`, the * file `"09/042.mp3"` is played. Thus, the folder and file names need to * follow a specific naming convention in order to be selectable with this * function. */ int dfplayer_play_file(dfplayer_t *dev, uint8_t folder, uint8_t file); /** * @brief Start playing the specified number in the MP3 folder * * @param dev Device descriptor of the DFPlayer to control * @param number Number of the file in the folder `"MP3"` to play * * @retval 0 Success * @retval -EINVAL Called with invalid parameters (see precondition) * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out * @retval -ENOENT Specified number does not exist * * @pre `0 < number <= 9999` * * E.g. when called with @p number set to `42`, the file `"MP3/0042.mp3"` is * played. Thus, the folder and file names need to follow a specific naming * convention in order to be selectable with this function. */ int dfplayer_play_from_mp3(dfplayer_t *dev, uint16_t number); /** * @brief Start playing the specified number in the ADVERT folder * * @param dev Device descriptor of the DFPlayer to control * @param number Number of the number in the folder `"ADVERT"` to play * * @retval 0 Success * @retval -EINVAL Called with invalid parameters (see precondition) * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out * @retval -ENOENT Specified number does not exist * * @pre `0 < number <= 9999` * @warning The playback is only started when the DFPlayer is currently playing * a non-advert file. The current playback is paused, the advert-file * is played, and the previous playback is resumed afterwards * @note While this feature was obviously added to allow playing * advertisements, this function was provided in the best hope it is * not used this way. * * E.g. when called with @p number set to `42`, the file `"ADVERT/0042.mp3"` is * played. Thus, the folder and file names need to follow a specific naming * convention in order to be selectable with this function. * * The most obvious use (apart for advertisements `:-/`) is to use it for * audible feedback to control commands. E.g. when the user changes the volume, * a short "boing" sound could be played. That would allow the user to perceive * the configured volume, even if currently played song is silent while * configuring the volume. */ int dfplayer_play_from_advert(dfplayer_t *dev, uint16_t number); /** * @brief Stop playing a file from the ADVERT folder and resume previous playback * * @param dev Device descriptor of the DFPlayer to control * * @retval 0 Success * @retval -EINVAL Called with invalid parameters (see precondition) * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out */ static inline int dfplayer_stop_advert(dfplayer_t *dev); /** * @brief Start playing and repeating the specified folder * * @param dev Device descriptor of the DFPlayer to control * @param folder Number of the folder to play and repeat * * @retval 0 Success * @retval -EINVAL Called with invalid parameters (see precondition) * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out * @retval -ENOENT Specified file and/or folder does not exist * * @pre `0 < folder <= 100` and `file > 0` */ static inline int dfplayer_repeat_folder(dfplayer_t *dev, uint8_t folder); /** * @brief Launch shuffle playback of all files * * @param dev Device descriptor of the DFPlayer to control * * @retval 0 Success * @retval -EINVAL Called with invalid parameters (see precondition) * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out * @retval -ENOENT Specified file and/or folder does not exist * * @warning Even files in the `"ADVERT"` folder are played */ static inline int dfplayer_shuffle_all(dfplayer_t *dev); /** * @brief Enable or disable repeat playback * * @param dev Device descriptor of the DFPlayer to control * @param repeat Enable repeat playback? * * @retval 0 Success * @retval -EINVAL Called with invalid parameters (see precondition) * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out * @retval -ENOENT Specified file and/or folder does not exist */ static inline int dfplayer_repeat(dfplayer_t *dev, bool repeat); /** * @brief Query the state of the DFPlayer Mini * * @param dev Device descriptor of the DFPlayer to query * @param state The state will be stored here * * @retval 0 Success * @retval -EINVAL Called with invalid parameters * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out * * @note This function will work best when the busy pin is connected and * and configured, as this can avoid UART communication if the device * is currently playing. (Remember that UART communication results * in audible glitches during playback...) */ int dfplayer_get_state(dfplayer_t *dev, dfplayer_state_t *state); /** * @brief Query the current volume of the DFPlayer Mini * * @param dev Device descriptor of the DFPlayer to query * @param volume The volume will be stored here * * @retval 0 Success * @retval -EINVAL Called with invalid parameters * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out */ static inline int dfplayer_get_volume(dfplayer_t *dev, uint8_t *volume); /** * @brief Query the current equalizer setting of the DFPlayer Mini * * @param dev Device descriptor of the DFPlayer to query * @param equalizer The equalizer setting will be stored here * * @retval 0 Success * @retval -EINVAL Called with invalid parameters * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out */ static inline int dfplayer_get_equalizer(dfplayer_t *dev, dfplayer_eq_t *equalizer); /** * @brief Query the current playback mode of the DFPlayer Mini * * @param dev Device descriptor of the DFPlayer to query * @param mode The playback mode will be stored here * * @retval 0 Success * @retval -EINVAL Called with invalid parameters * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out */ static inline int dfplayer_get_mode(dfplayer_t *dev, dfplayer_mode_t *mode); /** * @brief Query the software version running on the DFPlayer Mini * * @param dev Device descriptor of the DFPlayer to query * @param version The software version will be stored here * * @retval 0 Success * @retval -EINVAL Called with invalid parameters * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out */ static inline int dfplayer_get_version(dfplayer_t *dev, uint16_t *version); /** * @brief Query the number of files on the USB storage device * * @param dev Device descriptor of the DFPlayer to query * @param files The number of files will be stored here * * @retval 0 Success * @retval -EINVAL Called with invalid parameters * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out */ static inline int dfplayer_files_usb(dfplayer_t *dev, uint16_t *files); /** * @brief Query the number of files on the SD card * * @param dev Device descriptor of the DFPlayer to query * @param files The number of files will be stored here * * @retval 0 Success * @retval -EINVAL Called with invalid parameters * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out */ static inline int dfplayer_files_sdcard(dfplayer_t *dev, uint16_t *files); /** * @brief Query the number of files on the NOR flash * * @param dev Device descriptor of the DFPlayer to query * @param files The number of files will be stored here * * @retval 0 Success * @retval -EINVAL Called with invalid parameters * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out */ static inline int dfplayer_files_flash(dfplayer_t *dev, uint16_t *files); /** * @brief Query the selected file on the USB storage device * * @warning The file number refers to the internal file system order * * @param dev Device descriptor of the DFPlayer to query * @param fileno The selected file will be stored here * * @retval 0 Success * @retval -EINVAL Called with invalid parameters * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out */ static inline int dfplayer_get_fileno_usb(dfplayer_t *dev, uint16_t *fileno); /** * @brief Query the selected file on the SD card * * @warning The file number refers to the internal file system order * * @param dev Device descriptor of the DFPlayer to query * @param fileno The selected file will be stored here * * @retval 0 Success * @retval -EINVAL Called with invalid parameters * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out */ static inline int dfplayer_get_fileno_sdcard(dfplayer_t *dev, uint16_t *fileno); /** * @brief Query the selected file on the NOR flash * * @warning The file number refers to the internal file system order * * @param dev Device descriptor of the DFPlayer to query * @param fileno The selected file will be stored here * * @retval 0 Success * @retval -EINVAL Called with invalid parameters * @retval -EIO Communication with the DFPlayer Mini failed * @retval -EAGAIN DFPlayer responded with error "Device busy" * @retval -ETIMEDOUT Response of the DFPlayer timed out */ static inline int dfplayer_get_fileno_flash(dfplayer_t *dev, uint16_t *fileno); /** * @brief Get the currently played file and the used naming scheme * * @param dev Device descriptor of the DFPlayer to query * * @return The currently played file and the used naming scheme */ static inline dfplayer_file_t dfplayer_get_played_file(dfplayer_t *dev); /** * @brief Check if the given source set contains the given source * * @param set Set of sources to check * @param src Source to check for * * @retval 0 @p src is ***NOT*** part of @p set * @retval 1 @p src ***IS*** part of @p set */ static inline int dfplayer_source_set_contains(dfplayer_source_set_t set, dfplayer_source_t src); /** * @brief Add the given source to the given source set * * @param set Set of sources to add source to * @param src Source to add * * This function is idempotent */ static inline void dfplayer_source_set_add(dfplayer_source_set_t *set, dfplayer_source_t src); /** * @brief Remove the given source to the given source set * * @param set Set of sources to remove the source from * @param src Source to remove * * This function is idempotent */ static inline void dfplayer_source_set_rm(dfplayer_source_set_t *set, dfplayer_source_t src); #ifdef __cplusplus } #endif /* Include implementation of the static inline functions */ #include "dfplayer_implementation.h" #endif /* DFPLAYER_H */ /** @} */