Skip to content

Commit

Permalink
feat: add a3040 eq info update response
Browse files Browse the repository at this point in the history
  • Loading branch information
gmallios committed Apr 30, 2024
1 parent 9b1eb94 commit 3d1e276
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 24 deletions.
12 changes: 8 additions & 4 deletions soundcore-lib/src/devices/a3040.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
pub use bass_up_update::*;
pub use eq_info_update::*;
pub use eq_update_command::*;
pub use features::*;
pub use sound_mode_update_command::*;

mod bass_up_update;
mod eq_info_update;
mod eq_update_command;
mod features;
mod sound_mode_update_command;

pub use bass_up_update::*;
pub use eq_update_command::*;
pub use features::*;
pub use sound_mode_update_command::*;
pub use eq_info_update::*;

Check warning on line 13 in soundcore-lib/src/devices/a3040.rs

View workflow job for this annotation

GitHub Actions / Run cargo check

unused import: `eq_info_update::*`

Check warning on line 13 in soundcore-lib/src/devices/a3040.rs

View workflow job for this annotation

GitHub Actions / Run tests with stable Rust

unused import: `eq_info_update::*`
45 changes: 45 additions & 0 deletions soundcore-lib/src/devices/a3040/eq_info_update.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use log::warn;
use nom::combinator::map;
use nom::error::context;
use nom::number::complete::le_u8;
use nom::sequence::tuple;
use strum::EnumCount;
use crate::models::EQProfile;
use crate::parsers::{ParseError, ParseResult};

pub fn parse_a3040_eq_info_update<'a, E: ParseError<'a>>(bytes: &'a [u8]) -> ParseResult<EQProfile, E> {
context(
"parse_a3040_eq_info_update",
map(tuple((le_u8, le_u8)), |(b1, b2)| {
let eq_idx = ((b1 & 0xFF) as u16)
| (((b2 & 0xFF) as u16) << 8).clamp(0, EQProfile::COUNT as u16);
match EQProfile::from_id_le(eq_idx) {
Some(eq) => eq,
None => {
warn!("Unknown EQ profile index from eq info update: {}", eq_idx);
EQProfile::SoundcoreSignature
},
}
}),
)(bytes)
}


#[cfg(test)]
mod test {
use super::*;

#[test]
pub fn should_parse_eq_info_update() {
let bytes = &[0x01, 0x00];
let result = parse_a3040_eq_info_update::<nom::error::VerboseError<&[u8]>>(bytes);
assert_eq!(result, Ok((&[][..], EQProfile::Acoustic)));
}

#[test]
pub fn should_default_if_index_is_out_of_bounds() {
let bytes = &[0xFF, 0x00];
let result = parse_a3040_eq_info_update::<nom::error::VerboseError<&[u8]>>(bytes);
assert_eq!(result, Ok((&[][..], EQProfile::SoundcoreSignature)));
}
}
20 changes: 20 additions & 0 deletions soundcore-lib/src/devices/a3040/eq_update_command.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use crate::models::{BassUp, MonoEQConfiguration};
use crate::packets::Packet;

pub struct A3040EqUpdateCommand {
eq: MonoEQConfiguration,

Check warning on line 5 in soundcore-lib/src/devices/a3040/eq_update_command.rs

View workflow job for this annotation

GitHub Actions / Run cargo check

field `eq` is never read

Check warning on line 5 in soundcore-lib/src/devices/a3040/eq_update_command.rs

View workflow job for this annotation

GitHub Actions / Run tests with stable Rust

field `eq` is never read
bass_up: BassUp,
}

impl Packet for A3040EqUpdateCommand {
fn command(&self) -> [u8; 7] {
match self.bass_up.0 {
true => [0x08, 0xEE, 0x00, 0x00, 0x00, 0x02, 0x84],
false => todo!(),
}
}

fn payload(&self) -> Vec<u8> {
todo!()
}
}
10 changes: 10 additions & 0 deletions soundcore-lib/src/models/eq_configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ pub enum EQConfiguration {
Mono(MonoEQConfiguration),
}

impl EQConfiguration {
pub fn set_profile(&mut self, profile: EQProfile) {
match self {
EQConfiguration::Stereo(config) => config.profile = profile,
EQConfiguration::Mono(config) => config.profile = profile,
}
}
}

#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone, Hash, Default)]
#[typeshare]
pub struct StereoEQConfiguration {
Expand Down Expand Up @@ -41,3 +50,4 @@ impl From<MonoEQConfiguration> for EQConfiguration {
EQConfiguration::Mono(config)
}
}

3 changes: 2 additions & 1 deletion soundcore-lib/src/models/eq_profile.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use serde::{Deserialize, Serialize};
use strum::{Display, EnumIter, EnumString, FromRepr};
use strum::{Display, EnumCount, EnumIter, EnumString, FromRepr};
use typeshare::typeshare;

use super::MonoEQ;
Expand All @@ -20,6 +20,7 @@ use super::MonoEQ;
Serialize,
Deserialize,
EnumString,
EnumCount,
Default,
)]
#[typeshare]
Expand Down
5 changes: 5 additions & 0 deletions soundcore-lib/src/packets/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ use crate::{
parsers::{parse_and_check_checksum, parse_packet_header},
};
use crate::api::SoundcoreDeviceState;
use crate::packets::response::eq_info_update::{EqInfoUpdate, parse_eq_info_update};
use crate::parsers::TaggedData;

mod bass_up;
mod battery;
mod eq_info_update;
mod info;
mod sound_mode;
mod state;
Expand All @@ -25,6 +27,7 @@ pub enum ResponsePacket {
SoundModeUpdate(SoundModeUpdateResponse),
DeviceInfo(DeviceInfoResponse),
BassUpUpdate(BassUpUpdateResponse),
EqInfoUpdate(EqInfoUpdate),
Unknown,
}

Expand All @@ -46,6 +49,7 @@ impl ResponsePacket {
}
ResponsePacketKind::InfoUpdate => Self::DeviceInfo(parse_device_info_packet(bytes)?.1),
ResponsePacketKind::BassUpUpdate => Self::BassUpUpdate(parse_bass_up_update(bytes)?.1),
ResponsePacketKind::EqInfoUpdate => Self::EqInfoUpdate(parse_eq_info_update(bytes)?.1),
_ => {
// TODO: Have an array of Acks and handle those properly
error!(
Expand Down Expand Up @@ -95,6 +99,7 @@ impl StateTransformationPacket for ResponsePacket {
}
ResponsePacket::DeviceState(state_update) => state_update.data.transform_state(state),
ResponsePacket::BassUpUpdate(packet) => packet.transform_state(state),
ResponsePacket::EqInfoUpdate(packet) => packet.transform_state(state),
// No-op
_ => state.clone(),
}
Expand Down
30 changes: 30 additions & 0 deletions soundcore-lib/src/packets/response/eq_info_update.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use nom::combinator::map;
use nom::error::context;

use crate::api::SoundcoreDeviceState;
use crate::devices::parse_a3040_eq_info_update;
use serde::{Deserialize, Serialize};

use crate::models::EQProfile;
use crate::packets::StateTransformationPacket;
use crate::parsers::{ParseError, ParseResult};

#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
pub struct EqInfoUpdate(pub EQProfile);

pub fn parse_eq_info_update<'a, E: ParseError<'a>>(
bytes: &'a [u8],
) -> ParseResult<EqInfoUpdate, E> {
context(
"parse_eq_info_update",
map(parse_a3040_eq_info_update, EqInfoUpdate),
)(bytes)
}

impl StateTransformationPacket for EqInfoUpdate {
fn transform_state(self, state: &SoundcoreDeviceState) -> SoundcoreDeviceState {
let mut state = state.clone();
state.eq_configuration.set_profile(self.0);
state
}
}
19 changes: 0 additions & 19 deletions soundcore-lib/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,22 +122,3 @@ pub(crate) fn calculate_checksum_byte(cmd: &[u8]) -> u8 {
}
(i & 0xFF).try_into().unwrap()
}

pub(crate) trait Clamp<T> {
fn clamp(self, min: T, max: T) -> T;
}

impl<T> Clamp<T> for T
where
T: PartialOrd + Copy,
{
fn clamp(self, min: T, max: T) -> T {
if self > max {
max
} else if self < min {
min
} else {
self
}
}
}

0 comments on commit 3d1e276

Please sign in to comment.