Skip to content

Commit

Permalink
feat: Add more parsers
Browse files Browse the repository at this point in the history
  • Loading branch information
gmallios committed Dec 6, 2023
1 parent d392382 commit 638ebce
Show file tree
Hide file tree
Showing 34 changed files with 560 additions and 149 deletions.
29 changes: 29 additions & 0 deletions soundcore-lib/src/packets.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,34 @@
mod command;
mod request;
mod response;

pub use command::*;
pub use request::*;
pub use response::*;

pub trait SoundcorePacket {
const COMMAND_BYTE_SIZE: usize = 2;
const PACKET_PREFIX: [u8; 5] = [0x08, 0xEE, 0x00, 0x00, 0x00];

type ByteArr;
/// Returns the packet's bytes + checksum
fn bytes(&self) -> Self::ByteArr;
}

impl<T> SoundcorePacket for T
where
T: RequestPacket,
{
type ByteArr = [u8; Self::COMMAND_BYTE_SIZE + Self::PACKET_PREFIX.len() + 3];

fn bytes(&self) -> Self::ByteArr {
let mut bytes = [0; COMMAND_BYTE_SIZE + Self::PACKET_PREFIX.len() + 3];
// Add the prefix
bytes[..Self::PACKET_PREFIX.len()].copy_from_slice(&Self::PACKET_PREFIX);
// Add the command bytes
bytes[Self::PACKET_PREFIX.len()..Self::PACKET_PREFIX.len() + COMMAND_BYTE_SIZE]
.copy_from_slice(&self.default_bytes());

bytes
}
}
1 change: 1 addition & 0 deletions soundcore-lib/src/packets/command.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

15 changes: 15 additions & 0 deletions soundcore-lib/src/packets/request.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use crate::types::SupportedModels;

use super::COMMAND_BYTE_SIZE;

/// Request Packets are used to request data from the device.
pub trait RequestPacket {
/// Returns the default command bytes without checksum
fn default_bytes(&self) -> [u8; COMMAND_BYTE_SIZE];
/// Returns the command bytes for the specified variant without checksum
fn variant_bytes(&self, variant: SupportedModels) -> [u8; COMMAND_BYTE_SIZE];
}

mod state;

pub use state::*;
51 changes: 51 additions & 0 deletions soundcore-lib/src/packets/request/state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use serde::{Deserialize, Serialize};

use crate::{packets::COMMAND_BYTE_SIZE, types::SupportedModels};

use super::RequestPacket;

#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash, Default)]
struct RequestStatePacket {
variant: Option<SupportedModels>,
}

impl RequestStatePacket {
const DEFAULT: [u8; COMMAND_BYTE_SIZE] = [0x01, 0x01];

fn new() -> Self {
Self { variant: None }
}

fn with_variant(variant: SupportedModels) -> Self {
Self {
variant: Some(variant),
}
}
}

impl RequestPacket for RequestStatePacket {
fn default_bytes(&self) -> [u8; COMMAND_BYTE_SIZE] {
match self.variant {
Some(variant) => self.variant_bytes(variant),
None => Self::DEFAULT,
}
}

fn variant_bytes(&self, variant: SupportedModels) -> [u8; COMMAND_BYTE_SIZE] {
match variant {
SupportedModels::A3951 => Self::DEFAULT,
_ => todo!(),
}
}
}

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

#[test]
fn test_default() {
let packet = RequestStatePacket::new();
assert_eq!(packet.default_bytes(), RequestStatePacket::DEFAULT);
}
}
6 changes: 3 additions & 3 deletions soundcore-lib/src/packets/response/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};

use crate::{
models::{DeviceFirmware, SerialNumber},
parsers::{SoundcoreParseError, SoundcoreParseResult},
parsers::{ParseError, ParseResult},
};

#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone, Hash)]
Expand All @@ -16,9 +16,9 @@ pub struct DeviceInfoResponse {
}

// TODO: Add more parsers
pub fn parse_device_info_packet<'a, E: SoundcoreParseError<'a>>(
pub fn parse_device_info_packet<'a, E: ParseError<'a>>(
bytes: &'a [u8],
) -> SoundcoreParseResult<DeviceInfoResponse, E> {
) -> ParseResult<DeviceInfoResponse, E> {
context("parse_device_info", |bytes| {
map(
parse_a3951_device_info_packet::<'a, E>,
Expand Down
8 changes: 4 additions & 4 deletions soundcore-lib/src/packets/response/info/a3951.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use nom::{
combinator::{all_consuming, map},
error::context,
sequence::{pair},
sequence::pair,
};
use serde::{Deserialize, Serialize};

use crate::{
models::{DeviceFirmware, SerialNumber},
parsers::{parse_dual_fw, parse_serial_number, SoundcoreParseError, SoundcoreParseResult},
parsers::{parse_dual_fw, parse_serial_number, ParseError, ParseResult},
};

use super::DeviceInfoResponse;
Expand All @@ -18,9 +18,9 @@ pub struct A3951DeviceInfoResponse {
pub fw: DeviceFirmware,
}

pub fn parse_a3951_device_info_packet<'a, E: SoundcoreParseError<'a>>(
pub fn parse_a3951_device_info_packet<'a, E: ParseError<'a>>(
bytes: &'a [u8],
) -> SoundcoreParseResult<A3951DeviceInfoResponse, E> {
) -> ParseResult<A3951DeviceInfoResponse, E> {
context(
"parse_a3951_device_info",
all_consuming(map(pair(parse_dual_fw, parse_serial_number), |(fw, sn)| {
Expand Down
6 changes: 3 additions & 3 deletions soundcore-lib/src/packets/response/sound_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ use serde::{Deserialize, Serialize};

use crate::{
models::SoundMode,
parsers::{parse_sound_mode, SoundcoreParseError, SoundcoreParseResult},
parsers::{parse_sound_mode, ParseError, ParseResult},
};

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

pub fn parse_sound_mode_update_packet<'a, E: SoundcoreParseError<'a>>(
pub fn parse_sound_mode_update_packet<'a, E: ParseError<'a>>(
bytes: &'a [u8],
) -> SoundcoreParseResult<SoundModeUpdateResponse, E> {
) -> ParseResult<SoundModeUpdateResponse, E> {
context(
"parse_sound_mode_update",
map(parse_sound_mode, SoundModeUpdateResponse),
Expand Down
6 changes: 3 additions & 3 deletions soundcore-lib/src/packets/response/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
AgeRange, Battery, ButtonModel, CustomHearID, EQConfiguration, HearID, SideTone, SoundMode,
SoundcoreFeatureFlags, TouchTone, TwsStatus, WearDetection,
},
parsers::{SoundcoreParseError, SoundcoreParseResult},
parsers::{ParseError, ParseResult},
};

/// This is a generalized version of the state responses for all devices
Expand All @@ -33,9 +33,9 @@ pub struct DeviceStateResponse {
}

// TODO: Add more parsers
pub fn parse_state_update_packet<'a, E: SoundcoreParseError<'a>>(
pub fn parse_state_update_packet<'a, E: ParseError<'a>>(
bytes: &'a [u8],
) -> SoundcoreParseResult<DeviceStateResponse, E> {
) -> ParseResult<DeviceStateResponse, E> {
context("parse_state_update", |bytes| {
alt((
map(
Expand Down
8 changes: 4 additions & 4 deletions soundcore-lib/src/packets/response/state/a3027.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ use crate::{

use crate::parsers::{
bool_parser, parse_a3909_button_model, parse_age_range, parse_custom_hear_id,
parse_dual_battery, parse_gender, parse_sound_mode, parse_stereo_eq_configuration,
SoundcoreParseError, SoundcoreParseResult,
parse_dual_battery, parse_gender, parse_sound_mode, parse_stereo_eq_configuration, ParseError,
ParseResult,
};

use super::DeviceStateResponse;
Expand Down Expand Up @@ -70,9 +70,9 @@ impl From<A3027StateResponse> for DeviceStateResponse {
}
}

pub fn parse_a3027_state_response<'a, E: SoundcoreParseError<'a>>(
pub fn parse_a3027_state_response<'a, E: ParseError<'a>>(
bytes: &'a [u8],
) -> SoundcoreParseResult<A3027StateResponse, E> {
) -> ParseResult<A3027StateResponse, E> {
context(
"a3027_state_response",
all_consuming(|bytes| {
Expand Down
107 changes: 107 additions & 0 deletions soundcore-lib/src/packets/response/state/a3028.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use enumflags2::{make_bitflags, BitFlags};
use nom::{
combinator::{all_consuming, opt},
error::context,
number::complete::{le_u16, le_u8},
sequence::tuple,
};
use serde::{Deserialize, Serialize};

use crate::{
models::{
A3909ButtonModel, AgeRange, BaseHearID, Battery, ButtonModel, CustomHearID, DeviceFirmware,
DualBattery, EQConfiguration, FirmwareVer, Gender, HearID, SerialNumber, SideTone,
SingleBattery, SoundMode, SoundcoreFeatureFlags, StereoEQConfiguration, TouchTone,
TwsStatus, WearDetection,
},
parsers::{
parse_base_hear_id, parse_bool, parse_dual_fw, parse_fw, parse_serial_number,
parse_single_battery,
},
};

use crate::parsers::{
bool_parser, parse_a3909_button_model, parse_age_range, parse_custom_hear_id,
parse_dual_battery, parse_gender, parse_sound_mode, parse_stereo_eq_configuration, ParseError,
ParseResult,
};

use super::DeviceStateResponse;

#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
pub struct A3028StateResponse {
pub tws_status: TwsStatus,
pub battery: SingleBattery,
pub eq: StereoEQConfiguration,
pub gender: Gender,
pub age_range: AgeRange,
pub hear_id: BaseHearID,
pub sound_mode: SoundMode,
pub fw: DeviceFirmware,
pub sn: SerialNumber,
}

const A3028_FEATURE_FLAGS: BitFlags<SoundcoreFeatureFlags> = make_bitflags!(SoundcoreFeatureFlags::{
SOUND_MODE
| ANC_MODE
| TRANS_MODE
| EQ
| STEREO_EQ
| HEARID
});

impl From<A3028StateResponse> for DeviceStateResponse {
fn from(value: A3028StateResponse) -> Self {
DeviceStateResponse {
feature_flags: A3028_FEATURE_FLAGS,
battery: value.battery.into(),
sound_mode: value.sound_mode,
eq: EQConfiguration::Stereo(value.eq).into(),
tws_status: value.tws_status.into(),
hear_id: Some(HearID::Base(value.hear_id)),
age_range: value.age_range.into(),
..Default::default()
}
}
}

pub fn parse_a3028_state_response<'a, E: ParseError<'a>>(
bytes: &'a [u8],
) -> ParseResult<A3028StateResponse, E> {
context(
"a3028_state_response",
all_consuming(|bytes| {
let (bytes, (battery, eq, gender, age_range, hear_id, sound_mode, fw, sn)) =
tuple((
parse_single_battery,
parse_stereo_eq_configuration,
parse_gender,
parse_age_range,
parse_base_hear_id,
parse_sound_mode,
parse_dual_fw,
parse_serial_number,
))(bytes)?;

Ok((
bytes,
A3028StateResponse {
tws_status: TwsStatus(true),
battery,
eq,
gender,
age_range,
hear_id,
sound_mode,
fw: DeviceFirmware::DUAL(fw.0, fw.1),
sn,
},
))
}),
)(bytes)
}

#[cfg(test)]
mod a3028_state {
// TODO
}
Loading

0 comments on commit 638ebce

Please sign in to comment.