Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { SemVer } from 'semver'
import Notifier from '@/libs/notifier'
import autopilot_data from '@/store/autopilot'
import autopilot from '@/store/autopilot_manager'
import { Firmware, Vehicle } from '@/types/autopilot'
import { Firmware, SITLFrame, Vehicle } from '@/types/autopilot'
import { Dictionary } from '@/types/common'
import { autopilot_service } from '@/types/frontend_services'
import back_axios from '@/utils/api'
Expand Down Expand Up @@ -114,6 +114,20 @@ export async function fetchFirmwareVehicleType(): Promise<void> {
}
}

export async function fetchSitlFrame(): Promise<void> {
try {
const response: AxiosResponse = await back_axios({
method: 'get',
url: `${autopilot.API_URL}/sitl_frame`,
timeout: 10000,
})
autopilot.setSitlFrame(response.data as SITLFrame)
} catch (error) {
autopilot.setSitlFrame(null)
notifier.pushBackError('AUTOPILOT_SITL_FRAME_FETCH_FAIL', error)
}
}

Comment on lines +117 to +130

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why not using the return back_axios({/*...*/}).then(/*...*/).catch(/*...*/) pattern used in the similar functions below?

export async function availableFirmwares(vehicleType: Vehicle): Promise<Firmware[]> {
return back_axios({
method: 'get',
Expand Down
100 changes: 100 additions & 0 deletions core/frontend/src/components/autopilot/SitlConfiguration.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<template>
<v-card
elevation="0"
class="pa-2"
>
<v-select
:value="autopilot.sitl_frame"
:items="sitl_frame_options"
:disabled="autopilot.restarting || setting"
:loading="autopilot.restarting || setting"
label="SITL frame"
class="ma-1 pa-0"
@change="changeSitlFrame"
/>
<v-snackbar
v-model="show_success"
color="success"
timeout="3000"
>
SITL frame set, autopilot restarted
<template #action="{ attrs }">
<v-btn
text
v-bind="attrs"
@click="show_success = false"
>
Close
</v-btn>
</template>
</v-snackbar>
</v-card>
</template>

<script lang="ts">
import Vue from 'vue'

import { fetchSitlFrame, restart } from '@/components/autopilot/AutopilotManagerUpdater'
import Notifier from '@/libs/notifier'
import { OneMoreTime } from '@/one-more-time'
import autopilot from '@/store/autopilot_manager'
import { SITLFrame } from '@/types/autopilot'
import { autopilot_service } from '@/types/frontend_services'
import back_axios from '@/utils/api'

const notifier = new Notifier(autopilot_service)

export default Vue.extend({
name: 'SitlConfiguration',
data() {
return {
autopilot,
fetch_sitl_frame_task: new OneMoreTime({ delay: 5000, disposeWith: this }),
setting: false,
show_success: false,
}
},
computed: {
sitl_frame_options(): {value: SITLFrame, text: string}[] {
return Object.values(SITLFrame)
.filter((frame) => frame !== SITLFrame.UNDEFINED)
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
.map((frame) => ({ value: frame, text: frame }))
.sort((a, b) => a.text.localeCompare(b.text))
},
},
mounted() {
this.fetch_sitl_frame_task.setAction(fetchSitlFrame)
},
beforeDestroy() {
autopilot.setSitlFrame(null)
},
methods: {
async changeSitlFrame(frame: SITLFrame): Promise<void> {
this.setting = true
try {
await back_axios({
method: 'post',
url: `${autopilot.API_URL}/sitl_frame`,
params: { frame },
timeout: 10000,
})
} catch (error) {
notifier.pushBackError('AUTOPILOT_SITL_FRAME_SET_FAIL', error)
return
} finally {
this.setting = false
}

// The new frame is only picked up at SITL launch, so restart so it takes effect.
// The next fetchSitlFrame poll will update the store once SITL is back up.
// restart() pushes its own error notification on failure.
try {
await restart()
this.show_success = true
} catch {
// already surfaced by restart()
}
},
},
})
</script>
11 changes: 10 additions & 1 deletion core/frontend/src/store/autopilot_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
import store from '@/store'
import {
AutopilotEndpoint, FirmwareInfo, FirmwareVehicleType,
FlightController, SerialEndpoint,
FlightController, SerialEndpoint, SITLFrame,
} from '@/types/autopilot'

@Module({
Expand All @@ -29,6 +29,8 @@ class AutopilotManagerStore extends VuexModule {

firmware_vehicle_type: FirmwareVehicleType | null = null

sitl_frame: SITLFrame | null = null

updating_endpoints = true

updating_boards = true
Expand Down Expand Up @@ -72,6 +74,13 @@ class AutopilotManagerStore extends VuexModule {
this.firmware_vehicle_type = firmware_vehicle_type
}

@Mutation
setSitlFrame(sitl_frame: SITLFrame | null): void {
// UNDEFINED means "no frame selected" — collapse it to null so consumers
// (e.g. the SITL <v-select>) have a single sentinel to handle.
this.sitl_frame = sitl_frame === SITLFrame.UNDEFINED ? null : sitl_frame
}

@Mutation
setAvailableEndpoints(available_endpoints: AutopilotEndpoint[]): void {
this.available_endpoints = available_endpoints
Expand Down
56 changes: 56 additions & 0 deletions core/frontend/src/types/autopilot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,62 @@ export enum Platform {
SITL_ARM = 'SITL_arm_linux_gnueabihf',
}

// Mirrors the SITLFrame enum from
// core/services/ardupilot_manager/typedefs.py
export enum SITLFrame {
QUADPLANE = 'quadplane',
XPLANE = 'xplane',
FIREFLY = 'firefly',
PLUS_CONFIG = '+',
QUAD = 'quad',
COPTER = 'copter',
X_CONFIG = 'x',
BFXREV = 'bfxrev',
BFX = 'bfx',
DJIX = 'djix',
CWX = 'cwx',
HEXA = 'hexa',
HEXA_CWX = 'hexa-cwx',
HEXA_DJI = 'hexa-dji',
OCTA = 'octa',
OCTA_CWX = 'octa-cwx',
OCTA_DJI = 'octa-dji',
OCTA_QUAD_CWX = 'octa-quad-cwx',
DODECA_HEXA = 'dodeca-hexa',
TRI = 'tri',
Y_SIX = 'y6',
HELI = 'heli',
HELI_DUAL = 'heli-dual',
HELI_COMPOUND = 'heli-compound',
SINGLECOPTER = 'singlecopter',
COAXCOPTER = 'coaxcopter',
ROVER = 'rover',
ROVER_SKID = 'rover-skid',
ROVER_VECTORED = 'rover-vectored',
BALANCEBOT = 'balancebot',
SAILBOAT = 'sailboat',
MOTORBOAT = 'motorboat',
MOTORBOAT_SKID = 'motorboat-skid',
CRRCSIM = 'crrcsim',
JSBSIM = 'jsbsim',
FLIGHTAXIS = 'flightaxis',
GAZEBO = 'gazebo',
LAST_LETTER = 'last_letter',
TRACKER = 'tracker',
BALLOON = 'balloon',
PLANE = 'plane',
CALIBRATION = 'calibration',
VECTORED = 'vectored',
VECTORED_6DOF = 'vectored_6dof',
SILENTWINGS = 'silentwings',
MORSE = 'morse',
AIRSIM = 'airsim',
SCRIMMAGE = 'scrimmage',
WEBOTS = 'webots',
JSON = 'JSON',
UNDEFINED = 'undefined',
}

export enum EndpointType {
udpin = 'udpin',
udpout = 'udpout',
Expand Down
15 changes: 15 additions & 0 deletions core/frontend/src/views/Autopilot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
<v-expansion-panels v-if="is_sitl">
<v-expansion-panel>
<v-expansion-panel-header>
SITL configuration
</v-expansion-panel-header>
<v-expansion-panel-content>
<sitl-configuration />
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
<v-expansion-panels v-if="settings.is_pirate_mode && isLinuxFlightController">
<v-expansion-panel>
<v-expansion-panel-header>
Expand Down Expand Up @@ -139,6 +149,7 @@ import AutopilotSerialConfiguration from '@/components/autopilot/AutopilotSerial
import BoardChangeDialog from '@/components/autopilot/BoardChangeDialog.vue'
import FirmwareManager from '@/components/autopilot/FirmwareManager.vue'
import MasterEndpointManager from '@/components/autopilot/MasterEndpointManager.vue'
import SitlConfiguration from '@/components/autopilot/SitlConfiguration.vue'
import NotSafeOverlay from '@/components/common/NotSafeOverlay.vue'
import { MavAutopilot } from '@/libs/MAVLink2Rest/mavlink2rest-ts/messages/mavlink2rest-enum'
import Notifier from '@/libs/notifier'
Expand All @@ -161,6 +172,7 @@ export default Vue.extend({
AutopilotSerialConfiguration,
NotSafeOverlay,
MasterEndpointManager,
SitlConfiguration,
},
data() {
return {
Expand Down Expand Up @@ -221,6 +233,9 @@ export default Vue.extend({
is_external_board(): boolean {
return autopilot.current_board?.name === 'Manual'
},
is_sitl(): boolean {
return autopilot.current_board?.name === 'SITL'
},
current_board(): FlightController | null {
return autopilot.current_board
},
Expand Down
6 changes: 6 additions & 0 deletions core/services/ardupilot_manager/api/v1/routers/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ async def set_sitl_frame(frame: SITLFrame) -> Any:
return autopilot.set_sitl_frame(frame)


@index_router_v1.get("/sitl_frame", response_model=SITLFrame, summary="Get current SITL Frame type.")
@index_to_http_exception
async def get_sitl_frame() -> Any:
return autopilot.current_sitl_frame


@index_router_v1.get("/firmware_vehicle_type", response_model=str, summary="Get firmware vehicle type.")
@index_to_http_exception
async def get_firmware_vehicle_type() -> Any:
Expand Down
Loading