Skip to content

Commit bc875f5

Browse files
joystick: restore MANUAL_CONTROL axes saved by a newer version
1.19 persisted those axes as data-lake ids, and this version still sends MAVLink. Re-run the conversion when the vehicle sync replaces the mapping so a stick that arrives after boot is not left at zero.
1 parent b587d83 commit bc875f5

4 files changed

Lines changed: 124 additions & 6 deletions

File tree

src/libs/joystick/protocols.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { type ProtocolAction, JoystickProtocolActionsMapping } from '@/types/joy
22

33
import { availableCockpitActions } from './protocols/cockpit-actions'
44
import { availableDataLakeActions } from './protocols/data-lake'
5+
import { migrateDataLakeAxesToMavlinkManualControl } from './protocols/data-lake-axis-migration'
56
import {
67
availableMavlinkManualControlButtonFunctions,
78
mavlinkManualControlAxes,
@@ -30,5 +31,5 @@ export const allAvailableButtons = (): ProtocolAction[] => {
3031
export const performJoystickMappingMigrations = (
3132
mappings: JoystickProtocolActionsMapping[]
3233
): JoystickProtocolActionsMapping[] => {
33-
return migrateMavlinkManualControlButtons(mappings)
34+
return migrateDataLakeAxesToMavlinkManualControl(migrateMavlinkManualControlButtons(mappings))
3435
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { type JoystickProtocolActionsMapping, JoystickProtocol } from '@/types/joystick'
2+
3+
// Inverse of 1.19's migrateMavlinkManualControlAxes: that version persisted these data-lake ids
4+
// and 1.18 still drives MANUAL_CONTROL from the MAVLink axis actions.
5+
const dataLakeManualControlAxisById: Record<
6+
string,
7+
{
8+
/**
9+
*
10+
*/
11+
protocol: JoystickProtocol.MAVLinkManualControl
12+
/**
13+
*
14+
*/
15+
id: string
16+
/**
17+
*
18+
*/
19+
name: string
20+
}
21+
> = {
22+
'inputs/mavlink/axis-x': { protocol: JoystickProtocol.MAVLinkManualControl, id: 'axis_x', name: 'Axis X' },
23+
'inputs/mavlink/axis-y': { protocol: JoystickProtocol.MAVLinkManualControl, id: 'axis_y', name: 'Axis Y' },
24+
'inputs/mavlink/axis-z': { protocol: JoystickProtocol.MAVLinkManualControl, id: 'axis_z', name: 'Axis Z' },
25+
'inputs/mavlink/axis-r': { protocol: JoystickProtocol.MAVLinkManualControl, id: 'axis_r', name: 'Axis R' },
26+
'inputs/mavlink/axis-s': { protocol: JoystickProtocol.MAVLinkManualControl, id: 'axis_s', name: 'Axis S' },
27+
'inputs/mavlink/axis-t': { protocol: JoystickProtocol.MAVLinkManualControl, id: 'axis_t', name: 'Axis T' },
28+
}
29+
30+
/**
31+
* Turns 1.19 data-lake MANUAL_CONTROL axis bindings back into MAVLink axis actions.
32+
* @param {JoystickProtocolActionsMapping[]} mappings - Stored joystick mappings
33+
* @returns {JoystickProtocolActionsMapping[]} The mappings, with those axes restored
34+
*/
35+
export const migrateDataLakeAxesToMavlinkManualControl = (
36+
mappings: JoystickProtocolActionsMapping[]
37+
): JoystickProtocolActionsMapping[] => {
38+
const migratedMappings = JSON.parse(JSON.stringify(mappings)) as JoystickProtocolActionsMapping[]
39+
mappings.forEach((mapping, mappingIndex) => {
40+
Object.entries(mapping.axesCorrespondencies ?? {}).forEach(([axisIndex, axisConfig]) => {
41+
if (axisConfig.action?.protocol !== JoystickProtocol.DataLakeVariable) return
42+
const replacement = dataLakeManualControlAxisById[axisConfig.action.id]
43+
if (!replacement) return
44+
migratedMappings[mappingIndex].axesCorrespondencies[axisIndex as unknown as number].action = replacement
45+
})
46+
})
47+
return migratedMappings
48+
}

src/stores/controller.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,17 @@ export const useControllerStore = defineStore('controller', () => {
8383
if (migrated) protocolMapping.value = migrated
8484
})
8585

86-
// Run schema migrations on the current mapping
87-
const migratedArray = performJoystickMappingMigrations([protocolMapping.value])
88-
if (migratedArray.length > 0) {
89-
protocolMapping.value = migratedArray[0]
90-
}
86+
// Re-run when the vehicle sync replaces the mapping so 1.19's data-lake MANUAL_CONTROL axes
87+
// are turned back into the MAVLink actions this version still sends.
88+
watch(
89+
protocolMapping,
90+
(mapping) => {
91+
const [migrated] = performJoystickMappingMigrations([mapping])
92+
if (JSON.stringify(migrated) === JSON.stringify(toRaw(mapping))) return
93+
protocolMapping.value = migrated
94+
},
95+
{ immediate: true }
96+
)
9197

9298
const cockpitStdMappings = computed<typeof availableGamepadToCockpitMaps>(() => {
9399
const mappings = {} as typeof availableGamepadToCockpitMaps
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { expect, test } from 'vitest'
2+
3+
import { migrateDataLakeAxesToMavlinkManualControl } from '@/libs/joystick/protocols/data-lake-axis-migration'
4+
import { type JoystickProtocolActionsMapping, CockpitModifierKeyOption, JoystickProtocol } from '@/types/joystick'
5+
6+
const mappingWithAxes = (
7+
axesCorrespondencies: JoystickProtocolActionsMapping['axesCorrespondencies']
8+
): JoystickProtocolActionsMapping => ({
9+
name: 't',
10+
hash: 'h',
11+
axesCorrespondencies,
12+
buttonsCorrespondencies: {
13+
[CockpitModifierKeyOption.regular]: {},
14+
[CockpitModifierKeyOption.shift]: {},
15+
},
16+
})
17+
18+
test('turns 1.19 data-lake manual-control axes back into MAVLink axes', () => {
19+
const [migrated] = migrateDataLakeAxesToMavlinkManualControl([
20+
mappingWithAxes({
21+
0: {
22+
action: { protocol: JoystickProtocol.DataLakeVariable, id: 'inputs/mavlink/axis-x', name: 'Axis X' },
23+
min: 1000,
24+
max: -1000,
25+
},
26+
1: {
27+
action: { protocol: JoystickProtocol.DataLakeVariable, id: 'inputs/mavlink/axis-y', name: 'Axis Y' },
28+
min: -1000,
29+
max: 1000,
30+
},
31+
}),
32+
])
33+
34+
expect(migrated.axesCorrespondencies[0].action).toMatchObject({
35+
protocol: JoystickProtocol.MAVLinkManualControl,
36+
id: 'axis_x',
37+
})
38+
expect(migrated.axesCorrespondencies[0].min).toBe(1000)
39+
expect(migrated.axesCorrespondencies[1].action.id).toBe('axis_y')
40+
})
41+
42+
test('leaves already-MAVLink axes and unrelated data-lake axes alone', () => {
43+
const [migrated] = migrateDataLakeAxesToMavlinkManualControl([
44+
mappingWithAxes({
45+
0: {
46+
action: { protocol: JoystickProtocol.MAVLinkManualControl, id: 'axis_x', name: 'Axis X' },
47+
min: -1000,
48+
max: 1000,
49+
},
50+
1: {
51+
action: { protocol: JoystickProtocol.DataLakeVariable, id: 'camera-zoom', name: 'Camera Zoom' },
52+
min: 0,
53+
max: 1,
54+
},
55+
}),
56+
])
57+
58+
expect(migrated.axesCorrespondencies[0].action.id).toBe('axis_x')
59+
expect(migrated.axesCorrespondencies[1].action).toMatchObject({
60+
protocol: JoystickProtocol.DataLakeVariable,
61+
id: 'camera-zoom',
62+
})
63+
})

0 commit comments

Comments
 (0)