diff --git a/manager-app/src/async_bridge/command.rs b/manager-app/src/async_bridge/command.rs index cb5673b..fa08c8b 100644 --- a/manager-app/src/async_bridge/command.rs +++ b/manager-app/src/async_bridge/command.rs @@ -22,3 +22,11 @@ pub struct SetSoundModePayload { pub addr: BluetoothAdrr, pub sound_mode: SoundMode, } + +#[derive(Debug, Deserialize, Clone)] +#[typeshare] +#[serde(rename_all = "camelCase")] +pub enum SetEqualizerPayload { + SetCustomEqualizer, + SetEqualizerPreset, +} \ No newline at end of file diff --git a/manager-ui/src/components/EqualizerCard/equalizer.tsx b/manager-ui/src/components/EqualizerCard/equalizer.tsx index 5ac9a92..d45e73b 100644 --- a/manager-ui/src/components/EqualizerCard/equalizer.tsx +++ b/manager-ui/src/components/EqualizerCard/equalizer.tsx @@ -1,18 +1,19 @@ -import { ChartData } from 'chart.js'; -import { useCallback, useState } from 'react'; -import { Line } from 'react-chartjs-2'; -import 'chartjs-plugin-dragdata'; import { - Chart as ChartJS, CategoryScale, + Chart as ChartJS, + ChartData, + Filler, + Legend, LinearScale, - PointElement, LineElement, + PointElement, Title, - Tooltip, - Legend, - Filler + Tooltip } from 'chart.js'; +import { useCallback, useState } from 'react'; +import { Line } from 'react-chartjs-2'; +import 'chartjs-plugin-dragdata'; +import { Button } from '@mui/material'; ChartJS.register( CategoryScale, @@ -66,6 +67,12 @@ export const Equalizer = ({ bands, input, onEqualizerChange }: EqualizerProps): console.log('Equalizer output:', newDataSet); }; + const onResetClick = () => { + const newDataSet = Array(bands).fill(0); + setDataSet(newDataSet); + onEqualizerChange(newDataSet); + }; + //@ts-expect-error: no type found for this event const onHover = useCallback((e) => { const point = e?.chart.getElementsAtEventForMode(e, 'nearest', { intersect: true }, false); @@ -111,6 +118,7 @@ export const Equalizer = ({ bands, input, onEqualizerChange }: EqualizerProps): return ( <> + ); }; diff --git a/manager-ui/src/components/EqualizerCard/equalizerCard.tsx b/manager-ui/src/components/EqualizerCard/equalizerCard.tsx index 0b87a3b..de96b76 100644 --- a/manager-ui/src/components/EqualizerCard/equalizerCard.tsx +++ b/manager-ui/src/components/EqualizerCard/equalizerCard.tsx @@ -1,6 +1,6 @@ -import { Paper } from '@mui/material'; +import { Collapse, MenuItem, Paper, Select, SelectChangeEvent, Stack } from '@mui/material'; import { Equalizer } from './equalizer'; -import { SoundcoreDeviceState } from '@generated-types/soundcore-lib'; +import { EQProfile, SoundcoreDeviceState } from '@generated-types/soundcore-lib'; import { useCallback } from 'react'; export interface EqualizerCardProps { @@ -8,11 +8,15 @@ export interface EqualizerCardProps { } export const EqualizerCard = ({ state }: EqualizerCardProps): JSX.Element => { - const onEqualizerChange = useCallback((output: number[]) => { + const onCustomEqualizerChange = useCallback((output: number[]) => { console.log('Equalizer output:', output); console.log('Equalizer output mapped:', mapRangeArray(output, -6, 6, 0, 240)); }, []); + const onSelectedEqProfileChange = (e: SelectChangeEvent) => { + console.log('Selected EQ profile:', e.target.value); + }; + const mapRange = ( value: number, inMin: number, @@ -40,21 +44,35 @@ export const EqualizerCard = ({ state }: EqualizerCardProps): JSX.Element => { } else { valueArr = state.eqConfiguration.value.eq.values; } - console.log('EQ values:', valueArr); return mapRangeArray(valueArr, 0, 240, -6, 6); }; - console.log('Mapped EQ values:', getMappedEqValues()); + const eqProfiles = Object.keys(EQProfile).filter((item) => { + return isNaN(Number(item)); + }); + + const isOnCustom = state.eqConfiguration.value.profile === EQProfile.Custom; return ( - {state.featureSet.equalizerFeatures && ( - - )} + + + {state.featureSet.equalizerFeatures && ( + + + + )} + ); }; diff --git a/manager-ui/src/types/tauri-backend.d.ts b/manager-ui/src/types/tauri-backend.d.ts index 7462b55..b67c9c1 100644 --- a/manager-ui/src/types/tauri-backend.d.ts +++ b/manager-ui/src/types/tauri-backend.d.ts @@ -24,6 +24,11 @@ export type BridgeCommand = | { command: 'disconnectAll'; payload?: undefined } | { command: 'setSoundMode'; payload: SetSoundModePayload }; +export enum SetEqualizerPayload { + SetCustomEqualizer = 'setCustomEqualizer', + SetEqualizerPreset = 'setEqualizerPreset' +} + export type BridgeResponse = | { kind: 'scanResult'; payload: DiscoveredDevice[] } | { kind: 'connectionEstablished'; payload: TaggedStateResponse } diff --git a/soundcore-lib/src/devices/a3040/eq_update_command.rs b/soundcore-lib/src/devices/a3040/eq_update_command.rs index 2fa402f..5312531 100644 --- a/soundcore-lib/src/devices/a3040/eq_update_command.rs +++ b/soundcore-lib/src/devices/a3040/eq_update_command.rs @@ -10,11 +10,13 @@ impl Packet for A3040EqUpdateCommand { fn command(&self) -> [u8; 7] { match self.bass_up.0 { true => [0x08, 0xEE, 0x00, 0x00, 0x00, 0x02, 0x84], - false => todo!(), + false => [0x08, 0xEE, 0x00, 0x00, 0x00, 0x03, 0x87], } } fn payload(&self) -> Vec { + // 2 bytes profile - FEFE - Custom + // todo!() } } diff --git a/soundcore-lib/src/main.rs b/soundcore-lib/src/main.rs new file mode 100644 index 0000000..dba710e --- /dev/null +++ b/soundcore-lib/src/main.rs @@ -0,0 +1,33 @@ +use env_logger::{Builder, Target}; +use log::LevelFilter; + +use soundcore_lib::ble::{BLEConnectionFactory, BLEConnectionManager}; +use soundcore_lib::device_manager::create_device_manager; + +#[tokio::main] +async fn main() -> Result<(), Box> { + Builder::new() + .target(Target::Stdout) + .filter_level(LevelFilter::Trace) + .init(); + let manager = create_device_manager().await; + let scan_res = manager.ble_scan(None).await?; + println!("{:?}", scan_res); + let device = scan_res + .iter() + .find(|d| d.descriptor.name.contains("Q45")) + .unwrap(); + let connection = manager.connect(device.clone()).await?; + + let mut state_channel = connection.state_channel().await; + + while let Ok(()) = state_channel.changed().await { + println!("{:?}", state_channel.borrow_and_update()); + } + // let registry = BtlePlugDeviceRegistry::new().await?; + // let scan_res = registry.scan(None).await?; + // println!("{:?}", scan_res); + // let q45 = scan_res.iter().find(|d| d.name.contains("Q45")).unwrap(); + // let _connection = registry.connect(q45.clone(), None).await?; + Ok(()) +} diff --git a/soundcore-lib/src/parsers/packet_header.rs b/soundcore-lib/src/parsers/packet_header.rs index 8bc53bb..45c977b 100644 --- a/soundcore-lib/src/parsers/packet_header.rs +++ b/soundcore-lib/src/parsers/packet_header.rs @@ -34,7 +34,7 @@ fn parse_packet_kind<'a, E: ParseError<'a>>(bytes: &'a [u8]) -> ParseResult { + // TODO: Assert state + assert_eq!(state.tag, SupportedModels::A3040); + println!("{:?}", state.data); + } + Err(err) => panic!("Failed to parse state update packet, error: {:X?}", err), + _ => panic!("Parsed as wrong packet type"), + } +} + +#[test] +fn should_parse_sound_mode_update_packet() { + // Normal + // { + // let packet = ResponsePacket::from_bytes(&test_data::a3040::SOUND_MODE_UPDATE_NORMAL); + // match packet { + // Ok(ResponsePacket::SoundModeUpdate(state)) => { + // assert_eq!(state.0.current, CurrentSoundMode::Normal); + // } + // Err(_err) => panic!("Failed to parse state update packet"), + // _ => panic!("Parsed as wrong packet type"), + // } + // } + // // Noise Cancelling + // { + // let packet = ResponsePacket::from_bytes(&test_data::a3040::SOUND_MODE_UPDATE_NOISE_CANCELLING); + // match packet { + // Ok(ResponsePacket::SoundModeUpdate(state)) => { + // todo!() + // } + // Err(_err) => panic!("Failed to parse state update packet"), + // _ => panic!("Parsed as wrong packet type"), + // } + // } + // // Transparency + // { + // let packet = ResponsePacket::from_bytes(&test_data::a3040::SOUND_MODE_UPDATE_TRANSPARENCY); + // match packet { + // Ok(ResponsePacket::SoundModeUpdate(state)) => { + // todo!() + // } + // Err(_err) => panic!("Failed to parse state update packet"), + // _ => panic!("Parsed as wrong packet type"), + // } + // } +} diff --git a/test_data/src/a3040.rs b/test_data/src/a3040.rs index 467dfca..b5b9974 100644 --- a/test_data/src/a3040.rs +++ b/test_data/src/a3040.rs @@ -10,6 +10,18 @@ pub const A3040_STATE_UPDATE_BYTES: [u8; 152] = [ 0x78, 0x78, 0x78, 0x78, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x57, ]; +pub const UNKN: [u8; 152] = [ + 0x9, 0xFF, 0x0, 0x0, 0x1, 0x1, 0x1, 0x98, 0x0, 0x5, 0xFF, 0x30, 0x36, 0x2E, 0x33, 0x34, 0x33, + 0x30, 0x34, 0x30, 0x45, 0x41, 0x43, 0x33, 0x35, 0x36, 0x43, 0x43, 0x45, 0x45, 0x45, 0x38, 0x2, + 0x0, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x0, 0x0, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x0, 0x0, 0x4, 0x4, 0x7, 0x7, 0x1, 0x51, 0x1, 0x0, 0x0, 0x3, 0xFF, 0x0, 0x0, + 0xFF, 0x1, 0x31, 0x0, 0x1, 0xFF, 0x0, 0x1, 0x1, 0x0, 0x5A, 0x0, 0x1, 0x1, 0x0, 0x2, 0x0, 0x32, + 0xFF, 0x0, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x0, 0x0, 0x3C, 0x3C, 0x3C, 0x3C, + 0x3C, 0x3C, 0x3C, 0x3C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3C, 0x3C, 0x3C, 0x3C, 0xB4, 0x3C, + 0xB4, 0x3C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5C, +]; + pub const anc: [u8; 152] = [ 0x9, 0xFF, 0x0, 0x0, 0x1, 0x1, 0x1, 0x98, 0x0, 0x2, 0xFF, 0x30, 0x36, 0x2E, 0x33, 0x34, 0x33, 0x30, 0x34, 0x30, 0x45, 0x41, 0x43, 0x33, 0x35, 0x36, 0x43, 0x43, 0x45, 0x45, 0x45, 0x38, 0x0, @@ -59,8 +71,17 @@ pub const max_eq: [u8; 152] = [ 0x7C, 0x7C, 0x7C, 0x7E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x77, ]; -pub const SOUND_MODE_UPDATE_NOISE_CANCELLING: [u8; 16] = [0x9, 0xFF, 0x0, 0x0, 0x1, 0x6, 0x1, 0x10, 0x0, 0x0, 0x51, 0x1, 0x1, 0x0, 0x5, 0x78]; -pub const SOUND_MODE_UPDATE_TRANSPARENCY: [u8; 16] = [0x9, 0xFF, 0x0, 0x0, 0x1, 0x6, 0x1, 0x10, 0x0, 0x1, 0x50, 0x1, 0x1, 0x0, 0x5, 0x78]; -pub const SOUND_MODE_UPDATE_NORMAL: [u8; 16] = [0x9, 0xFF, 0x0, 0x0, 0x1, 0x6, 0x1, 0x10, 0x0, 0x2, 0x50, 0x1, 0x1, 0x0, 0x5, 0x79]; -pub const BASS_UP_UPDATE_ENABLE: [u8; 12] = [0x9, 0xFF, 0x0, 0x0, 0x1, 0x2, 0x1, 0xC, 0x0, 0x2, 0x0, 0x1A]; -pub const BASS_UP_UPDATE_DISABLE: [u8; 12] = [0x9, 0xFF, 0x0, 0x0, 0x1, 0x2, 0x1, 0xC, 0x0, 0xFE, 0xFE, 0x14]; \ No newline at end of file +pub const SOUND_MODE_UPDATE_NOISE_CANCELLING: [u8; 16] = [ + 0x9, 0xFF, 0x0, 0x0, 0x1, 0x6, 0x1, 0x10, 0x0, 0x0, 0x51, 0x1, 0x1, 0x0, 0x5, 0x78, +]; +pub const SOUND_MODE_UPDATE_TRANSPARENCY: [u8; 16] = [ + 0x9, 0xFF, 0x0, 0x0, 0x1, 0x6, 0x1, 0x10, 0x0, 0x1, 0x50, 0x1, 0x1, 0x0, 0x5, 0x78, +]; +pub const SOUND_MODE_UPDATE_NORMAL: [u8; 16] = [ + 0x9, 0xFF, 0x0, 0x0, 0x1, 0x6, 0x1, 0x10, 0x0, 0x2, 0x50, 0x1, 0x1, 0x0, 0x5, 0x79, +]; +pub const BASS_UP_UPDATE_ENABLE: [u8; 12] = + [0x9, 0xFF, 0x0, 0x0, 0x1, 0x2, 0x1, 0xC, 0x0, 0x2, 0x0, 0x1A]; +pub const BASS_UP_UPDATE_DISABLE: [u8; 12] = [ + 0x9, 0xFF, 0x0, 0x0, 0x1, 0x2, 0x1, 0xC, 0x0, 0xFE, 0xFE, 0x14, +]; diff --git a/test_data/src/lib.rs b/test_data/src/lib.rs index 07c375f..b5838d8 100644 --- a/test_data/src/lib.rs +++ b/test_data/src/lib.rs @@ -1,2 +1,2 @@ +pub mod a3040; pub mod a3951; -pub mod a3040; \ No newline at end of file