Skip to content

Commit

Permalink
cockpit-actions: Allow actions to be called from sources other than t…
Browse files Browse the repository at this point in the history
…he joystick
  • Loading branch information
rafaellehmkuhl committed Oct 2, 2024
1 parent 6ceade7 commit 6fc12b0
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 54 deletions.
80 changes: 35 additions & 45 deletions src/libs/joystick/protocols/cockpit-actions.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
/* eslint-disable vue/max-len */
/* eslint-disable prettier/prettier */
/* eslint-disable max-len */
import { v4 as uuid4 } from 'uuid'

import { slideToConfirm } from '@/libs/slide-to-confirm'
import { type JoystickProtocolActionsMapping,type JoystickState, type ProtocolAction, JoystickProtocol } from '@/types/joystick'
import { type ProtocolAction,JoystickProtocol } from '@/types/joystick'

/**
* Possible functions in the MAVLink `MANUAL_CONTROL` message protocol
Expand Down Expand Up @@ -67,54 +64,47 @@ interface CallbackEntry {
callback: CockpitActionCallback
}

// @ts-ignore: Typescript does not get that we are initializing the object dinamically
const actionsCallbacks: { [id in string]: CallbackEntry } = {}

export const registerActionCallback = (action: CockpitAction, callback: CockpitActionCallback): string => {
const id = uuid4()
actionsCallbacks[id] = { action, callback }
return id
}
export const unregisterActionCallback = (id: string): void => {
delete actionsCallbacks[id]
}

/**
* Responsible for routing cockpit actions
*/
export class CockpitActionsManager {
joystickState: JoystickState
currentActionsMapping: JoystickProtocolActionsMapping
activeButtonsActions: ProtocolAction[]
actionsJoystickConfirmRequired: Record<string, boolean>
actionsCallbacks: Record<string, CallbackEntry> = {}

registerActionCallback = (action: CockpitAction, callback: CockpitActionCallback): string => {
this.actionsCallbacks[action.id] = { action, callback }
return action.id
}

updateControllerData = (
state: JoystickState,
protocolActionsMapping: JoystickProtocolActionsMapping,
activeButtonsActions: ProtocolAction[],
actionsJoystickConfirmRequired: Record<string, boolean>
): void => {
this.joystickState = state
this.currentActionsMapping = protocolActionsMapping
this.activeButtonsActions = activeButtonsActions
this.actionsJoystickConfirmRequired = actionsJoystickConfirmRequired
unregisterActionCallback = (id: string): void => {
delete this.actionsCallbacks[id]
}

sendCockpitActions = (): void => {
if (!this.joystickState || !this.currentActionsMapping || !this.activeButtonsActions) return
executeActionCallback = (id: string): void => {
const callbackEntry = this.actionsCallbacks[id]
if (!callbackEntry) {
console.error(`Callback for action ${id} not found.`)
return
}

const actionsToCallback = this.activeButtonsActions.filter((a) => a.protocol === JoystickProtocol.CockpitAction)
Object.values(actionsCallbacks).forEach((entry) => {
if (actionsToCallback.map((a) => a.id).includes(entry.action.id)) {
console.log('Sending action', entry.action.name, '/ Require confirm:', this.actionsJoystickConfirmRequired[entry.action.id])
slideToConfirm(
entry.callback,
{
command: entry.action.name,
},
!this.actionsJoystickConfirmRequired[entry.action.id]
)
}
})
console.debug(`Executing action callback for action ${id}.`)
try {
callbackEntry.callback()
} catch (error) {
console.error(`Error executing action callback for action ${id}.`, error)
}
}
}

export const cockpitActionsManager = new CockpitActionsManager()

export const registerActionCallback = (action: CockpitAction, callback: CockpitActionCallback): string => {
return cockpitActionsManager.registerActionCallback(action, callback)
}

export const unregisterActionCallback = (id: string): void => {
cockpitActionsManager.unregisterActionCallback(id)
}

export const executeActionCallback = (id: string): void => {
cockpitActionsManager.executeActionCallback(id)
}
27 changes: 27 additions & 0 deletions src/stores/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import { useBlueOsStorage } from '@/composables/settingsSyncer'
import { MavType } from '@/libs/connection/m2r/messages/mavlink2rest-enum'
import { type JoystickEvent, EventType, joystickManager, JoystickModel } from '@/libs/joystick/manager'
import { allAvailableAxes, allAvailableButtons } from '@/libs/joystick/protocols'
import { CockpitActionsFunction, executeActionCallback } from '@/libs/joystick/protocols/cockpit-actions'
import { modifierKeyActions, otherAvailableActions } from '@/libs/joystick/protocols/other'
import { slideToConfirm } from '@/libs/slide-to-confirm'
import { Alert, AlertLevel } from '@/types/alert'
import {
type JoystickProtocolActionsMapping,
Expand Down Expand Up @@ -373,6 +375,31 @@ export const useControllerStore = defineStore('controller', () => {
}
}

const actionsToCallFromJoystick = ref<CockpitActionsFunction[]>([])
const addActionToCallFromJoystick = (actionId: CockpitActionsFunction): void => {
if (!actionsToCallFromJoystick.value.includes(actionId)) {
actionsToCallFromJoystick.value.push(actionId)
}
}

registerControllerUpdateCallback((joystickState, actionsMapping, activeActions, actionsConfirmRequired) => {
if (!joystickState || !actionsMapping || !activeActions || !actionsConfirmRequired) {
return
}

actionsToCallFromJoystick.value = []

const actionsToCallback = activeActions.filter((a) => a.protocol === JoystickProtocol.CockpitAction)
Object.values(actionsToCallback).forEach((a) => {
const callback = (): void => addActionToCallFromJoystick(a.id as CockpitActionsFunction)
slideToConfirm(callback, { command: a.name }, !actionsConfirmRequired[a.id])
})

if (enableForwarding.value) {
actionsToCallFromJoystick.value.forEach((a) => executeActionCallback(a as CockpitActionsFunction))
}
})

return {
registerControllerUpdateCallback,
enableForwarding,
Expand Down
9 changes: 0 additions & 9 deletions src/stores/mainVehicle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -531,9 +531,7 @@ export const useMainVehicleStore = defineStore('main-vehicle', () => {
})

const mavlinkManualControlManager = new MavlinkManualControlManager()
const cockpitActionsManager = new CockpitActionsManager()
controllerStore.registerControllerUpdateCallback(mavlinkManualControlManager.updateControllerData)
controllerStore.registerControllerUpdateCallback(cockpitActionsManager.updateControllerData)

// Loop to send MAVLink Manual Control messages
setInterval(() => {
Expand All @@ -549,13 +547,6 @@ export const useMainVehicleStore = defineStore('main-vehicle', () => {
}, 40)
setInterval(() => sendGcsHeartbeat(), 1000)

// Loop to send Cockpit Action messages
setInterval(() => {
if (controllerStore.enableForwarding) {
cockpitActionsManager.sendCockpitActions()
}
}, 10)

return {
arm,
takeoff,
Expand Down

0 comments on commit 6fc12b0

Please sign in to comment.