#![no_std]
use embedded_hal_async::delay::DelayNs;
use embedded_io_async::{Read, ReadReady, Write};
#[cfg(feature = "defmt")]
use defmt::{Debug2Format, info};
const START_BYTE: u8 = 0x7E;
const END_BYTE: u8 = 0xEF;
const VERSION: u8 = 0xFF;
const MSG_LEN: u8 = 0x06;
const DATA_FRAME_SIZE: usize = 10;
const INDEX_VERSION: usize = 1;
const INDEX_CMD: usize = 3;
const INDEX_FEEDBACK_ENABLE: usize = 4;
const INDEX_PARAM_H: usize = 5;
const INDEX_PARAM_L: usize = 6;
const INDEX_CHECKSUM_H: usize = 7;
const INDEX_CHECKSUM_L: usize = 8;
pub trait TimeSource {
type Instant: Copy + Clone + PartialEq + PartialOrd;
fn now(&self) -> Self::Instant;
fn is_elapsed(&self, since: Self::Instant, timeout_ms: u64) -> bool;
}
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Source {
USBFlash = 0b001,
SDCard = 0b010,
USBHost = 0b100,
}
impl TryFrom<u8> for Source {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0b001 => Ok(Source::USBFlash),
0b010 => Ok(Source::SDCard),
0b100 => Ok(Source::USBHost),
_ => Err(()),
}
}
}
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ModuleError {
Busy = 1,
Sleeping = 2,
SerialRxError = 3,
Checksum = 4,
TrackNotInScope = 5,
TrackNotFound = 6,
InsertionError = 7,
EnterSleep = 8,
}
impl TryFrom<u8> for ModuleError {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
1 => Ok(ModuleError::Busy),
2 => Ok(ModuleError::Sleeping),
3 => Ok(ModuleError::SerialRxError),
4 => Ok(ModuleError::Checksum),
5 => Ok(ModuleError::TrackNotInScope),
6 => Ok(ModuleError::TrackNotFound),
7 => Ok(ModuleError::InsertionError),
8 => Ok(ModuleError::EnterSleep),
_ => Err(()),
}
}
}
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error<SerialError> {
Init,
SerialPort(SerialError),
DelayError,
FailedAck,
Connection,
ModuleError(ModuleError),
Unknown,
BrokenMessage,
UserTimeout,
BadParameter,
}
#[derive(PartialEq, Debug, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct MessageData {
command: Command,
param_h: u8,
param_l: u8,
}
impl MessageData {
pub const fn new(command: Command, param_h: u8, param_l: u8) -> Self {
Self {
command,
param_h,
param_l,
}
}
}
const ACK_MESSAGE_DATA: MessageData =
MessageData::new(Command::NotifyReply, 0, 0);
#[repr(u8)]
#[derive(PartialEq, Debug, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Command {
Next = 0x01,
Previous = 0x02,
PlayTrack = 0x03,
VolumeUp = 0x04,
VolumeDown = 0x05,
SetVolume = 0x06,
SetEQ = 0x07,
PlayLoopTrack = 0x08,
SetPlaybackSource = 0x09,
EnterSleepMode = 0x0A,
EnterNormalMode = 0x0B,
Reset = 0x0C,
Play = 0x0D,
Pause = 0x0E,
PlayTrackInFolder = 0x0F,
ConfigAudioAmp = 0x10,
PlayLoopAll = 0x11,
PlayTrackInMp3Folder = 0x12,
StartAdvertisement = 0x13,
PlayTrackLargeFolder = 0x14,
StopAdvertisement = 0x15,
Stop = 0x16,
PlayLoopFolder = 0x17,
PlayRandom = 0x18,
LoopCurrentTrack = 0x19,
SetDAC = 0x1a,
NotifyPushMedia = 0x3A,
NotifyPullOutMedia = 0x3B,
NotifyFinishTrackUSBFlash = 0x3C,
NotifyFinishTrackSD = 0x3D,
NotifyFinishTrackUSBHost = 0x3E,
QueryAvailableSources = 0x3F,
NotifyError = 0x40,
NotifyReply = 0x41,
QueryStatus = 0x42,
QueryVolume = 0x43,
QueryEQ = 0x44,
ReservedQueryPlaybackMode = 0x45,
ReservedQuerySwVersion = 0x46,
QueryTrackCntUSB = 0x47,
QueryTrackCntSD = 0x48,
ReservedQueryTrackCntPC = 0x49,
ReservedQueryKeepOn = 0x4A,
QueryCurrentTrackUSBFlash = 0x4B,
QueryCurrentTrackSD = 0x4C,
QueryCurrentTrackUSBHost = 0x4D,
QueryFolderTrackCnt = 0x4E,
QueryFolderCnt = 0x4F,
}
impl TryFrom<u8> for Command {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0x01 => Ok(Command::Next),
0x02 => Ok(Command::Previous),
0x03 => Ok(Command::PlayTrack),
0x04 => Ok(Command::VolumeUp),
0x05 => Ok(Command::VolumeDown),
0x06 => Ok(Command::SetVolume),
0x07 => Ok(Command::SetEQ),
0x08 => Ok(Command::PlayLoopTrack),
0x09 => Ok(Command::SetPlaybackSource),
0x0A => Ok(Command::EnterSleepMode),
0x0B => Ok(Command::EnterNormalMode),
0x0C => Ok(Command::Reset),
0x0D => Ok(Command::Play),
0x0E => Ok(Command::Pause),
0x0F => Ok(Command::PlayTrackInFolder),
0x10 => Ok(Command::ConfigAudioAmp),
0x11 => Ok(Command::PlayLoopAll),
0x12 => Ok(Command::PlayTrackInMp3Folder),
0x13 => Ok(Command::StartAdvertisement),
0x14 => Ok(Command::PlayTrackLargeFolder),
0x15 => Ok(Command::StopAdvertisement),
0x16 => Ok(Command::Stop),
0x17 => Ok(Command::PlayLoopFolder),
0x18 => Ok(Command::PlayRandom),
0x19 => Ok(Command::LoopCurrentTrack),
0x1A => Ok(Command::SetDAC),
0x3A => Ok(Command::NotifyPushMedia),
0x3B => Ok(Command::NotifyPullOutMedia),
0x3C => Ok(Command::NotifyFinishTrackUSBFlash),
0x3D => Ok(Command::NotifyFinishTrackSD),
0x3E => Ok(Command::NotifyFinishTrackUSBHost),
0x3F => Ok(Command::QueryAvailableSources),
0x40 => Ok(Command::NotifyError),
0x41 => Ok(Command::NotifyReply),
0x42 => Ok(Command::QueryStatus),
0x43 => Ok(Command::QueryVolume),
0x44 => Ok(Command::QueryEQ),
0x45 => Ok(Command::ReservedQueryPlaybackMode),
0x46 => Ok(Command::ReservedQuerySwVersion),
0x47 => Ok(Command::QueryTrackCntUSB),
0x48 => Ok(Command::QueryTrackCntSD),
0x49 => Ok(Command::ReservedQueryTrackCntPC),
0x4A => Ok(Command::ReservedQueryKeepOn),
0x4B => Ok(Command::QueryCurrentTrackUSBFlash),
0x4C => Ok(Command::QueryCurrentTrackSD),
0x4D => Ok(Command::QueryCurrentTrackUSBHost),
0x4E => Ok(Command::QueryFolderTrackCnt),
0x4F => Ok(Command::QueryFolderCnt),
_ => Err(()),
}
}
}
#[repr(u8)]
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Equalizer {
Normal = 0x0,
Pop = 0x1,
Rock = 0x2,
Jazz = 0x3,
Classic = 0x4,
Bass = 0x5,
}
#[repr(u8)]
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum PlayBackMode {
Repeat = 0x0,
FolderRepeat = 0x1,
SingleRepeat = 0x2,
Random = 0x3,
}
#[repr(u8)]
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum PlayBackSource {
USB = 0x0,
SDCard = 0x1,
Aux = 0x2,
Sleep = 0x3,
Flash = 0x4,
}
pub fn checksum(buffer: &[u8]) -> u16 {
let mut checksum = 0;
for &b in buffer {
checksum += u16::from(b);
}
if buffer[2] == 0x0 {
checksum += 2
};
0u16.wrapping_sub(checksum)
}
pub struct DfPlayer<'a, S, T, D>
where
S: Read + Write + ReadReady,
T: TimeSource,
D: DelayNs,
{
port: &'a mut S,
feedback_enable: bool,
last_command: MessageData,
last_response: MessageData,
last_cmd_acknowledged: bool,
timeout_ms: u64,
time_source: T,
delay: D,
}
impl<'a, S, T, D> DfPlayer<'a, S, T, D>
where
S: Read + Write + ReadReady,
T: TimeSource,
D: DelayNs,
{
pub async fn new(
port: &'a mut S,
feedback_enable: bool,
timeout_ms: u64,
time_source: T,
delay: D,
reset_duration_override: Option<u64>,
) -> Result<Self, Error<S::Error>> {
#[cfg(feature = "defmt")]
info!("=== DfPlayer::new starting ===");
let mut player = Self {
port,
feedback_enable,
last_command: MessageData::new(Command::EnterNormalMode, 0, 0),
last_response: MessageData::new(Command::EnterNormalMode, 0, 0),
last_cmd_acknowledged: false,
timeout_ms,
time_source,
delay,
};
#[cfg(feature = "defmt")]
info!("Clearing initial receive buffer");
let _ = player.clear_receive_buffer().await;
#[cfg(feature = "defmt")]
info!("Initial buffer clear completed");
#[cfg(feature = "defmt")]
info!("About to send reset command");
let original_timeout = player.timeout_ms;
player.timeout_ms = 2000;
#[cfg(feature = "defmt")]
info!("Calling send_command_init for reset");
let _reset_result = player
.send_command_init(MessageData::new(Command::Reset, 0, 0))
.await;
#[cfg(feature = "defmt")]
info!("Reset command send_command_init completed");
let wait_ms = reset_duration_override.unwrap_or(1500);
#[cfg(feature = "defmt")]
info!("Waiting {}ms for device reset", wait_ms);
player.delay.delay_ms(wait_ms as u32).await;
#[cfg(feature = "defmt")]
info!("Reset delay completed");
#[cfg(feature = "defmt")]
info!("Clearing buffer after reset");
let _ = player.clear_receive_buffer().await;
#[cfg(feature = "defmt")]
info!("Post-reset buffer clear completed");
player.timeout_ms = original_timeout;
if let Err(_e) = _reset_result {
#[cfg(feature = "defmt")]
info!("Reset error: {:?} - continuing anyway", Debug2Format(&_e));
}
#[cfg(feature = "defmt")]
info!("About to set playback source to SD card");
#[cfg(feature = "defmt")]
info!("Calling send_command_init for playback source");
let _source_result = player
.send_command_init(MessageData::new(
Command::SetPlaybackSource,
0,
PlayBackSource::SDCard as u8,
))
.await;
#[cfg(feature = "defmt")]
info!("Playback source command completed");
if let Err(_e) = _source_result {
#[cfg(feature = "defmt")]
info!(
"Source select warning: {:?} - continuing anyway",
Debug2Format(&_e)
);
}
#[cfg(feature = "defmt")]
info!("Adding 200ms delay after source selection");
player.delay.delay_ms(200).await;
#[cfg(feature = "defmt")]
info!("Source selection delay completed");
#[cfg(feature = "defmt")]
info!("About to set initial volume");
#[cfg(feature = "defmt")]
info!("Calling send_command_init for volume");
let _vol_result = player
.send_command_init(MessageData::new(Command::SetVolume, 0, 15))
.await;
#[cfg(feature = "defmt")]
info!("Volume command completed");
if let Err(_e) = _vol_result {
#[cfg(feature = "defmt")]
info!(
"Volume set warning: {:?} - continuing anyway",
Debug2Format(&_e)
);
}
#[cfg(feature = "defmt")]
info!("=== DFPlayer initialization complete - SUCCESS! ===");
Ok(player)
}
pub async fn read_last_message(&mut self) -> Result<(), Error<S::Error>> {
let timeout_start = self.time_source.now();
let mut current_index = 0;
let mut message = [0u8; DATA_FRAME_SIZE];
let mut receive_buffer = [0u8; 32];
while !self.time_source.is_elapsed(timeout_start, self.timeout_ms) {
let bytes_read = match self.port.read_ready() {
Ok(true) => match self.port.read(&mut receive_buffer).await {
Ok(n) => n,
Err(_e) => {
#[cfg(feature = "defmt")]
info!(
"Read error, will retry: {:?}",
Debug2Format(&_e)
);
self.delay.delay_ms(10).await;
continue;
}
},
_ => {
match self.port.read(&mut receive_buffer).await {
Ok(n) => {
if n == 0 {
self.delay.delay_ms(10).await;
continue;
}
n
}
Err(_e) => {
#[cfg(feature = "defmt")]
info!("Read error: {:?}", Debug2Format(&_e));
self.delay.delay_ms(10).await;
continue;
}
}
}
};
#[cfg(feature = "defmt")]
if bytes_read > 0 {
info!(
"Read {} bytes: {:?}",
bytes_read,
&receive_buffer[..bytes_read]
);
}
if bytes_read == 8 && receive_buffer[0] == 0x06 {
let cmd_byte = receive_buffer[1];
if let Ok(cmd) = Command::try_from(cmd_byte) {
self.last_response.command = cmd;
self.last_response.param_h = receive_buffer[3];
self.last_response.param_l = receive_buffer[4];
#[cfg(feature = "defmt")]
info!(
"Parsed 8-byte response: cmd={:?}, params={},{}",
cmd,
self.last_response.param_h,
self.last_response.param_l
);
return Ok(());
}
}
for i in 0..bytes_read {
let byte = receive_buffer[i];
match current_index {
0 => {
if byte == START_BYTE {
message[current_index] = byte;
current_index = 1;
}
}
9 => {
message[current_index] = byte;
if byte == END_BYTE {
#[cfg(feature = "defmt")]
info!("Complete message: {:?}", message);
let read_checksum = ((message[7] as u16) << 8)
| (message[8] as u16);
let calc_checksum = checksum(&message[1..7]);
if read_checksum == calc_checksum {
if let Ok(cmd) = Command::try_from(message[3]) {
self.last_response.command = cmd;
self.last_response.param_h = message[5];
self.last_response.param_l = message[6];
if self.last_response == ACK_MESSAGE_DATA {
self.last_cmd_acknowledged = true;
}
if self.last_response.command
== Command::NotifyError
{
if let Ok(err) = ModuleError::try_from(
self.last_response.param_l,
) {
return Err(Error::ModuleError(
err,
));
} else {
return Err(Error::Unknown);
}
}
return Ok(());
}
} else {
#[cfg(feature = "defmt")]
info!(
"Checksum mismatch: expected {:04X}, got {:04X}",
calc_checksum, read_checksum
);
}
}
current_index = 0;
}
_ => {
message[current_index] = byte;
current_index += 1;
}
}
}
}
#[cfg(feature = "defmt")]
info!("Timeout waiting for response");
if self.last_command.command == Command::Reset {
#[cfg(feature = "defmt")]
info!("Ignoring timeout for reset command");
return Ok(());
}
Err(Error::UserTimeout)
}
async fn send_command_init(
&mut self,
command_data: MessageData,
) -> Result<(), Error<S::Error>> {
let mut out_buffer = [
START_BYTE, VERSION, MSG_LEN, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
END_BYTE,
];
if self.feedback_enable {
out_buffer[INDEX_FEEDBACK_ENABLE] = 0x1;
}
out_buffer[INDEX_CMD] = command_data.command as u8;
out_buffer[INDEX_PARAM_H] = command_data.param_h;
out_buffer[INDEX_PARAM_L] = command_data.param_l;
let checksum = checksum(&out_buffer[INDEX_VERSION..INDEX_CHECKSUM_H]);
out_buffer[INDEX_CHECKSUM_H] = (checksum >> 8) as u8;
out_buffer[INDEX_CHECKSUM_L] = checksum as u8;
#[cfg(feature = "defmt")]
info!("tx {}", out_buffer);
self.port
.write_all(&out_buffer)
.await
.map_err(Error::SerialPort)?;
self.last_command = command_data;
self.last_cmd_acknowledged = false;
if !self.feedback_enable {
#[cfg(feature = "defmt")]
info!(
"Skipping response wait during initialization (feedback disabled)"
);
self.delay.delay_ms(50).await;
return Ok(());
}
let original_timeout = self.timeout_ms;
self.timeout_ms = 200;
let result = self.read_last_message().await;
self.timeout_ms = original_timeout;
match result {
Ok(_) => {
#[cfg(feature = "defmt")]
info!("Initialization command received response");
}
Err(Error::UserTimeout) => {
#[cfg(feature = "defmt")]
info!("Initialization command timed out (continuing anyway)");
}
Err(_e) => {
#[cfg(feature = "defmt")]
info!("Initialization command error: {:?}", Debug2Format(&_e));
}
}
Ok(())
}
pub async fn send_command(
&mut self,
command_data: MessageData,
) -> Result<(), Error<S::Error>> {
let mut out_buffer = [
START_BYTE, VERSION, MSG_LEN, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
END_BYTE,
];
if self.feedback_enable {
out_buffer[INDEX_FEEDBACK_ENABLE] = 0x1;
}
out_buffer[INDEX_CMD] = command_data.command as u8;
out_buffer[INDEX_PARAM_H] = command_data.param_h;
out_buffer[INDEX_PARAM_L] = command_data.param_l;
let checksum = checksum(&out_buffer[INDEX_VERSION..INDEX_CHECKSUM_H]);
out_buffer[INDEX_CHECKSUM_H] = (checksum >> 8) as u8;
out_buffer[INDEX_CHECKSUM_L] = checksum as u8;
#[cfg(feature = "defmt")]
info!("tx {}", out_buffer);
self.port
.write_all(&out_buffer)
.await
.map_err(Error::SerialPort)?;
self.last_command = command_data;
self.last_cmd_acknowledged = false;
let is_query_command = matches!(
command_data.command,
Command::QueryTrackCntSD
| Command::QueryVolume
| Command::QueryEQ
| Command::QueryAvailableSources
| Command::QueryStatus
| Command::QueryTrackCntUSB
| Command::QueryCurrentTrackUSBFlash
| Command::QueryCurrentTrackSD
| Command::QueryCurrentTrackUSBHost
| Command::QueryFolderTrackCnt
| Command::QueryFolderCnt
);
if self.feedback_enable {
match self.read_last_message().await {
Ok(_) if self.last_cmd_acknowledged => {
if is_query_command {
#[cfg(feature = "defmt")]
info!("Reading data response after ACK for query");
self.delay.delay_ms(20).await;
match self.read_last_message().await {
Ok(_) => {
#[cfg(feature = "defmt")]
info!("Received data response for query");
}
Err(e) => {
#[cfg(feature = "defmt")]
info!(
"Error reading data response: {:?}",
Debug2Format(&e)
);
return Err(e);
}
}
}
}
Ok(_) => {
if command_data.command != Command::Reset {
#[cfg(feature = "defmt")]
info!("Expected ACK not received");
return Err(Error::FailedAck);
}
}
Err(e) => return Err(e),
}
} else {
if is_query_command {
self.delay.delay_ms(100).await;
let mut attempts = 0;
let max_attempts = 3;
while attempts < max_attempts {
attempts += 1;
let mut buffer = [0u8; 32]; let bytes_read = match self.port.read(&mut buffer).await {
Ok(n) => n,
Err(e) => {
#[cfg(feature = "defmt")]
info!("Read error: {:?}", Debug2Format(&e));
if attempts == max_attempts {
return Err(Error::SerialPort(e));
}
self.delay.delay_ms(50).await;
continue;
}
};
#[cfg(feature = "defmt")]
if bytes_read > 0 {
info!(
"Response (attempt {}): {:?}",
attempts,
&buffer[..bytes_read]
);
}
if bytes_read >= DATA_FRAME_SIZE
&& buffer[0] == START_BYTE
&& buffer[DATA_FRAME_SIZE - 1] == END_BYTE
{
if let Ok(cmd) = Command::try_from(buffer[INDEX_CMD]) {
self.last_response.command = cmd;
self.last_response.param_h = buffer[INDEX_PARAM_H];
self.last_response.param_l = buffer[INDEX_PARAM_L];
if command_data.command == Command::QueryTrackCntSD
{
#[cfg(feature = "defmt")]
info!(
"Got response for track count query: {:?}, value={}",
cmd, buffer[INDEX_PARAM_L]
);
return Ok(());
}
if cmd == command_data.command {
#[cfg(feature = "defmt")]
info!(
"Got matching response: {:?}, value={}",
cmd, buffer[INDEX_PARAM_L]
);
return Ok(());
} else {
#[cfg(feature = "defmt")]
info!(
"Response command mismatch: expected {:?}, got {:?}",
command_data.command, cmd
);
}
}
}
if attempts < max_attempts {
self.delay.delay_ms(50).await;
}
}
if command_data.command == Command::QueryTrackCntSD {
#[cfg(feature = "defmt")]
info!(
"No immediate track count response, will check for delayed response"
);
return Ok(());
}
#[cfg(feature = "defmt")]
info!(
"Failed to get proper response after {} attempts",
max_attempts
);
return Err(Error::BrokenMessage);
} else {
}
}
Ok(())
}
async fn clear_receive_buffer(&mut self) -> Result<(), Error<S::Error>> {
#[cfg(feature = "defmt")]
info!("clear_receive_buffer: Starting buffer clear");
let mut buffer = [0u8; 32];
#[cfg(feature = "defmt")]
info!("clear_receive_buffer: Checking if data is available");
let has_data = match self.port.read_ready() {
Ok(true) => {
#[cfg(feature = "defmt")]
info!("clear_receive_buffer: Data is available, reading");
true
}
_ => {
#[cfg(feature = "defmt")]
info!("clear_receive_buffer: No data available");
false
}
};
if has_data {
match self.port.read(&mut buffer).await {
Ok(0) => {
#[cfg(feature = "defmt")]
info!("clear_receive_buffer: Read returned 0 bytes");
}
Ok(_n) => {
#[cfg(feature = "defmt")]
info!("Cleared {} bytes: {:?}", _n, &buffer[.._n]);
}
Err(_e) => {
#[cfg(feature = "defmt")]
info!(
"clear_receive_buffer: Read error: {:?}",
Debug2Format(&_e)
);
}
}
}
#[cfg(feature = "defmt")]
info!("clear_receive_buffer: Completed successfully");
Ok(())
}
pub async fn next(&mut self) -> Result<(), Error<S::Error>> {
self.send_command(MessageData::new(Command::Next, 0, 0))
.await
}
pub async fn reset(
&mut self,
reset_duration_override: Option<u64>,
) -> Result<(), Error<S::Error>> {
self.send_command(MessageData::new(Command::Reset, 0, 0))
.await?;
let wait_ms = reset_duration_override.unwrap_or(1500); self.delay.delay_ms(wait_ms as u32).await;
let _ = self.read_last_message().await;
Ok(())
}
pub async fn set_playback_source(
&mut self,
playback_source: PlayBackSource,
) -> Result<(), Error<S::Error>> {
let cmd_result = self
.send_command(MessageData::new(
Command::SetPlaybackSource,
0,
playback_source as u8,
))
.await;
self.delay.delay_ms(200).await;
cmd_result
}
pub async fn set_volume(
&mut self,
volume: u8,
) -> Result<(), Error<S::Error>> {
if volume > 30 {
return Err(Error::BadParameter);
}
self.send_command(MessageData::new(Command::SetVolume, 0, volume))
.await
}
pub async fn play(&mut self, track: u16) -> Result<(), Error<S::Error>> {
if track > 2999 {
return Err(Error::BadParameter);
}
self.send_command(MessageData::new(
Command::PlayTrack,
(track >> 8) as u8,
track as u8,
))
.await
}
pub async fn set_equalizer(
&mut self,
equalizer: Equalizer,
) -> Result<(), Error<S::Error>> {
self.send_command(MessageData::new(Command::SetEQ, 0, equalizer as u8))
.await
}
pub async fn set_loop_all(
&mut self,
enable: bool,
) -> Result<(), Error<S::Error>> {
self.send_command(MessageData::new(
Command::PlayLoopAll,
0,
if enable { 1 } else { 0 },
))
.await
}
pub async fn pause(&mut self) -> Result<(), Error<S::Error>> {
self.send_command(MessageData::new(Command::Pause, 0, 0))
.await
}
pub async fn resume(&mut self) -> Result<(), Error<S::Error>> {
self.send_command(MessageData::new(Command::Play, 0, 0))
.await
}
pub async fn previous(&mut self) -> Result<(), Error<S::Error>> {
self.send_command(MessageData::new(Command::Previous, 0, 0))
.await
}
pub async fn stop(&mut self) -> Result<(), Error<S::Error>> {
self.send_command(MessageData::new(Command::Stop, 0, 0))
.await
}
pub async fn play_from_folder(
&mut self,
folder: u8,
track: u8,
) -> Result<(), Error<S::Error>> {
if folder == 0 || folder > 99 || track == 0 {
return Err(Error::BadParameter);
}
self.send_command(MessageData::new(
Command::PlayTrackInFolder,
folder,
track,
))
.await
}
pub async fn play_loop_folder(
&mut self,
folder: u8,
) -> Result<(), Error<S::Error>> {
if folder == 0 || folder > 99 {
return Err(Error::BadParameter);
}
self.send_command(MessageData::new(Command::PlayLoopFolder, 0, folder))
.await
}
pub async fn play_random(&mut self) -> Result<(), Error<S::Error>> {
self.send_command(MessageData::new(Command::PlayRandom, 0, 0))
.await
}
pub async fn set_loop_current_track(
&mut self,
enable: bool,
) -> Result<(), Error<S::Error>> {
self.send_command(MessageData::new(
Command::LoopCurrentTrack,
0,
if enable { 1 } else { 0 },
))
.await
}
pub async fn query_tracks_sd(&mut self) -> Result<u16, Error<S::Error>> {
self.send_command(MessageData::new(Command::QueryTrackCntSD, 0, 0))
.await?;
Ok(self.last_response.param_l as u16)
}
pub async fn query_tracks_folder(
&mut self,
folder: u8,
) -> Result<u16, Error<S::Error>> {
self.send_command(MessageData::new(
Command::QueryFolderTrackCnt,
0,
folder,
))
.await?;
Ok(self.last_response.param_l as u16)
}
pub async fn query_current_track_sd(
&mut self,
) -> Result<u16, Error<S::Error>> {
self.send_command(MessageData::new(Command::QueryCurrentTrackSD, 0, 0))
.await?;
Ok(((self.last_response.param_h as u16) << 8)
| self.last_response.param_l as u16)
}
pub async fn query_volume(&mut self) -> Result<u8, Error<S::Error>> {
self.send_command(MessageData::new(Command::QueryVolume, 0, 0))
.await?;
Ok(self.last_response.param_l)
}
pub async fn query_eq(&mut self) -> Result<u8, Error<S::Error>> {
self.send_command(MessageData::new(Command::QueryEQ, 0, 0))
.await?;
Ok(self.last_response.param_l)
}
pub async fn sleep(&mut self) -> Result<(), Error<S::Error>> {
self.send_command(MessageData::new(Command::EnterSleepMode, 0, 0))
.await
}
pub async fn wake_up(
&mut self,
reset_if_needed: bool,
reset_duration_override: Option<u64>,
) -> Result<(), Error<S::Error>> {
let result = self
.send_command(MessageData::new(Command::EnterNormalMode, 0, 0))
.await;
if result.is_ok() || !reset_if_needed {
return result;
}
#[cfg(feature = "defmt")]
info!("Normal wake failed, trying reset");
self.reset(reset_duration_override).await
}
pub async fn query_status(&mut self) -> Result<u8, Error<S::Error>> {
self.send_command(MessageData::new(Command::QueryStatus, 0, 0))
.await?;
Ok(self.last_response.param_l)
}
}