-
Notifications
You must be signed in to change notification settings - Fork 13
Serial ports config page completed #1097
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
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
7c93f06
implementation complete for serial ports config page
Kwash67 49fcbc1
formatting
Kwash67 c6b38dd
copilot suggestions
Kwash67 7ed8018
fixed missing ports
Kwash67 84559ff
formatting
Kwash67 b3dcad4
made requested changes
Kwash67 b3d7c81
fix linting
Kwash67 5a5ba25
fix linting
Kwash67 36c7f3e
format protocol options to include id
Kwash67 54838e8
Merge branch 'main' into 898-add-a-serial-ports-config-page
Kwash67 48e68be
trying to get the tests working
Kwash67 76a8a22
trying to get the tests working
Kwash67 5f307e5
linting
Kwash67 66a553e
Fix broken tests
1Blademaster File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,249 @@ | ||
| // Serial Ports Configuration Page | ||
| import { useEffect, useMemo } from "react" | ||
| import { | ||
| Table, | ||
| Select, | ||
| MultiSelect, | ||
| ScrollArea, | ||
| Text, | ||
| Tooltip, | ||
| } from "@mantine/core" | ||
| import { useListState } from "@mantine/hooks" | ||
|
|
||
| // Custom components, helpers and data | ||
| import apmParamDefsCopter from "../../../data/gen_apm_params_def_copter.json" | ||
| import apmParamDefsPlane from "../../../data/gen_apm_params_def_plane.json" | ||
| import { dec2bin } from "../../helpers/dataFormatters" | ||
|
|
||
| import { useSelector, useDispatch } from "react-redux" | ||
| import { selectAircraftType } from "../../redux/slices/droneInfoSlice" | ||
| import { | ||
| emitGetSerialPortsConfig, | ||
| emitSetSerialPortConfigParam, | ||
| selectSerialPortsConfig, | ||
| } from "../../redux/slices/configSlice" | ||
| import { emitSetState } from "../../redux/slices/droneConnectionSlice" | ||
| import { selectConnectedToDrone } from "../../redux/slices/droneConnectionSlice" | ||
|
|
||
| // Bitmask Select component for OPTIONS field. | ||
| function OptionsBitmaskSelect({ value, onChange, options }) { | ||
| const [selected, selectedHandler] = useListState([]) | ||
|
|
||
| useEffect(() => { | ||
| parseBitmask(value) | ||
| }, [value]) | ||
|
|
||
| function parseBitmask(bitmaskToParse) { | ||
| const binaryString = dec2bin(bitmaskToParse) | ||
| const selectedArray = [] | ||
|
|
||
| binaryString | ||
| .split("") | ||
| .reverse() | ||
| .forEach((bit, index) => { | ||
| if (bit === "1") { | ||
| selectedArray.push(`${index}`) | ||
| } | ||
| }) | ||
|
|
||
| selectedHandler.setState(selectedArray) | ||
| } | ||
|
|
||
| function createBitmask(value) { | ||
| const initialValue = 0 | ||
| const bitmask = value.reduce( | ||
| (accumulator, currentValue) => accumulator + 2 ** parseInt(currentValue), | ||
| initialValue, | ||
| ) | ||
| selectedHandler.setState(value) | ||
| onChange(bitmask) | ||
| } | ||
|
|
||
| const data = useMemo( | ||
| () => | ||
| options | ||
| ? Object.keys(options).map((key) => ({ | ||
| value: `${key}`, | ||
| label: `${options[key]}`, | ||
| })) | ||
| : [], | ||
| [options], | ||
| ) | ||
|
|
||
| return ( | ||
| <ScrollArea.Autosize className="max-h-24 min-w-[200px]"> | ||
| <MultiSelect | ||
| value={selected} | ||
| onChange={createBitmask} | ||
| data={data} | ||
| placeholder="Select options" | ||
| /> | ||
| </ScrollArea.Autosize> | ||
| ) | ||
| } | ||
|
|
||
| export default function SerialPorts() { | ||
| const dispatch = useDispatch() | ||
| const aircraftType = useSelector(selectAircraftType) | ||
| const serialPortsConfig = useSelector(selectSerialPortsConfig) | ||
| const connected = useSelector(selectConnectedToDrone) | ||
|
|
||
| // Helper to get paramDef for a given param_id | ||
| function getParamDef(param_id) { | ||
| if (aircraftType === 1) return apmParamDefsPlane[param_id] | ||
| if (aircraftType === 2) return apmParamDefsCopter[param_id] | ||
| return undefined | ||
| } | ||
|
Kwash67 marked this conversation as resolved.
|
||
|
|
||
| // Helper to handle param change | ||
| function handleParamChange(param_id, value) { | ||
| // Guard against null/undefined values from Mantine components | ||
| if (value === null || value === undefined) { | ||
| return | ||
| } | ||
| dispatch( | ||
| emitSetSerialPortConfigParam({ | ||
| param_id, | ||
| value: parseInt(value), | ||
|
Kwash67 marked this conversation as resolved.
|
||
| }), | ||
| ) | ||
| } | ||
|
|
||
| // Build serial port rows | ||
| const serialPortRows = useMemo( | ||
| () => | ||
| Object.entries(serialPortsConfig).map(([key, config]) => ({ | ||
| number: Number(key.split("_")[1]), | ||
| protocol: config.protocol, | ||
| baud: config.baud, | ||
| options: config.options, | ||
| })), | ||
| [serialPortsConfig], | ||
| ) | ||
|
|
||
| useEffect(() => { | ||
| if (connected) { | ||
| dispatch(emitSetState("config.serial_ports")) | ||
| dispatch(emitGetSerialPortsConfig()) | ||
| } | ||
| }, [connected, dispatch]) | ||
|
|
||
| return ( | ||
| <div className="p-4 overflow-auto"> | ||
| <Table withRowBorders={false} className="!w-fit"> | ||
| <Table.Thead> | ||
| <Table.Tr> | ||
| <Table.Th>Port</Table.Th> | ||
| <Table.Th>Baud Rate</Table.Th> | ||
| <Table.Th>Protocol</Table.Th> | ||
| <Table.Th>Options</Table.Th> | ||
| </Table.Tr> | ||
| </Table.Thead> | ||
| <Table.Tbody> | ||
| {serialPortRows.map((port) => { | ||
| const num = port.number | ||
| const protocolParam = `SERIAL${num}_PROTOCOL` | ||
| const baudParam = `SERIAL${num}_BAUD` | ||
| const optionsParam = `SERIAL${num}_OPTIONS` | ||
|
|
||
| const protocolDef = getParamDef(protocolParam) | ||
| const baudDef = getParamDef(baudParam) | ||
| const optionsDef = getParamDef(optionsParam) | ||
|
|
||
| const protocolOptions = protocolDef?.Values | ||
| ? Object.entries(protocolDef.Values).map(([value, label]) => ({ | ||
| value, | ||
| label: `${value}: ${label}`, | ||
| })) | ||
| : [] | ||
|
|
||
| // Baud rate handling | ||
| const baudOptions = baudDef?.Values | ||
| ? Object.entries(baudDef.Values).map(([value, label]) => ({ | ||
| value, | ||
| label: `${value}: ${label}`, | ||
| })) | ||
| : [] | ||
|
|
||
| return ( | ||
| <Table.Tr key={num} className="h-12"> | ||
| <Table.Td> | ||
| <Tooltip | ||
| label={protocolDef?.DisplayName || `Serial Port ${num}`} | ||
| position="top-start" | ||
| > | ||
| <Text fw={500}>SERIAL{num}</Text> | ||
| </Tooltip> | ||
| </Table.Td> | ||
| <Table.Td> | ||
| <Tooltip | ||
| label={ | ||
| <ScrollArea.Autosize className="max-h-48 max-w-80"> | ||
| <div> | ||
| {baudDef?.Description || "Baud rate selection"} | ||
| </div> | ||
| </ScrollArea.Autosize> | ||
| } | ||
| position="top" | ||
| multiline | ||
| > | ||
| <Select | ||
| data={baudOptions} | ||
| value={port.baud?.toString() || ""} | ||
| placeholder="Select baud" | ||
| className="min-w-[120px]" | ||
| onChange={(val) => handleParamChange(baudParam, val)} | ||
| /> | ||
| </Tooltip> | ||
| </Table.Td> | ||
| <Table.Td> | ||
| <Tooltip | ||
| label={ | ||
| <ScrollArea.Autosize className="max-h-48 max-w-80"> | ||
| {protocolDef?.Description || "Protocol selection"} | ||
| </ScrollArea.Autosize> | ||
| } | ||
| position="top" | ||
| multiline | ||
| > | ||
| <Select | ||
| data={protocolOptions} | ||
| value={port.protocol?.toString() || ""} | ||
| placeholder="Select protocol" | ||
| className="min-w-[180px]" | ||
| onChange={(val) => handleParamChange(protocolParam, val)} | ||
| /> | ||
| </Tooltip> | ||
| </Table.Td> | ||
| <Table.Td> | ||
| <Tooltip | ||
| label={ | ||
| <ScrollArea.Autosize className="max-h-48 max-w-80"> | ||
| {optionsDef?.Description || "Serial port options"} | ||
| </ScrollArea.Autosize> | ||
| } | ||
| position="top" | ||
| multiline | ||
| > | ||
| <div> | ||
| <OptionsBitmaskSelect | ||
| value={port.options || 0} | ||
| onChange={(val) => handleParamChange(optionsParam, val)} | ||
| options={optionsDef?.Bitmask} | ||
| /> | ||
| </div> | ||
| </Tooltip> | ||
| </Table.Td> | ||
| </Table.Tr> | ||
| ) | ||
| })} | ||
| </Table.Tbody> | ||
| </Table> | ||
|
|
||
| <Text size="md" fw={500} mt="md" c="dimmed"> | ||
| Note: Changes to the serial port settings will not take effect until the | ||
| board is rebooted. | ||
| </Text> | ||
| </div> | ||
| ) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.