Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement magnetometer toggle for firmware #1114

Merged
merged 22 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions gui/public/i18n/en/translation.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,12 @@ tracker-infos-hardware_identifier = Hardware ID
tracker-infos-imu = IMU Sensor
tracker-infos-board_type = Main board
tracker-infos-network_version = Protocol Version
tracker-infos-magnetometer = Magnetometer
tracker-infos-magnetometer-status = { $status ->
*[0] Not supported
[1] Disabled
[2] Enabled
}

## Tracker settings
tracker-settings-back = Go back to trackers list
Expand All @@ -200,6 +206,13 @@ tracker-settings-mounting_section-edit = Edit mounting
tracker-settings-drift_compensation_section = Allow drift compensation
tracker-settings-drift_compensation_section-description = Should this tracker compensate for its drift when drift compensation is enabled?
tracker-settings-drift_compensation_section-edit = Allow drift compensation
tracker-settings-use_mag = Allow magnetometer on this tracker
# Multiline!
tracker-settings-use_mag-description =
Should this tracker use magnetometer to reduce drift when magnetometer usage is allowed? <b>Please don't shutdown your tracker while toggling this!</b>

You need to allow magnetometer usage first, <magSetting>click here to go to the setting</magSetting>.
tracker-settings-use_mag-label = Allow magnetometer
# The .<name> means it's an attribute and it's related to the top key.
# In this case that is the settings for the assignment section.
tracker-settings-name_section = Tracker name
Expand Down Expand Up @@ -354,6 +367,11 @@ settings-general-tracker_mechanics-save_mounting_reset-description =
Saves the automatic mounting reset calibrations for the trackers between restarts. Useful
when wearing a suit where trackers don't move between sessions. <b>Not recommended for normal users!</b>
settings-general-tracker_mechanics-save_mounting_reset-enabled-label = Save mounting reset
settings-general-tracker_mechanics-use_mag_on_all_trackers = Use magnetometer on all IMU trackers that support it
settings-general-tracker_mechanics-use_mag_on_all_trackers-description =
Uses magnetometer on all trackers that have a compatible firmware for it, reducing drift in stable magnetic environments.
Can be disabled per tracker in the tracker's settings. <b>Please don't shutdown any of the trackers while toggling this!</b>
settings-general-tracker_mechanics-use_mag_on_all_trackers-label = Use magnetometer on trackers

## FK/Tracking settings
settings-general-fk_settings = Tracking settings
Expand Down
24 changes: 16 additions & 8 deletions gui/src/components/commons/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export function CheckBox({
control,
outlined,
name,
loading,
// input props
disabled,
...props
Expand All @@ -19,6 +20,7 @@ export function CheckBox({
variant?: 'checkbox' | 'toggle';
color?: 'primary' | 'secondary' | 'tertiary';
outlined?: boolean;
loading?: boolean;
} & React.HTMLProps<HTMLInputElement>) {
const classes = useMemo(() => {
const vriantsMap = {
Expand All @@ -32,7 +34,9 @@ export function CheckBox({
toggle: {
checkbox: classNames('hidden'),
toggle: classNames('w-10 h-4 rounded-full relative transition-colors'),
pin: classNames('h-2 w-2 bg-background-10 rounded-full absolute m-1'),
pin: classNames(
'h-2 w-2 bg-background-10 rounded-full absolute m-1 transition-opacity'
),
},
};
return vriantsMap[variant];
Expand Down Expand Up @@ -60,7 +64,8 @@ export function CheckBox({
'w-full py-3 flex gap-2 items-center text-standard-bold',
{
'px-3': outlined,
'cursor-pointer': !disabled,
'cursor-pointer': !disabled || !loading,
'cursor-default': disabled || loading,
}
)}
>
Expand All @@ -71,23 +76,26 @@ export function CheckBox({
name={name}
className={classes.checkbox}
type="checkbox"
disabled={disabled}
disabled={disabled || loading}
{...props}
/>
{variant === 'toggle' && (
<div
className={classNames(classes.toggle, {
'bg-accent-background-30': value && !disabled,
'bg-accent-background-30': value && !disabled && !loading,
'bg-accent-background-50': value && disabled,
'bg-accent-background-30 animate-pulse': loading && !disabled,
'bg-background-50':
(!value && color == 'primary') || color == 'secondary',
'bg-background-40': !value && color == 'tertiary',
((!value && color == 'primary') || color == 'secondary') &&
!loading,
'bg-background-40': !value && color == 'tertiary' && !loading,
})}
>
<div
className={classNames(classes.pin, {
'left-0': !value,
'right-0': value,
'left-0': !value && !loading,
'opacity-0': loading,
'right-0': value && !loading,
'bg-background-30': disabled,
})}
></div>
Expand Down
5 changes: 5 additions & 0 deletions gui/src/components/settings/pages/GeneralSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
SettingsPagePaneLayout,
} from '@/components/settings/SettingsPageLayout';
import { HandsWarningModal } from '@/components/settings/HandsWarningModal';
import { MagnetometerToggleSetting } from './MagnetometerToggleSetting';
import { DriftCompensationModal } from '@/components/settings/DriftCompensationModal';

interface SettingsForm {
Expand Down Expand Up @@ -808,6 +809,10 @@ export function GeneralSettings() {
'settings-general-tracker_mechanics-save_mounting_reset-enabled-label'
)}
/>
<MagnetometerToggleSetting
settingType="general"
id="mechanics-magnetometer"
/>
</>
</SettingsPagePaneLayout>
<SettingsPagePaneLayout
Expand Down
160 changes: 160 additions & 0 deletions gui/src/components/settings/pages/MagnetometerToggleSetting.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import { CheckBox } from '@/components/commons/Checkbox';
import { Typography } from '@/components/commons/Typography';
import { useWebsocketAPI } from '@/hooks/websocket-api';
import { Localized, useLocalization } from '@fluent/react';
import { useCallback, useEffect, useRef, useState } from 'react';
import { useForm } from 'react-hook-form';
import {
ChangeMagToggleRequestT,
DeviceIdT,
MagToggleRequestT,
MagToggleResponseT,
RpcMessage,
TrackerIdT,
} from 'solarxr-protocol';
import { Link } from 'react-router-dom';

interface MagnetometerToggleForm {
magToggle: boolean;
}

export function MagnetometerToggleSetting({
trackerNum,
deviceId,
settingType,
id,
}: {
trackerNum?: number;
deviceId?: number;
settingType: 'general' | 'tracker';
id?: string;
}) {
const { l10n } = useLocalization();
const { sendRPCPacket, useRPCPacket } = useWebsocketAPI();
const originalValue = useRef<boolean | null>(null);
// used to disable the tracker specific toggle if false
const [globalToggle, setGlobalToggle] = useState(false);
const [waitingMag, setWaitingMag] = useState(false);
const { control, watch, handleSubmit, reset } =
useForm<MagnetometerToggleForm>({
defaultValues: { magToggle: settingType === 'tracker' },
});

const onSubmit = useCallback(
(values: MagnetometerToggleForm) => {
if (originalValue.current === values.magToggle) return;
setWaitingMag(true);
const req = new ChangeMagToggleRequestT();
if (trackerNum !== undefined) {
const id = new TrackerIdT(
deviceId ? new DeviceIdT(deviceId) : undefined,
trackerNum
);
req.trackerId = id;
}

req.enable = values.magToggle;
sendRPCPacket(RpcMessage.ChangeMagToggleRequest, req);
},
[trackerNum, deviceId]
);

useEffect(() => {
const subscription = watch(() => handleSubmit(onSubmit)());
return () => subscription.unsubscribe();
}, []);

useEffect(() => {
const req = new MagToggleRequestT();
if (trackerNum !== undefined) {
const id = new TrackerIdT(
deviceId ? new DeviceIdT(deviceId) : undefined,
trackerNum
);
req.trackerId = id;
sendRPCPacket(RpcMessage.MagToggleRequest, new MagToggleRequestT());
}
sendRPCPacket(RpcMessage.MagToggleRequest, req);
}, [trackerNum, deviceId]);

useRPCPacket(RpcMessage.MagToggleResponse, (mag: MagToggleResponseT) => {
if (trackerNum !== undefined && mag.trackerId?.trackerNum === undefined) {
setGlobalToggle(mag.enable);
}
if (
mag.trackerId?.trackerNum !== trackerNum ||
mag.trackerId?.deviceId?.id !== deviceId
) {
return;
}
originalValue.current = mag.enable;
setWaitingMag(false);
reset({ magToggle: mag.enable });
});

return settingType === 'general' ? (
<>
<div className="flex flex-col pt-5 pb-3" id={id}>
<Typography bold>
{l10n.getString(
'settings-general-tracker_mechanics-use_mag_on_all_trackers'
)}
</Typography>
<Localized
id="settings-general-tracker_mechanics-use_mag_on_all_trackers-description"
elems={{ b: <b></b> }}
>
<Typography
color="secondary"
whitespace="whitespace-pre-line"
></Typography>
</Localized>
</div>
<CheckBox
variant="toggle"
outlined
control={control}
loading={waitingMag}
name="magToggle"
label={l10n.getString(
'settings-general-tracker_mechanics-use_mag_on_all_trackers-label'
)}
/>
</>
) : (
<div className="flex flex-col gap-2 w-full mt-3" id={id}>
<Typography variant="section-title">
{l10n.getString('tracker-settings-use_mag')}
</Typography>
<Localized
id="tracker-settings-use_mag-description"
elems={{
b: <b></b>,
magSetting: (
<Link
to="/settings/trackers"
state={{ scrollTo: 'mechanics-magnetometer' }}
className="underline"
></Link>
),
}}
>
<Typography
color="secondary"
whitespace="whitespace-pre-line"
></Typography>
</Localized>
<div className="flex">
<CheckBox
variant="toggle"
outlined
loading={waitingMag}
disabled={!globalToggle}
name="magToggle"
control={control}
label={l10n.getString('tracker-settings-use_mag-label')}
/>
</div>
</div>
);
}
20 changes: 20 additions & 0 deletions gui/src/components/tracker/TrackerSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { SingleTrackerBodyAssignmentMenu } from './SingleTrackerBodyAssignmentMe
import { TrackerCard } from './TrackerCard';
import { Quaternion } from 'three';
import { useAppContext } from '@/hooks/app';
import { MagnetometerToggleSetting } from '@/components/settings/pages/MagnetometerToggleSetting';

const rotationsLabels: [Quaternion, string][] = [
[rotationToQuatMap.BACK, 'tracker-rotation-back'],
Expand Down Expand Up @@ -276,6 +277,18 @@ export function TrackerSettingsPage() {
{tracker?.device?.hardwareInfo?.boardType || '--'}
</Typography>
</div>
<div className="flex justify-between">
<Typography color="secondary">
{l10n.getString('tracker-infos-magnetometer')}
</Typography>
<Typography>
{tracker?.tracker.info?.magnetometer === undefined
? '--'
: l10n.getString('tracker-infos-magnetometer-status', {
status: tracker.tracker.info.magnetometer,
})}
</Typography>
</div>
<div className="flex justify-between">
<Typography color="secondary">
{l10n.getString('tracker-infos-network_version')}
Expand Down Expand Up @@ -403,6 +416,13 @@ export function TrackerSettingsPage() {
</div>
</div>
)}
{tracker?.tracker.info?.isImu && (
<MagnetometerToggleSetting
settingType="tracker"
trackerNum={tracker.tracker.trackerId?.trackerNum}
deviceId={tracker.tracker.trackerId?.deviceId?.id}
/>
)}
<div className="flex flex-col gap-2 w-full mt-3">
<Typography variant="section-title">
{l10n.getString('tracker-settings-name_section')}
Expand Down
2 changes: 1 addition & 1 deletion server/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ configure<com.diffplug.gradle.spotless.SpotlessExtension> {
"java.util.*,kotlin.math.*,dev.slimevr.autobone.errors.*" +
",io.github.axisangles.ktmath.*,kotlinx.atomicfu.*" +
",dev.slimevr.tracking.trackers.*,dev.slimevr.desktop.platform.ProtobufMessages.*" +
",com.illposed.osc.*,android.app.*",
",solarxr_protocol.rpc.*,kotlinx.coroutines.*,com.illposed.osc.*,android.app.*",
"ij_kotlin_allow_trailing_comma" to true,
)
val ktlintVersion = "1.2.1"
Expand Down
1 change: 1 addition & 0 deletions server/core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ dependencies {
implementation("org.java-websocket:Java-WebSocket:1.+")
implementation("com.melloware:jintellitype:1.+")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")

// Jitpack
implementation("com.github.SlimeVR:oscquery-kt:566a0cba58")
Expand Down
10 changes: 0 additions & 10 deletions server/core/src/main/java/dev/slimevr/config/ServerConfig.java

This file was deleted.

Loading