Skip to content

Commit

Permalink
feat: add a3947 image and product code
Browse files Browse the repository at this point in the history
  • Loading branch information
gmallios committed May 3, 2024
1 parent 46d8f6a commit f6d0698
Show file tree
Hide file tree
Showing 22 changed files with 125 additions and 88 deletions.
11 changes: 5 additions & 6 deletions manager-app/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@ use std::sync::Arc;

use log::trace;
use mpsc::channel;
use soundcore_lib::api::SoundcoreDeviceState;
use soundcore_lib::btaddr::BluetoothAdrr;

use tauri::async_runtime::{Mutex, RwLock};
use tauri::{AppHandle, Manager};
use tauri::async_runtime::{Mutex, RwLock};
use tauri_plugin_log::LogTarget;
use tokio::sync::mpsc;

use soundcore_lib::types::SupportedModels;
use soundcore_lib::api::SoundcoreDeviceState;
use soundcore_lib::btaddr::BluetoothAdrr;
use soundcore_lib::types::KnownProductCodes;

use crate::async_bridge::{async_bridge, BridgeCommand, BridgeResponse};

Expand All @@ -26,7 +25,7 @@ pub(crate) mod async_bridge;
// mod tray;

struct SoundcoreAppState {
model: Arc<RwLock<Option<SupportedModels>>>,
model: Arc<RwLock<Option<KnownProductCodes>>>,
bridge_tx: Mutex<mpsc::Sender<BridgeCommand>>,
scan_in_progress: Arc<Mutex<bool>>,
last_states: Arc<Mutex<HashMap<BluetoothAdrr, SoundcoreDeviceState>>>,
Expand Down
Binary file added manager-ui/src/assets/a3947_img_device.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ export const DeviceStateCard: React.FC = () => {
<Paper
sx={{ display: 'flex', margin: 1.5, justifyContent: 'center', alignItems: 'center' }}
elevation={0}>
<ProductImageWithBattery
model={currentState?.serial?.model}
battery={currentState?.battery}
/>
<ProductImageWithBattery model={'A3947'} battery={currentState?.battery} />
</Paper>
</Box>
</>
Expand Down
62 changes: 47 additions & 15 deletions manager-ui/src/types/soundcore-lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ export type CustomANCValue = number;

export type CustomTransparencyValue = number;

/**
* This u8 is a char which based on it fetches the apropriate image for the device (Reference: OtaBaseActivity/renderProductIcon).
* Perhaps this can be internally mapped to our product images.
* Further investigation is needed.
*/
export type DeviceColor = number;

export type HearIDType = number;

export type HearIDMusicType = number;
Expand Down Expand Up @@ -92,20 +99,21 @@ export type EQConfiguration =
| { type: 'stereo'; value: StereoEQConfiguration }
| { type: 'mono'; value: MonoEQConfiguration };

export enum SupportedModels {
export enum KnownProductCodes {
A3027 = 'A3027',
A3028 = 'A3028',
A3029 = 'A3029',
A3040 = 'A3040',
A3930 = 'A3930',
A3931 = 'A3931',
A3935 = 'A3935',
A3951 = 'A3951'
A3951 = 'A3951',
A3947 = 'A3947'
}

export interface SerialNumber {
value: string;
model?: SupportedModels;
model?: KnownProductCodes;
}

export interface FirmwareVer {
Expand All @@ -119,6 +127,22 @@ export type ButtonModel =

export type HearID = { type: 'base'; value: BaseHearID } | { type: 'custom'; value: CustomHearID };

export interface AutoPowerOff {
enabled: boolean;
index: number;
}

export enum PromptLanguage {
English = 'English',
Chinese = 'Chinese'
}

export interface HearingProtect {
enabled: boolean;
db: number;
freq: number;
}

/** This is a generalized version of the state for all devices */
export interface SoundcoreDeviceState {
featureSet: DeviceFeatureSet;
Expand All @@ -127,14 +151,28 @@ export interface SoundcoreDeviceState {
eqConfiguration: EQConfiguration;
serial?: SerialNumber;
fw?: FirmwareVer;
hostDevice?: number;
twsStatus?: TwsStatus;
buttonModel?: ButtonModel;
hostDevice?: number;
sideTone?: SideTone;
ageRange?: AgeRange;
/** HearID */
hearidEqPreset?: number;
wearDetection?: WearDetection;
hearId?: HearID;
ageRange?: AgeRange;
hearIdHasData?: boolean;
touchTone?: TouchTone;
twsStatus?: TwsStatus;
wearDetection?: WearDetection;
bassUp?: BassUp;
autoPowerOff?: AutoPowerOff;
supportTwoCnn?: SupportTwoCnn;
inEarBeep?: InEarBeep;
ambientSoundNotice?: AmbientSoundNotice;
powerOnBatteryNotice?: PowerOnBatteryNotice;
threeDimensionalEffect?: ThreeDimensionalEffect;
deviceColor?: DeviceColor;
ldac?: LDAC;
promptLanguage?: PromptLanguage;
hearingProtect?: HearingProtect;
}

export interface BluetoothAdrr {
Expand All @@ -151,7 +189,7 @@ export interface DiscoveredDevice {
/** The BLE device descriptor. */
descriptor: BLEDeviceDescriptor;
/** The model of the device, resolved using the device's advertised name. */
model?: SupportedModels;
model?: KnownProductCodes;
}

export enum Action {
Expand Down Expand Up @@ -249,8 +287,7 @@ export enum EQProfile {
Daya = 'Daya',
CedricGervais = 'CedricGervais',
TheInfamousStringdusters = 'TheInfamousStringdusters',
JohnPaulWhite = 'JohnPaulWhite',
SoundcoreSignatureBassUp = 'SoundcoreSignatureBassUp'
JohnPaulWhite = 'JohnPaulWhite'
}

export interface StereoEQConfiguration {
Expand Down Expand Up @@ -335,11 +372,6 @@ export enum NonCustomizableTransparencyMode {
Vocal = 'vocal'
}

export enum PromptLanguage {
English = 'English',
Chinese = 'Chinese'
}

export enum SceneBasedANCMode {
Transport = 'Transport',
Outdoor = 'Outdoor',
Expand Down
4 changes: 3 additions & 1 deletion manager-ui/src/utils/modelToImgMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import A3028Img from '@assets/a3028_img_device.webp';
import A3029Img from '@assets/a3029_img_device.webp';
import A3040Img from '@assets/a3040_img_device.webp';
import A3935Img from '@assets/a3935_img_device.webp';
import A3947Img from '@assets/a3947_img_device.png';

export type ImageData = {
img: string;
Expand All @@ -19,7 +20,8 @@ const ModelSingleImageMap: {
A3027: { img: A3027Img, height: 90 },
A3028: { img: A3028Img, height: 90 },
A3029: { img: A3029Img, height: 90 },
A3935: { img: A3935Img, height: 90 }
A3935: { img: A3935Img, height: 90 },
A3947: { img: A3947Img, height: 90 }
};

const ModelDoubleImageMap: {
Expand Down
6 changes: 3 additions & 3 deletions soundcore-lib/src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::packets::{
StateTransformationPacket,
};
use crate::parsers::TaggedData;
use crate::types::SupportedModels;
use crate::types::KnownProductCodes;

pub struct SoundcoreBLEDevice<Connection>
where
Expand All @@ -24,7 +24,7 @@ where
connection: Arc<Connection>,
state_channel: Arc<Mutex<watch::Sender<SoundcoreDeviceState>>>,
state_channel_handle: JoinHandle<()>,
model: SupportedModels,
model: KnownProductCodes,
}

impl<Connection> SoundcoreBLEDevice<Connection>
Expand Down Expand Up @@ -117,7 +117,7 @@ where
// TODO: Add test data to mocked device so initial state can be fetched
if cfg!(test) || cfg!(feature = "mock") {
return Ok(TaggedData {
tag: SupportedModels::A3951,
tag: KnownProductCodes::A3951,
data: SoundcoreDeviceState::default(),
});
}
Expand Down
22 changes: 11 additions & 11 deletions soundcore-lib/src/device_manager.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
use std::{sync::Arc, time::Duration};
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::{sync::Arc, time::Duration};

use crate::ble::BLEAdapterEvent;
#[cfg(any(test, feature = "mock"))]
use crate::mocks::*;
use serde::{Deserialize, Serialize};
use tokio::sync::RwLock;
use typeshare::typeshare;

use crate::{
ble::{BLEConnectionManager, BLEDeviceDescriptor},
btaddr::BluetoothAdrr,
device::SoundcoreBLEDevice,
error::SoundcoreLibResult,
types::{SupportedModels, SOUNDCORE_NAME_MODEL_MAP},
types::{KnownProductCodes, SOUNDCORE_NAME_PRODUCT_CODE_MAP},
};
use serde::{Deserialize, Serialize};
use tokio::sync::RwLock;
use typeshare::typeshare;

use crate::ble::BLEAdapterEvent;
// TODO: Specify clippy & fmt features
#[allow(unused_imports)]
#[cfg(all(feature = "btleplug-backend", not(feature = "mock")))]
use crate::ble::btleplug::manager::BtlePlugBLEManager;
#[cfg(any(test, feature = "mock"))]
use crate::mocks::*;

pub struct DeviceManager<B>
where
Expand Down Expand Up @@ -111,7 +111,7 @@ where
}

fn resolve_model(discovered_device: DiscoveredDevice) -> DiscoveredDevice {
match SOUNDCORE_NAME_MODEL_MAP
match SOUNDCORE_NAME_PRODUCT_CODE_MAP
.into_iter()
.find(|(k, _v)| discovered_device.descriptor.name.contains(**k))
{
Expand All @@ -132,7 +132,7 @@ pub struct DiscoveredDevice {
/// The BLE device descriptor.
pub descriptor: BLEDeviceDescriptor,
/// The model of the device, resolved using the device's advertised name.
pub model: Option<SupportedModels>,
pub model: Option<KnownProductCodes>,
}

#[cfg(all(
Expand Down
2 changes: 2 additions & 0 deletions soundcore-lib/src/models/auto_power.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use serde::{Deserialize, Serialize};
use typeshare::typeshare;

#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash)]
#[serde(rename_all = "camelCase", tag = "type")]
#[typeshare]
pub struct AutoPowerOff {
pub enabled: bool,
pub index: u8, //TODO: Search for possible values and map to enum
Expand Down
2 changes: 2 additions & 0 deletions soundcore-lib/src/models/device_color.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use derive_more::From;
use serde::{Deserialize, Serialize};
use typeshare::typeshare;

/// This u8 is a char which based on it fetches the apropriate image for the device (Reference: OtaBaseActivity/renderProductIcon).
/// Perhaps this can be internally mapped to our product images.
/// Further investigation is needed.
#[derive(
Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Default, Hash, From,
)]
#[typeshare]
pub struct DeviceColor(pub u8);
2 changes: 2 additions & 0 deletions soundcore-lib/src/models/hearing_protect.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use derive_more::From;
use serde::{Deserialize, Serialize};
use typeshare::typeshare;

#[derive(
Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Default, Hash, From,
)]
#[typeshare]
pub struct HearingProtect {
pub enabled: bool,
pub db: u8,
Expand Down
10 changes: 5 additions & 5 deletions soundcore-lib/src/models/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,25 @@ use std::sync::Arc;
use serde::{Deserialize, Serialize};
use typeshare::typeshare;

use crate::types::SupportedModels;
use crate::types::KnownProductCodes;

#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone, Hash)]
#[typeshare]
pub struct SerialNumber {
value: Arc<str>,
model: Option<SupportedModels>,
model: Option<KnownProductCodes>,
}

impl SerialNumber {
pub fn to_str(&self) -> &str {
&self.value
}

pub fn to_model(&self) -> Option<SupportedModels> {
pub fn to_model(&self) -> Option<KnownProductCodes> {
self.model
}

fn extract_model(value: &str) -> Option<SupportedModels> {
fn extract_model(value: &str) -> Option<KnownProductCodes> {
match value.get(0..4) {
Some(v) => ("A".to_owned() + v).parse().ok(),
None => None,
Expand Down Expand Up @@ -54,7 +54,7 @@ mod serial_number {
#[test]
fn returns_correct_model() {
let serial = SerialNumber::from("3040EAC356CCEEE8");
assert_eq!(serial.to_model(), Some(SupportedModels::A3040));
assert_eq!(serial.to_model(), Some(KnownProductCodes::A3040));
}

#[test]
Expand Down
15 changes: 8 additions & 7 deletions soundcore-lib/src/packets/command/sound_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,23 @@ use crate::{
devices::{A3040SoundModeUpdateCommand, A3951SoundModeUpdateCommand},
models::{ANCMode, SoundMode, TransparencyMode},
packets::Packet,
types::SupportedModels,
types::KnownProductCodes,
};

pub struct SoundModeCommandBuilder {
sound_mode: SoundMode,
model: SupportedModels,
model: KnownProductCodes,
}

impl SoundModeCommandBuilder {
pub fn new(sound_mode: SoundMode, model: SupportedModels) -> Self {
pub fn new(sound_mode: SoundMode, model: KnownProductCodes) -> Self {
Self { sound_mode, model }
}

pub fn build(self) -> Vec<u8> {
match self.model {
SupportedModels::A3040 => A3040SoundModeUpdateCommand::new(self.sound_mode).bytes(),
SupportedModels::A3951 => A3951SoundModeUpdateCommand::new(self.sound_mode).bytes(),
KnownProductCodes::A3040 => A3040SoundModeUpdateCommand::new(self.sound_mode).bytes(),
KnownProductCodes::A3951 => A3951SoundModeUpdateCommand::new(self.sound_mode).bytes(),
_ => self.find_builder(),
}
}
Expand All @@ -38,9 +38,10 @@ impl SoundModeCommandBuilder {

#[cfg(test)]
mod tests {
use super::*;
use crate::models::{ANCMode, CurrentSoundMode, CustomANCValue, SoundMode, TransparencyMode};

use super::*;

#[test]
fn test_find_builder() {
let sound_mode = SoundMode {
Expand All @@ -52,7 +53,7 @@ mod tests {
custom_anc: CustomANCValue::from_u8(0),
custom_trans: None,
};
let builder = SoundModeCommandBuilder::new(sound_mode, SupportedModels::A3027);
let builder = SoundModeCommandBuilder::new(sound_mode, KnownProductCodes::A3027);
let bytes = builder.build();
assert_eq!(bytes, [8, 238, 0, 0, 0, 6, 129, 14, 0, 2, 1, 0, 0, 142]);
}
Expand Down
Loading

0 comments on commit f6d0698

Please sign in to comment.