fix: updating position flags to be more readable
This commit is contained in:
@@ -6,10 +6,11 @@ import type { PositionValidation } from "@app/validation/config/position.tsx";
|
|||||||
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/js";
|
||||||
|
import { useCallback } from "react";
|
||||||
|
|
||||||
export const Position = () => {
|
export const Position = () => {
|
||||||
const { config, setWorkingConfig } = useDevice();
|
const { config, setWorkingConfig } = useDevice();
|
||||||
const { flagsValue, activeFlags, toggleFlag } = usePositionFlags(
|
const { flagsValue, activeFlags, toggleFlag, getAllFlags } = usePositionFlags(
|
||||||
config.position.positionFlags ?? 0,
|
config.position.positionFlags ?? 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -24,9 +25,12 @@ export const Position = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPositonFlagChange = (name: string) => {
|
const onPositonFlagChange = useCallback(
|
||||||
|
(name: string) => {
|
||||||
return toggleFlag(name as FlagName);
|
return toggleFlag(name as FlagName);
|
||||||
};
|
},
|
||||||
|
[toggleFlag],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DynamicForm<PositionValidation>
|
<DynamicForm<PositionValidation>
|
||||||
@@ -73,9 +77,10 @@ export const Position = () => {
|
|||||||
onValueChange: onPositonFlagChange,
|
onValueChange: onPositonFlagChange,
|
||||||
label: "Position Flags",
|
label: "Position Flags",
|
||||||
placeholder: "Select position flags...",
|
placeholder: "Select position flags...",
|
||||||
description: "Configuration options for Position messages",
|
description:
|
||||||
|
"Optional fields to include when assembling position messages. The more fields are selected, the larger the message will be leading to longer airtime usage and a higher risk of packet loss.",
|
||||||
properties: {
|
properties: {
|
||||||
enumValue: Protobuf.Config.Config_PositionConfig_PositionFlags,
|
enumValue: getAllFlags(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,10 +46,10 @@ const MultiSelectItem = ({
|
|||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<CheckboxPrimitive.Indicator>
|
<CheckboxPrimitive.Indicator className="mr-2">
|
||||||
<Check className="h-4 w-4 animate-in zoom-in duration-200" />
|
<Check className="h-4 w-4 animate-in zoom-in duration-200" />
|
||||||
</CheckboxPrimitive.Indicator>
|
</CheckboxPrimitive.Indicator>
|
||||||
<span className="ml-2">{children}</span>
|
{children}
|
||||||
</CheckboxPrimitive.Root>
|
</CheckboxPrimitive.Root>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,23 +1,27 @@
|
|||||||
import { useCallback, useMemo, useState } from "react";
|
import { useCallback, useMemo, useState } from "react";
|
||||||
|
|
||||||
export type FlagName =
|
const FLAGS = {
|
||||||
| "UNSET"
|
UNSET: 0,
|
||||||
| "ALTITUDE"
|
Altitude: 1,
|
||||||
| "ALTITUDE_MSL"
|
"Altitude is Mean Sea Level": 2,
|
||||||
| "GEOIDAL_SEPARATION"
|
"Altitude Geoidal Seperation": 4,
|
||||||
| "DOP"
|
"Dilution of precision (DOP) PDOP used by default": 8,
|
||||||
| "HVDOP"
|
"If DOP is set, use HDOP / VDOP values instead of PDOP": 16,
|
||||||
| "SATINVIEW"
|
"Number of satellites": 32,
|
||||||
| "SEQ_NO"
|
"Sequence number": 64,
|
||||||
| "TIMESTAMP"
|
Timestamp: 128,
|
||||||
| "HEADING"
|
"Vehicle heading": 256,
|
||||||
| "SPEED";
|
"Vehicle speed": 512,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type FlagName = keyof typeof FLAGS;
|
||||||
|
type FlagsObject = typeof FLAGS;
|
||||||
|
|
||||||
type UsePositionFlagsProps = {
|
type UsePositionFlagsProps = {
|
||||||
decode: (value: number) => FlagName[];
|
decode: (value: number) => FlagName[];
|
||||||
encode: (flagNames: FlagName[]) => number;
|
encode: (flagNames: FlagName[]) => number;
|
||||||
hasFlag: (value: number, flagName: FlagName) => boolean;
|
hasFlag: (value: number, flagName: FlagName) => boolean;
|
||||||
getAllFlags: () => FlagName[];
|
getAllFlags: () => FlagsObject;
|
||||||
isValidValue: (value: number) => boolean;
|
isValidValue: (value: number) => boolean;
|
||||||
flagsValue: number;
|
flagsValue: number;
|
||||||
activeFlags: FlagName[];
|
activeFlags: FlagName[];
|
||||||
@@ -27,30 +31,17 @@ type UsePositionFlagsProps = {
|
|||||||
clearFlags: () => void;
|
clearFlags: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const FLAGS_MAP: ReadonlyMap<FlagName, number> = new Map([
|
|
||||||
["UNSET", 0],
|
|
||||||
["ALTITUDE", 1],
|
|
||||||
["ALTITUDE_MSL", 2],
|
|
||||||
["GEOIDAL_SEPARATION", 4],
|
|
||||||
["DOP", 8],
|
|
||||||
["HVDOP", 16],
|
|
||||||
["SATINVIEW", 32],
|
|
||||||
["SEQ_NO", 64],
|
|
||||||
["TIMESTAMP", 128],
|
|
||||||
["HEADING", 256],
|
|
||||||
["SPEED", 512],
|
|
||||||
]);
|
|
||||||
|
|
||||||
export const usePositionFlags = (initialValue = 0): UsePositionFlagsProps => {
|
export const usePositionFlags = (initialValue = 0): UsePositionFlagsProps => {
|
||||||
const [flagsValue, setFlagsValue] = useState<number>(initialValue);
|
const [flagsValue, setFlagsValue] = useState<number>(initialValue);
|
||||||
|
|
||||||
const utils = useMemo(() => {
|
const utils = useMemo(() => {
|
||||||
const decode = (value: number): FlagName[] => {
|
const decode = (value: number): FlagName[] => {
|
||||||
if (value === 0) return ["UNSET"];
|
if (value === 0) return ["UNSET"];
|
||||||
|
|
||||||
const activeFlags: FlagName[] = [];
|
const activeFlags: FlagName[] = [];
|
||||||
for (const [name, flagValue] of FLAGS_MAP) {
|
for (const [name, flagValue] of Object.entries(FLAGS)) {
|
||||||
if (flagValue !== 0 && (value & flagValue) === flagValue) {
|
if (flagValue !== 0 && (value & flagValue) === flagValue) {
|
||||||
activeFlags.push(name);
|
activeFlags.push(name as FlagName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return activeFlags;
|
return activeFlags;
|
||||||
@@ -61,31 +52,24 @@ export const usePositionFlags = (initialValue = 0): UsePositionFlagsProps => {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return flagNames.reduce((acc, name) => {
|
return flagNames.reduce((acc, name) => {
|
||||||
const value = FLAGS_MAP.get(name);
|
const value = FLAGS[name];
|
||||||
if (value === undefined) {
|
|
||||||
throw new Error(`Invalid flag name: ${name}`);
|
|
||||||
}
|
|
||||||
return acc | value;
|
return acc | value;
|
||||||
}, 0);
|
}, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasFlag = (value: number, flagName: FlagName): boolean => {
|
const hasFlag = (value: number, flagName: FlagName): boolean => {
|
||||||
const flagValue = FLAGS_MAP.get(flagName);
|
const flagValue = FLAGS[flagName];
|
||||||
if (flagValue === undefined) {
|
|
||||||
throw new Error(`Invalid flag name: ${flagName}`);
|
|
||||||
}
|
|
||||||
return (value & flagValue) === flagValue;
|
return (value & flagValue) === flagValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getAllFlags = (): FlagName[] => {
|
const getAllFlags = (): FlagsObject => {
|
||||||
return Array.from(FLAGS_MAP.keys());
|
return FLAGS;
|
||||||
};
|
};
|
||||||
|
|
||||||
const isValidValue = (value: number): boolean => {
|
const isValidValue = (value: number): boolean => {
|
||||||
const maxValue = Array.from(FLAGS_MAP.values()).reduce(
|
const maxValue = Object.values(FLAGS)
|
||||||
(a, b) => a + b,
|
.filter((val) => val !== 0) // Exclude UNSET (0) from the calculation
|
||||||
0,
|
.reduce((acc, val) => acc | val, 0);
|
||||||
);
|
|
||||||
return Number.isInteger(value) && value >= 0 && value <= maxValue;
|
return Number.isInteger(value) && value >= 0 && value <= maxValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -99,18 +83,12 @@ export const usePositionFlags = (initialValue = 0): UsePositionFlagsProps => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const toggleFlag = useCallback((flagName: FlagName) => {
|
const toggleFlag = useCallback((flagName: FlagName) => {
|
||||||
const flagValue = FLAGS_MAP.get(flagName);
|
const flagValue = FLAGS[flagName];
|
||||||
if (flagValue === undefined) {
|
|
||||||
throw new Error(`Invalid flag name: ${flagName}`);
|
|
||||||
}
|
|
||||||
setFlagsValue((prev) => prev ^ flagValue);
|
setFlagsValue((prev) => prev ^ flagValue);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const setFlag = useCallback((flagName: FlagName, enabled: boolean) => {
|
const setFlag = useCallback((flagName: FlagName, enabled: boolean) => {
|
||||||
const flagValue = FLAGS_MAP.get(flagName);
|
const flagValue = FLAGS[flagName];
|
||||||
if (flagValue === undefined) {
|
|
||||||
throw new Error(`Invalid flag name: ${flagName}`);
|
|
||||||
}
|
|
||||||
setFlagsValue((prev) => (enabled ? prev | flagValue : prev & ~flagValue));
|
setFlagsValue((prev) => (enabled ? prev | flagValue : prev & ~flagValue));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user