Skip to content

Commit

Permalink
fix: Refactor A3040StateResponse parsing and add new fields
Browse files Browse the repository at this point in the history
  • Loading branch information
gmallios committed Feb 25, 2024
1 parent a5675f0 commit a8e724f
Showing 1 changed file with 72 additions and 69 deletions.
141 changes: 72 additions & 69 deletions soundcore-lib/src/packets/response/state/a3040.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
use std::num::NonZeroUsize;

Check warning on line 1 in soundcore-lib/src/packets/response/state/a3040.rs

View workflow job for this annotation

GitHub Actions / Tests with stable Rust

unused import: `std::num::NonZeroUsize`

Check warning on line 1 in soundcore-lib/src/packets/response/state/a3040.rs

View workflow job for this annotation

GitHub Actions / Check

unused import: `std::num::NonZeroUsize`

use enumflags2::{make_bitflags, BitFlags};
use nom::number::complete::le_u8;
use nom::{combinator::all_consuming, error::context, sequence::tuple};
use nom::{bits, combinator::all_consuming, error::context, sequence::tuple};

Check warning on line 4 in soundcore-lib/src/packets/response/state/a3040.rs

View workflow job for this annotation

GitHub Actions / Tests with stable Rust

unused imports: `bits`, `combinator::all_consuming`

Check warning on line 4 in soundcore-lib/src/packets/response/state/a3040.rs

View workflow job for this annotation

GitHub Actions / Check

unused imports: `bits`, `combinator::all_consuming`
use nom::{bytes::complete::take, number::complete::le_u8};
use serde::{Deserialize, Serialize};

use crate::models::PromptLanguage;
use crate::models::{A3040ButtonModel, ButtonModel, PromptLanguage, TwsStatus, EQConfiguration, StereoEQConfiguration};

Check warning on line 8 in soundcore-lib/src/packets/response/state/a3040.rs

View workflow job for this annotation

GitHub Actions / Tests with stable Rust

unused import: `EQConfiguration`

Check warning on line 8 in soundcore-lib/src/packets/response/state/a3040.rs

View workflow job for this annotation

GitHub Actions / Check

unused import: `EQConfiguration`
use crate::packets::DeviceStateResponse;
use crate::parsers::{
bool_parser, parse_a3040_button_model, parse_auto_power_off_on, parse_fw,
parse_hearing_protect, parse_prompt_language, parse_single_battery, parse_sound_mode,
parse_stereo_eq, u8_parser, TaggedData, TaggedParseResult,
parse_hearing_protect, parse_mono_eq, parse_prompt_language, parse_single_battery,
parse_sound_mode, parse_stereo_eq, u8_parser, TaggedData, TaggedParseResult, parse_stereo_eq_configuration,
};
use crate::types::SupportedModels;
use crate::{
Expand All @@ -22,12 +24,15 @@ use crate::{

#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
pub struct A3040StateResponse {
pub feature_flags: BitFlags<SoundcoreFeatureFlags>,
pub battery: SingleBattery,
pub fw: FirmwareVer,
pub sn: SerialNumber,
pub eq: StereoEQConfiguration,
pub touch_tone: TouchTone,
pub wear_detection: WearDetection,
pub three_dimensional_effect: ThreeDimensionalEffect,
pub button_model: A3040ButtonModel,
// TODO: Extract type?
pub charging_case_battery: u8,
pub bass_up: BassUp,
Expand Down Expand Up @@ -63,35 +68,73 @@ const A3040_FEATURE_FLAGS: BitFlags<SoundcoreFeatureFlags> = make_bitflags!(Soun
| SupportTwoCnn
});

// TODO: Figure out what the bytes remaining are so this can be all_consuming
pub fn parse_a3040_state_response<'a, E: ParseError<'a>>(
bytes: &'a [u8],
) -> TaggedParseResult<A3040StateResponse, E> {
context(
"a3040_state_response",
all_consuming(|bytes| {
// The A3040 state response seems to be composed of 3 parts:
// 1. The first part where some state data exists along with an offset
// 2. An empty? part which length is determined by the offset
// 3. The 3rd part where the rest of the state data exists and is read based on the offset

let (bytes, (battery, fw, sn, _eq_idx_0, _eq_idx_1, _eq)) = tuple((
context("a3040_state_response", |bytes: &'a [u8]| {
let (bytes, (battery, fw, sn,eq, offset, button_model)) =
tuple((
parse_single_battery,
parse_fw,
parse_serial_number,
parse_stereo_eq_configuration(10), // TODO: We have mono eq here, but it appears to be duplicated (bytes are not 1-1, DRC?)
le_u8,
le_u8,
parse_stereo_eq,
parse_a3040_button_model,
))(bytes)?;

let (bytes, _offset) = (le_u8)(bytes)?;
let (bytes, _ignored) = take(offset as usize - 1)(bytes)?;
let (
bytes,
(
_sound_mode,
touch_tone,
wear_detection,
three_dimensional_effect,
charging_case_battery,
bass_up,
device_color,
ldac,
support_two_cnn,
in_ear_beep,
prompt_language,
auto_power_off,
hearing_protect,
ambient_sound_notice,
power_on_battery_notice,
),
) = tuple((
parse_sound_mode,
bool_parser::<TouchTone, E>,
bool_parser::<WearDetection, E>,
bool_parser::<ThreeDimensionalEffect, E>,
le_u8,
bool_parser::<BassUp, E>,
u8_parser::<DeviceColor, E>,
bool_parser::<LDAC, E>,
bool_parser::<SupportTwoCnn, E>,
bool_parser::<InEarBeep, E>,
parse_prompt_language,
parse_auto_power_off_on,
parse_hearing_protect,
bool_parser::<AmbientSoundNotice, E>,
bool_parser::<PowerOnBatteryNotice, E>,
))(bytes)?;

let (
bytes,
(
_custom_btn_model,
_sound_mode,
println!("Remaining bytes: {:x?}", bytes);
Ok((
bytes,
TaggedData {
tag: SupportedModels::A3040,
data: A3040StateResponse {
feature_flags: A3040_FEATURE_FLAGS,
battery,
fw,
sn,
eq,
touch_tone,
wear_detection,
button_model,
three_dimensional_effect,
charging_case_battery,
bass_up,
Expand All @@ -104,59 +147,16 @@ pub fn parse_a3040_state_response<'a, E: ParseError<'a>>(
hearing_protect,
ambient_sound_notice,
power_on_battery_notice,
),
) = tuple((
parse_a3040_button_model,
parse_sound_mode,
bool_parser::<TouchTone, E>,
bool_parser::<WearDetection, E>,
bool_parser::<ThreeDimensionalEffect, E>,
le_u8,
bool_parser::<BassUp, E>,
u8_parser::<DeviceColor, E>,
bool_parser::<LDAC, E>,
bool_parser::<SupportTwoCnn, E>,
bool_parser::<InEarBeep, E>,
parse_prompt_language,
parse_auto_power_off_on,
parse_hearing_protect,
bool_parser::<AmbientSoundNotice, E>,
bool_parser::<PowerOnBatteryNotice, E>,
))(bytes)?;

Ok((
bytes,
TaggedData {
tag: SupportedModels::A3040,
data: A3040StateResponse {
battery,
fw,
sn,
touch_tone,
wear_detection,
three_dimensional_effect,
charging_case_battery,
bass_up,
device_color,
ldac,
support_two_cnn,
in_ear_beep,
prompt_language,
auto_power_off,
hearing_protect,
ambient_sound_notice,
power_on_battery_notice,
},
},
))
}),
)(bytes)
},
))
})(&bytes)
}

// TODO:
impl From<A3040StateResponse> for DeviceStateResponse {
fn from(value: A3040StateResponse) -> Self {
Self {
feature_flags: value.feature_flags,
battery: value.battery.into(),
fw: value.fw.into(),
sn: Some(value.sn),
Expand All @@ -173,6 +173,9 @@ impl From<A3040StateResponse> for DeviceStateResponse {
hearing_protect: Some(value.hearing_protect),
ambient_sound_notice: Some(value.ambient_sound_notice),
power_on_battery_notice: Some(value.power_on_battery_notice),
button_model: Some(ButtonModel::A3040(value.button_model)),
tws_status: Some(TwsStatus(true)),
eq: value.eq.into(),
..Default::default()
}
}
Expand Down

0 comments on commit a8e724f

Please sign in to comment.