diff --git a/soundcore-lib/src/devices/a3040.rs b/soundcore-lib/src/devices/a3040.rs index d8f180e..e7d7f9f 100644 --- a/soundcore-lib/src/devices/a3040.rs +++ b/soundcore-lib/src/devices/a3040.rs @@ -1,5 +1,9 @@ +mod bass_up_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::*; diff --git a/soundcore-lib/src/devices/a3040/bass_up_update.rs b/soundcore-lib/src/devices/a3040/bass_up_update.rs new file mode 100644 index 0000000..cb147df --- /dev/null +++ b/soundcore-lib/src/devices/a3040/bass_up_update.rs @@ -0,0 +1,12 @@ +use nom::{combinator::map, error::context}; + +use crate::{ + models::BassUp, + parsers::{parse_bool, ParseError, ParseResult}, +}; + +pub fn parse_a3040_bass_up_update<'a, E: ParseError<'a>>( + bytes: &'a [u8], +) -> ParseResult { + context("parse_a3040_bass_up_update", map(parse_bool, BassUp))(bytes) +} diff --git a/soundcore-lib/src/models/packet_kind.rs b/soundcore-lib/src/models/packet_kind.rs index 1fa4a6e..a53d69b 100644 --- a/soundcore-lib/src/models/packet_kind.rs +++ b/soundcore-lib/src/models/packet_kind.rs @@ -6,6 +6,9 @@ pub enum ResponsePacketKind { /* Packets which *should* update the state in some way */ StateUpdate, InfoUpdate, + ThreeDimensionalEffectUpdate, + BassUpUpdate, + EqInfoUpdate, SoundModeUpdate, BattLevelUpdate, BattChargingUpdate, @@ -19,10 +22,16 @@ pub enum ResponsePacketKind { /* We can use Generic Arg Infer "#![feature(generic_arg_infer)]" once https://github.com/rust-lang/rust/issues/85077 is stabilized */ /* This also could be dynamically be created, since the bytes match the command id bytes */ -pub const PACKET_KIND_MAP: [(&[u8; 2], ResponsePacketKind); 10] = [ +pub const PACKET_KIND_MAP: [(&[u8; 2], ResponsePacketKind); 13] = [ (&[0xFF, 0xFF], ResponsePacketKind::Unknown), /* Updates */ (&[0x01, 0x01], ResponsePacketKind::StateUpdate), + (&[0x02, 0x01], ResponsePacketKind::EqInfoUpdate), + (&[0x02, 0x04], ResponsePacketKind::BassUpUpdate), + ( + &[0x02, 0x06], + ResponsePacketKind::ThreeDimensionalEffectUpdate, + ), (&[0x01, 0x03], ResponsePacketKind::BattLevelUpdate), (&[0x01, 0x04], ResponsePacketKind::BattChargingUpdate), (&[0x01, 0x05], ResponsePacketKind::InfoUpdate), diff --git a/soundcore-lib/src/packets/response.rs b/soundcore-lib/src/packets/response.rs index c6cc906..376f9a9 100644 --- a/soundcore-lib/src/packets/response.rs +++ b/soundcore-lib/src/packets/response.rs @@ -1,10 +1,6 @@ use log::error; use nom::error::VerboseError; -pub use info::*; -pub use sound_mode::*; -pub use state::*; - use crate::api::SoundcoreDeviceState; use crate::parsers::TaggedData; use crate::{ @@ -12,11 +8,23 @@ use crate::{ parsers::{parse_and_check_checksum, parse_packet_header}, }; +mod battery; +mod info; +mod sound_mode; +mod state; +mod bass_up; + +pub use info::*; +pub use sound_mode::*; +pub use state::*; +pub use bass_up::*; + #[derive(Debug)] pub enum ResponsePacket { DeviceState(TaggedData), SoundModeUpdate(SoundModeUpdateResponse), DeviceInfo(DeviceInfoResponse), + BassUpUpdate(BassUpUpdateResponse), Unknown, } @@ -37,6 +45,7 @@ impl ResponsePacket { Self::SoundModeUpdate(parse_sound_mode_update_packet(bytes)?.1) } ResponsePacketKind::InfoUpdate => Self::DeviceInfo(parse_device_info_packet(bytes)?.1), + ResponsePacketKind::BassUpUpdate => Self::BassUpUpdate(parse_bass_up_update(bytes)?.1), _ => { // TODO: Have an array of Acks and handle those properly error!( @@ -85,17 +94,13 @@ impl StateTransformationPacket for ResponsePacket { sound_mode_update.transform_state(state) } ResponsePacket::DeviceState(state_update) => state_update.data.transform_state(state), + ResponsePacket::BassUpUpdate(packet) => packet.transform_state(state), // No-op _ => state.clone(), } } } -mod battery; -mod info; -mod sound_mode; -mod state; - #[cfg(test)] mod response_test { use test_data::a3951::*; diff --git a/soundcore-lib/src/packets/response/bass_up.rs b/soundcore-lib/src/packets/response/bass_up.rs new file mode 100644 index 0000000..a1114c0 --- /dev/null +++ b/soundcore-lib/src/packets/response/bass_up.rs @@ -0,0 +1,37 @@ +use log::{debug, warn}; +use nom::combinator::map; +use nom::error::context; +use serde::{Deserialize, Serialize}; + +use crate::api::SoundcoreDeviceState; +use crate::devices::parse_a3040_bass_up_update; +use crate::models::BassUp; +use crate::packets::StateTransformationPacket; +use crate::parsers::{ParseError, ParseResult}; + +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)] +pub struct BassUpUpdateResponse(pub BassUp); +pub fn parse_bass_up_update<'a, E: ParseError<'a>>( + bytes: &'a [u8], +) -> ParseResult { + context( + "parse_bass_up_update", + map(parse_a3040_bass_up_update, BassUpUpdateResponse), + )(bytes) +} + +impl StateTransformationPacket for BassUpUpdateResponse { + fn transform_state(self, state: &SoundcoreDeviceState) -> SoundcoreDeviceState { + let mut state = state.to_owned(); + match state.bass_up { + Some(bass_up) => { + debug!("Updating BassUp state from {:?} to {:?}", bass_up, self.0); + state.bass_up = Some(self.0); + } + None => { + warn!("BassUpUpdateResponse received without a previous BassUp state"); + } + } + state + } +} diff --git a/soundcore-lib/src/packets/response/state/a3040.rs b/soundcore-lib/src/packets/response/state/a3040.rs index 60f7ddd..b82210d 100644 --- a/soundcore-lib/src/packets/response/state/a3040.rs +++ b/soundcore-lib/src/packets/response/state/a3040.rs @@ -2,6 +2,14 @@ use nom::{bytes::complete::take, number::complete::le_u8}; use nom::{error::context, sequence::tuple}; use serde::{Deserialize, Serialize}; +use crate::{ + models::{ + AmbientSoundNotice, AutoPowerOff, BassUp, DeviceColor, FirmwareVer, HearingProtect, + InEarBeep, LDAC, PowerOnBatteryNotice, SerialNumber, SingleBattery, + SupportTwoCnn, ThreeDimensionalEffect, TouchTone, WearDetection, + }, + parsers::{parse_serial_number, ParseError}, +}; use crate::devices::a3040_features; use crate::models::{ A3040ButtonModel, ButtonModel, PromptLanguage, SoundMode, StereoEQConfiguration, TwsStatus, @@ -10,17 +18,9 @@ use crate::packets::DeviceStateResponse; use crate::parsers::{ bool_parser, parse_a3040_button_model, parse_adaptive_sound_mode_customizable_trans, parse_auto_power_off_on, parse_fw, parse_hearing_protect, parse_prompt_language, - parse_single_battery, parse_stereo_eq_configuration, u8_parser, TaggedData, TaggedParseResult, + parse_single_battery, parse_stereo_eq_configuration, TaggedData, TaggedParseResult, u8_parser, }; use crate::types::SupportedModels; -use crate::{ - models::{ - AmbientSoundNotice, AutoPowerOff, BassUp, DeviceColor, FirmwareVer, HearingProtect, - InEarBeep, PowerOnBatteryNotice, SerialNumber, SingleBattery, SupportTwoCnn, - ThreeDimensionalEffect, TouchTone, WearDetection, LDAC, - }, - parsers::{parse_serial_number, ParseError}, -}; #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)] pub struct A3040StateResponse { diff --git a/soundcore-lib/src/parsers/packet_header.rs b/soundcore-lib/src/parsers/packet_header.rs index c2f7054..8bc53bb 100644 --- a/soundcore-lib/src/parsers/packet_header.rs +++ b/soundcore-lib/src/parsers/packet_header.rs @@ -1,3 +1,4 @@ +use log::trace; use nom::{ bytes::complete::take, combinator::{map, map_opt}, @@ -33,6 +34,7 @@ fn parse_packet_kind<'a, E: ParseError<'a>>(bytes: &'a [u8]) -> ParseResult