1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/shell/cmds/dfplayer.c

625 lines
16 KiB
C

/*
* 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.
*/
/**
* @ingroup sys_shell_commands
* @{
*
* @file
* @brief Provides a shell command to control a DFPlayer Mini
*
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*
* @}
*/
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "dfplayer.h"
#include "dfplayer_internal.h"
#include "fmt.h"
#include "shell.h"
static const char *_equalizers[] = {
[DFPLAYER_EQ_NORMAL] = "normal",
[DFPLAYER_EQ_POP] = "pop",
[DFPLAYER_EQ_ROCK] = "rock",
[DFPLAYER_EQ_JAZZ] = "jazz",
[DFPLAYER_EQ_CLASSIC] = "classic",
[DFPLAYER_EQ_BASE] = "base",
[DFPLAYER_EQ_NUMOF] = NULL
};
static const char *_modes[] = {
[DFPLAYER_MODE_UNKOWN] = "unknown",
[DFPLAYER_MODE_REPEAT_DIR] = "repeat folder",
[DFPLAYER_MODE_REPEAT] = "repeat",
[DFPLAYER_MODE_RANDOM] = "random",
[DFPLAYER_MODE_NORMAL] = "normal",
[DFPLAYER_MODE_NUMOF] = NULL
};
static const char *_states[] = {
[DFPLAYER_STATE_PLAYING] = "playing",
[DFPLAYER_STATE_PAUSED] = "paused",
[DFPLAYER_STATE_STOPPED] = "stopped",
[DFPLAYER_STATE_NUMOF] = NULL
};
static void _print_error(int retval)
{
print_str("Error: ");
#ifdef CONFIG_DFPLAYER_NO_STRERROR
print_s32_dec(retval);
#else
print_str(strerror(-retval));
#endif
print("\n", 1);
}
static void _print_state(dfplayer_t *dev)
{
dfplayer_state_t state;
print_str("State: ");
int retval = dfplayer_get_state(dev, &state);
if (retval) {
_print_error(retval);
}
else {
print_str(_states[state]);
print("\n", 1);
}
}
static void _print_tracks(dfplayer_t *dev)
{
dfplayer_source_set_t srcs = dfplayer_get_sources(dev);
print_str("Selected file numbers (in file system):\n");
if (dfplayer_source_set_contains(srcs, DFPLAYER_SOURCE_USB)) {
uint16_t fileno;
int retval = dfplayer_get_fileno_usb(dev, &fileno);
print_str(" - USB: ");
if (retval) {
_print_error(retval);
}
else {
print_u32_dec(fileno);
print("\n", 1);
}
}
if (dfplayer_source_set_contains(srcs, DFPLAYER_SOURCE_SDCARD)) {
uint16_t fileno;
int retval = dfplayer_get_fileno_sdcard(dev, &fileno);
print_str(" - SD card: ");
if (retval) {
_print_error(retval);
}
else {
print_u32_dec(fileno);
print("\n", 1);
}
}
if (dfplayer_source_set_contains(srcs, DFPLAYER_SOURCE_FLASH)) {
uint16_t fileno;
int retval = dfplayer_get_fileno_sdcard(dev, &fileno);
print_str(" - NOR flash: ");
if (retval) {
_print_error(retval);
}
else {
print_u32_dec(fileno);
print("\n", 1);
}
}
print_str("Current track: ");
dfplayer_file_t file = dfplayer_get_played_file(dev);
if (file.scheme == DFPLAYER_SCHEME_FOLDER_FILE) {
print_u32_dec(file.folder);
print_str("/");
print_u32_dec(file.file);
}
else {
print_u32_dec(file.number);
}
print("\n", 1);
}
static void _print_volume(dfplayer_t *dev)
{
uint8_t volume = 0;
int retval = dfplayer_get_volume(dev, &volume);
print_str("Volume: ");
if (retval) {
_print_error(retval);
}
else {
print_u32_dec(volume);
print("\n", 1);
}
}
static void _print_equalizer(dfplayer_t *dev)
{
dfplayer_eq_t equalizer = 0;
int retval = dfplayer_get_equalizer(dev, &equalizer);
print_str("Equalizer: ");
if (retval) {
_print_error(retval);
}
else {
if ((unsigned)equalizer >= (unsigned)DFPLAYER_EQ_NUMOF) {
print_str("Invalid response!?!\n");
}
else {
print_str(_equalizers[equalizer]);
print("\n", 1);
}
}
}
static void _print_mode(dfplayer_t *dev)
{
dfplayer_mode_t mode = {0};
int retval = dfplayer_get_mode(dev, &mode);
if (retval) {
_print_error(retval);
}
else {
print_str("Playback mode: ");
print_str(_modes[mode]);
print("\n", 1);
}
}
static void _print_files(dfplayer_t *dev)
{
dfplayer_source_set_t srcs = dfplayer_get_sources(dev);
uint16_t files;
int retval;
print_str("USB: ");
if (dfplayer_source_set_contains(srcs, DFPLAYER_SOURCE_USB)) {
retval = dfplayer_files_usb(dev, &files);
if (retval) {
_print_error(retval);
}
else {
print_u32_dec(files);
print("\n", 1);
}
}
else {
print_str("Not present\n");
}
print_str("SD card: ");
if (dfplayer_source_set_contains(srcs, DFPLAYER_SOURCE_SDCARD)) {
retval = dfplayer_files_sdcard(dev, &files);
if (retval) {
_print_error(retval);
}
else {
print_u32_dec(files);
print("\n", 1);
}
}
else {
print_str("Not present\n");
}
print_str("Flash: ");
if (dfplayer_source_set_contains(srcs, DFPLAYER_SOURCE_FLASH)) {
retval = dfplayer_files_flash(dev, &files);
if (retval) {
_print_error(retval);
}
else {
print_u32_dec(files);
print("\n", 1);
}
}
else {
print_str("Not present\n");
}
}
static void _print_status(dfplayer_t *dev)
{
uint16_t version;
int retval;
print_str("Software version: ");
retval = dfplayer_get_version(dev, &version);
if (retval) {
_print_error(retval);
}
else {
print_u32_dec(version);
print("\n", 1);
}
_print_state(dev);
_print_volume(dev);
_print_tracks(dev);
_print_mode(dev);
_print_files(dev);
}
static void _print_usage(const char *progname)
{
print_str("Usage: ");
print_str(progname);
print_str(" [-d <DEV_NUM>] [CMD [PARAMS]]\n");
}
static void _print_help(const char *progname)
{
_print_usage(progname);
print_str("Run ");
print_str(progname);
print_str(" without command to query the current status\n");
print_str(
"\n"
"Commands:\n"
" play Start playback\n"
" pause Pause playing\n"
" next Start playing next song\n"
" prev Start playing previous song\n"
" track Print the currently played track\n"
" track <VAL> Select track with number <VAL>\n"
" files Print the number of files present\n"
" file <DIR> <FILE> Play file number <FILE> in folder <DIR>\n"
" (E.g. \"09/042.mp3\" is selected with \""
);
print_str(progname);
print_str(" file 9 42\")\n");
print_str(
" volume Print current volume\n"
" volume <VAL> Set volume to <VAL> (0 - 30)\n"
" source <VAL> Set source to <VAL> (USB, SD, FLASH)\n"
" equalizer Print current equalizer setting\n"
" equalizer <VAL> Set equalizer to <VAL>\n"
" mode Print the current playback mode\n"
" repeat <1 / 0> Enable (1) or disable (0) repeat\n"
" repeat-folder <VAL> Play and repeat folder number <VAL>\n"
" state Print the DFPlayer's state\n"
" shuffle Play all files at random\n"
" mp3 <VAL> Play file number <VAL> from \"MP3\" folder\n"
" advert <VAL> Play file number <VAL> from \"ADVERT\" folder\n"
" (Only works during playback, previous playback\n"
" is resumed afterwards)\n"
" stop-advert During advert, resume previous playback now\n"
" cmd <CMD> [[P1] P2] Run command <CMD> with parameters P1 and P2\n"
);
}
static int _sc_dfplayer(int argc, char **argv)
{
unsigned dev_num = 0;
int pos = 1;
dfplayer_t *dev;
if ((argc > 1) && (!strcmp("-d", argv[1]))) {
if (argc < 3) {
print_str("Missing device number for parameter \"-d\"\n\n");
_print_usage(argv[0]);
return 1;
}
dev_num = atoi(argv[2]);
pos = 3;
}
dev = dfplayer_get(dev_num);
if (!dev) {
print_str("Error: No DFPlayer Mini device with number ");
print_u32_dec(dev_num);
print("\n", 1);
return 1;
}
if (argc == pos) {
_print_status(dev);
return 0;
}
if (!strcmp("play", argv[pos])) {
int retval = dfplayer_play(dev);
if (retval) {
_print_error(retval);
return 1;
}
return 0;
}
if (!strcmp("pause", argv[pos])) {
int retval = dfplayer_pause(dev);
if (retval) {
_print_error(retval);
return 1;
}
return 0;
}
if (!strcmp("next", argv[pos])) {
int retval = dfplayer_next(dev);
if (retval) {
_print_error(retval);
return 1;
}
return 0;
}
if (!strcmp("prev", argv[pos])) {
int retval = dfplayer_prev(dev);
if (retval) {
_print_error(retval);
return 1;
}
return 0;
}
if (!strcmp("track", argv[pos])) {
_print_tracks(dev);
return 0;
}
if (!strcmp("files", argv[pos])) {
if ((pos + 1) != argc) {
print_str("Error: Expected no parameter for argument \"files\"\n");
return 1;
}
_print_files(dev);
return 0;
}
if (!strcmp("file", argv[pos])) {
if (pos + 2 >= argc) {
print_str("Error: Missing folder / file number\n\n");
_print_help(argv[0]);
return 1;
}
uint8_t folder = atoi(argv[++pos]);
uint8_t file = atoi(argv[++pos]);
int retval = dfplayer_play_file(dev, folder, file);
if (retval) {
_print_error(retval);
return 1;
}
return 0;
}
if (!strcmp("volume", argv[pos])) {
if (argc == ++pos) {
_print_volume(dev);
}
else {
uint8_t volume = atoi(argv[pos]);
int retval = dfplayer_set_volume(dev, volume);
if (retval) {
_print_error(retval);
return -1;
}
}
return 0;
}
if (!strcmp("source", argv[pos])) {
if (argc < ++pos) {
print_str("Error: Missing argument for command \"source\"\n\n");
_print_help(argv[0]);
return 1;
}
dfplayer_source_t src;
if (!strcmp("usb", argv[pos]) || !strcmp("USB", argv[pos])) {
src = DFPLAYER_SOURCE_USB;
}
else if (!strcmp("sd", argv[pos]) || !strcmp("SD", argv[pos])) {
src = DFPLAYER_SOURCE_SDCARD;
}
else if (!strcmp("flash", argv[pos]) || !strcmp("FLASH", argv[pos])) {
src = DFPLAYER_SOURCE_FLASH;
}
else {
print_str("Error: Unknown source type. (Valid: USB, SD, FLASH)\n");
return 1;
}
dfplayer_source_set_t srcs = dfplayer_get_sources(dev);
if (!dfplayer_source_set_contains(srcs, src)) {
print_str("Error: Specified playback source not connected\n");
return 1;
}
int retval = dfplayer_set_source(dev, src);
if (retval) {
_print_error(retval);
return 1;
}
return 0;
}
if (!strcmp("equalizer", argv[pos])) {
if (++pos == argc) {
_print_equalizer(dev);
}
else {
dfplayer_eq_t eq = DFPLAYER_EQ_NUMOF;
for (unsigned i = 0; _equalizers[i] != NULL; i++) {
if (!strcmp(_equalizers[i], argv[pos])) {
eq = (dfplayer_eq_t)i;
break;
}
}
if (eq == DFPLAYER_EQ_NUMOF) {
print_str("Error: Unknown equalizer\n");
return 1;
}
int retval = dfplayer_set_equalizer(dev, eq);
if (retval) {
_print_error(retval);
return 1;
}
}
return 0;
}
if (!strcmp("mode", argv[pos])) {
_print_mode(dev);
return 0;
}
if (!strcmp("repeat", argv[pos])) {
if (++pos == argc) {
print_str("Error: Missing parameter for command \"repeat\"\n");
return 1;
}
else {
bool repeat = (atoi(argv[pos])) ? true : false;
int retval = dfplayer_repeat(dev, repeat);
if (retval) {
_print_error(retval);
return 1;
}
}
return 0;
}
if (!strcmp("repeat-folder", argv[pos])) {
if (++pos == argc) {
print_str("Error: Missing argument for command \"repeat\"\n");
return 1;
}
uint8_t folder = atoi(argv[pos]);
int retval = dfplayer_repeat_folder(dev, folder);
if (retval) {
_print_error(retval);
return 1;
}
return 0;
}
if (!strcmp("state", argv[pos])) {
_print_state(dev);
return 0;
}
if (!strcmp("shuffle", argv[pos])) {
int retval = dfplayer_shuffle_all(dev);
if (retval) {
_print_error(retval);
return 1;
}
return 0;
}
if (!strcmp("mp3", argv[pos])) {
if (++pos == argc) {
print_str("Error: Missing parameter for command \"mp3\"\n");
return 1;
}
uint16_t file = atoi(argv[pos]);
int retval = dfplayer_play_from_mp3(dev, file);
if (retval) {
_print_error(retval);
return 1;
}
return 0;
}
if (!strcmp("advert", argv[pos])) {
if (++pos == argc) {
print_str("Error: Missing parameter for command \"advert\"\n");
return 1;
}
uint16_t file = atoi(argv[pos]);
int retval = dfplayer_play_from_advert(dev, file);
if (retval) {
_print_error(retval);
return 1;
}
return 0;
}
if (!strcmp("stop-advert", argv[pos])) {
int retval = dfplayer_stop_advert(dev);
if (retval) {
_print_error(retval);
return 1;
}
return 0;
}
if (!strcmp("cmd", argv[pos])) {
uint8_t cmd, p1, p2;
uint16_t resp;
p1 = p2 = 0;
if (++pos == argc) {
print_str("Error: Missing <CMD> for command \"cmd\"\n");
}
cmd = (uint8_t)scn_u32_hex(argv[pos], 2);
if (++pos < argc) {
p2 = (uint8_t)scn_u32_hex(argv[pos], 2);
}
if (++pos < argc) {
p1 = p2;
p2 = (uint8_t)scn_u32_hex(argv[pos], 2);
}
print_str("Sending cmd = 0x");
print_u32_hex(cmd);
print_str(" with params = 0x");
print_u32_hex(p1);
print_str(", 0x");
print_u32_hex(p2);
print_str(": ");
int retval = dfplayer_transceive(dev, &resp, cmd, p1, p2);
if (retval) {
_print_error(retval);
return 1;
}
else {
print_str("Response = 0x");
print_u32_hex(resp);
print("\n", 1);
}
return 0;
}
if (strcmp("-h", argv[pos]) && strcmp("--help", argv[pos])) {
print_str("Failed to parse command \"");
print_str(argv[pos]);
print_str("\"\n");
}
_print_help(argv[0]);
return 1;
}
SHELL_COMMAND(dfplayer, "Control a DFPlayer Mini MP3 player", _sc_dfplayer);