Skip to content

Commit

Permalink
dont p
Browse files Browse the repository at this point in the history
  • Loading branch information
gmallios committed Mar 5, 2024
1 parent 3b1f759 commit 9ec6032
Show file tree
Hide file tree
Showing 16 changed files with 1,317 additions and 90 deletions.
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@
"react-chartjs-2": "^4.3.1",
"react-dom": "^18.2.0",
"tauri-plugin-log-api": "https://github.com/tauri-apps/tauri-plugin-log#v1",
"zustand": "^4.1.3"
"zustand": "^4.5.2"
},
"devDependencies": {
"@tauri-apps/cli": "^1.5.1",
"@testing-library/jest-dom": "^6.4.2",
"@testing-library/react": "^14.2.1",
"@types/node": "^18.7.10",
"@types/react": "^18.2.6",
"@types/react-dom": "^18.0.6",
Expand All @@ -45,8 +47,10 @@
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-react": "^7.33.2",
"jsdom": "^24.0.0",
"prettier": "^3.2.5",
"typescript": "^5.0.4",
"vite": "^4.3.1"
"vite": "^4.3.1",
"vitest": "^1.3.1"
}
}
4 changes: 4 additions & 0 deletions setup-vitest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import '@testing-library/jest-dom';
import { vi } from 'vitest';

vi.mock('zustand');
2 changes: 1 addition & 1 deletion soundcore-lib/examples/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const BT_ADDR: &str = "E8:EE:CC:56:C3:EA";
async fn main() {
let addr = BluetoothAdrr::from(BT_ADDR);
let dev = A3951::default().init(addr).await.unwrap();
let info = dev.get_info().await.unwrap();
let info = dev.get_status().await.unwrap();
println!("Device info: {:?}", info);
// println!("Device status: {:?}", info);
// let charging = dev.get_battery_charging().await.unwrap();
Expand Down
1 change: 1 addition & 0 deletions soundcore-lib/src/api/state.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod feature_set;
mod state;

pub use state::*;
17 changes: 17 additions & 0 deletions soundcore-lib/src/api/state/feature_set.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Proof of concept for splitting up the state into features
pub struct HearIDFeature {}

pub struct DeviceInfoFeature {
// fw, sn, button_model, host_device, side_tone, age_range,
}

pub struct SoundFeatures {
// bassup,
}

pub struct PowerFeatures {
// battery_level,
// battery_status,
// auto_power_off,
// power_on_battery_notice,
}
2 changes: 1 addition & 1 deletion soundcore-lib/src/devices/A3951Device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ impl SoundcoreDevice for A3951 {
async fn get_info(&self) -> Result<DeviceInfo, SoundcoreLibError> {
self.build_and_send_cmd(A3951_CMD_DEVICE_INFO, None).await?;
let resp = self.recv().await?;
if A3951_RESPONSE_VERIFICATION && A3951_RESPONSE_VERIFICATION {
if A3951_RESPONSE_VERIFICATION {
verify_resp(&resp)?;
}
Ok(Self::decode(self, &resp)?)
Expand Down
30 changes: 30 additions & 0 deletions soundcore-lib/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
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<dyn std::error::Error>> {
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(())
}
51 changes: 0 additions & 51 deletions soundcore-lib/src/packets/request/state.rs

This file was deleted.

52 changes: 52 additions & 0 deletions soundcore-lib/tests/a3040.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use soundcore_lib::{packets::ResponsePacket, types::SupportedModels};

#[test]
fn should_parse_state_update() {
let packet = ResponsePacket::from_bytes(&test_data::a3040::anc);
match packet {
Ok(ResponsePacket::DeviceState(state)) => {
// TODO: Assert state
assert_eq!(state.tag, SupportedModels::A3040);
println!("{:?}", state.data);
}
Err(err) => panic!("Failed to parse state update packet"),
_ => 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)) => {
todo!()
}
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"),
}
}
}
8 changes: 5 additions & 3 deletions soundcore-lib/tests/a3951.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use soundcore_lib::packets::ResponsePacket;
use soundcore_lib::{packets::ResponsePacket, types::SupportedModels};
use test_data::a3951::A3951_STATE_UPDATE_BYTES;

#[test]
fn parse_a3951_state_update() {
let packet = ResponsePacket::from_bytes(&A3951_STATE_UPDATE_BYTES).unwrap();
match packet {
ResponsePacket::DeviceState(_state) => {
// TODO
ResponsePacket::DeviceState(state) => {
// TODO: Assert state
assert_eq!(state.tag, SupportedModels::A3951);
println!("{:?}", state.data);
}
_ => panic!("Parsed as wrong packet type"),
}
Expand Down
7 changes: 4 additions & 3 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

use std::sync::Arc;

use log::info;
use log::{info, trace};
use mpsc::channel;
use tauri::async_runtime::{Mutex, RwLock};
use tauri::Manager;
Expand Down Expand Up @@ -143,8 +143,9 @@ async fn main() {
}

fn handle_bridge_output<R: tauri::Runtime>(resp: BridgeResponse, manager: &impl Manager<R>) {
info!("Received response from bridge: {:?}", resp);
manager.emit_all("bridge-response", resp).unwrap();
trace!("Received response from bridge, emitting event...");
trace!("Response: {:?}", resp);
manager.emit_all("async-bridge-event", resp).unwrap();
}

#[tauri::command]
Expand Down
45 changes: 45 additions & 0 deletions src/__mocks__/zustand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import * as zustand from 'zustand';
import { act } from '@testing-library/react';
import { afterEach } from 'node:test';
import { vi } from 'vitest';

const { create: actualCreate, createStore: actualCreateStore } =
await vi.importActual<typeof zustand>('zustand');

export const storeResetFns = new Set<() => void>();

const createUncurried = <T>(stateCreator: zustand.StateCreator<T>) => {
const store = actualCreate(stateCreator);
const initialState = store.getInitialState();
storeResetFns.add(() => {
store.setState(initialState, true);
});
return store;
};

export const create = (<T>(stateCreator: zustand.StateCreator<T>) => {
return typeof stateCreator === 'function' ? createUncurried(stateCreator) : createUncurried;
}) as typeof zustand.create;

const createStoreUncurried = <T>(stateCreator: zustand.StateCreator<T>) => {
const store = actualCreateStore(stateCreator);
const initialState = store.getInitialState();
storeResetFns.add(() => {
store.setState(initialState, true);
});
return store;
};

export const createStore = (<T>(stateCreator: zustand.StateCreator<T>) => {
return typeof stateCreator === 'function'
? createStoreUncurried(stateCreator)
: createStoreUncurried;
}) as typeof zustand.createStore;

afterEach(() => {
act(() => {
storeResetFns.forEach((resetFn) => {
resetFn();
});
});
});
13 changes: 4 additions & 9 deletions src/stores/baseSlice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ import { StateCreator, StoreApi } from 'zustand';
import { SoundcoreStoreSlices } from './useSoundcoreStore';
import { BridgeResponse } from '../types/tauri-backend';

export interface BaseSlice {
handleAsyncBridgeEvent: (e: Event<BridgeResponse>) => void;
}

export const createBaseSlice: StateCreator<SoundcoreStoreSlices, [], [], BaseSlice> = (
set,
get
) => ({
handleAsyncBridgeEvent: (e: Event<BridgeResponse>) => {
console.log('Handling async bridge event', e);

const payload = e.payload as BridgeResponse;
const kind = e.payload.kind as BridgeResponse['kind'];
const handler = bridgeResponseHandlers[kind];
Expand All @@ -28,11 +30,9 @@ type BridgeResponseHandlers = {
};
const bridgeResponseHandlers: BridgeResponseHandlers = {
newState: (payload, _set, get) => {
console.log('Handling new state', payload);
get().setStateFromBridgeResponse(payload);
},
scanResult: function (payload, _set, get): void {
console.log('Handling scan result', payload);
get().setLatestScan(payload);
},
connectionEstablished: function (_e, _set, _get): void {
Expand All @@ -45,8 +45,3 @@ const bridgeResponseHandlers: BridgeResponseHandlers = {
throw new Error('Function not implemented.');
}
};

// TODO: Add types
export interface BaseSlice {
handleAsyncBridgeEvent: (e: Event<BridgeResponse>) => void;
}
22 changes: 22 additions & 0 deletions src/stores/useSoundcoreStore.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { describe, it } from 'vitest';
import { useSoundcoreStore } from './useSoundcoreStore';
import { Event } from '@tauri-apps/api/event';
import { BridgeResponse } from '../types/tauri-backend';

describe('useSoundcoreStore', () => {
describe('handleAsyncBridgeEvent', () => {
it('should call the handler for the given kind', () => {
const store = useSoundcoreStore();
const event: Event<BridgeResponse> = {
event: 'test',
windowLabel: 'test',
id: 0,
payload: {
kind: 'scanResult',
payload: []
}
};
store.handleAsyncBridgeEvent(event);
});
});
});
14 changes: 14 additions & 0 deletions vitest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { defineConfig, mergeConfig } from 'vitest/config';
import viteConfig from './vite.config';

export default mergeConfig(
viteConfig,
defineConfig({
test: {
globals: true,
environment: 'jsdom',
setupFiles: ['./setup-vitest.ts'],
root: 'src/'
}
})
);
Loading

0 comments on commit 9ec6032

Please sign in to comment.