Skip to content

Commit adc0031

Browse files
wip
Signed-off-by: Patrick José Pereira <patrickelectric@gmail.com>
1 parent 289eafb commit adc0031

File tree

8 files changed

+306
-13
lines changed

8 files changed

+306
-13
lines changed
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
<template>
2+
<v-card class="mt-5">
3+
<v-card-text>
4+
<v-alert
5+
v-if="has_crash"
6+
type="error"
7+
dense
8+
class="mb-4"
9+
>
10+
ArduPilot process exited with code {{ process_status.exit_code }}.
11+
Check your arguments and restart.
12+
</v-alert>
13+
<div
14+
v-for="(_, index) in entries"
15+
:key="index"
16+
class="d-flex align-center mb-2"
17+
>
18+
<v-text-field
19+
v-model="entries[index].name"
20+
label="Argument"
21+
placeholder="e.g. --home"
22+
outlined
23+
dense
24+
hide-details
25+
class="mr-2"
26+
/>
27+
<v-text-field
28+
v-model="entries[index].value"
29+
label="Value"
30+
placeholder="e.g. -27.563,-48.459,0.0,270.0"
31+
outlined
32+
dense
33+
hide-details
34+
class="mr-2"
35+
/>
36+
<v-btn
37+
icon
38+
color="error"
39+
@click="removeEntry(index)"
40+
>
41+
<v-icon>mdi-close-circle</v-icon>
42+
</v-btn>
43+
</div>
44+
<v-btn
45+
text
46+
color="primary"
47+
class="mt-2"
48+
@click="addEntry"
49+
>
50+
<v-icon left>
51+
mdi-plus
52+
</v-icon>
53+
Add argument
54+
</v-btn>
55+
</v-card-text>
56+
<v-card-actions>
57+
<v-btn
58+
style="margin: auto;"
59+
color="primary"
60+
:loading="restarting"
61+
:disabled="!has_changes"
62+
@click="saveAndRestart"
63+
>
64+
Save and restart
65+
</v-btn>
66+
</v-card-actions>
67+
</v-card>
68+
</template>
69+
70+
<script lang="ts">
71+
import Vue from 'vue'
72+
73+
import * as AutopilotManager from '@/components/autopilot/AutopilotManagerUpdater'
74+
import { fetchExtraArguments, fetchProcessStatus } from '@/components/autopilot/AutopilotManagerUpdater'
75+
import Notifier from '@/libs/notifier'
76+
import { OneMoreTime } from '@/one-more-time'
77+
import autopilot from '@/store/autopilot_manager'
78+
import { ProcessStatus } from '@/types/autopilot'
79+
import { autopilot_service } from '@/types/frontend_services'
80+
import back_axios from '@/utils/api'
81+
82+
const notifier = new Notifier(autopilot_service)
83+
84+
interface ArgumentEntry {
85+
name: string
86+
value: string
87+
}
88+
89+
export default Vue.extend({
90+
name: 'AutopilotExtraArguments',
91+
data() {
92+
return {
93+
entries: [] as ArgumentEntry[],
94+
fetch_extra_arguments_task: new OneMoreTime({ delay: 10000, disposeWith: this }),
95+
fetch_process_status_task: new OneMoreTime({ delay: 5000, disposeWith: this }),
96+
loaded: false,
97+
}
98+
},
99+
computed: {
100+
restarting(): boolean {
101+
return autopilot.restarting
102+
},
103+
stored_arguments(): Record<string, string> {
104+
return autopilot.extra_arguments
105+
},
106+
process_status(): ProcessStatus | null {
107+
return autopilot.process_status
108+
},
109+
has_crash(): boolean {
110+
const status = this.process_status
111+
return status !== null && !status.running
112+
&& status.exit_code !== null && status.exit_code !== 0
113+
},
114+
has_changes(): boolean {
115+
const current = this.entriesToDict()
116+
const stored = this.stored_arguments
117+
return JSON.stringify(current) !== JSON.stringify(stored)
118+
},
119+
},
120+
watch: {
121+
stored_arguments: {
122+
handler(new_args: Record<string, string>) {
123+
if (!this.loaded) {
124+
this.loadEntries(new_args)
125+
this.loaded = true
126+
}
127+
},
128+
immediate: true,
129+
},
130+
},
131+
mounted() {
132+
this.fetch_extra_arguments_task.setAction(fetchExtraArguments)
133+
this.fetch_process_status_task.setAction(fetchProcessStatus)
134+
},
135+
methods: {
136+
loadEntries(args: Record<string, string>): void {
137+
this.entries = Object.entries(args).map(([name, value]) => ({ name, value }))
138+
},
139+
entriesToDict(): Record<string, string> {
140+
const result: Record<string, string> = {}
141+
for (const entry of this.entries) {
142+
const name = entry.name.trim()
143+
if (name) {
144+
result[name] = entry.value.trim()
145+
}
146+
}
147+
return result
148+
},
149+
addEntry(): void {
150+
this.entries.push({ name: '', value: '' })
151+
},
152+
removeEntry(index: number): void {
153+
this.entries.splice(index, 1)
154+
},
155+
async saveAndRestart(): Promise<void> {
156+
const args = this.entriesToDict()
157+
try {
158+
await back_axios({
159+
method: 'put',
160+
url: `${autopilot.API_URL}/extra_arguments`,
161+
timeout: 10000,
162+
data: args,
163+
})
164+
autopilot.setExtraArguments(args)
165+
this.loaded = false
166+
} catch (error) {
167+
notifier.pushBackError('AUTOPILOT_EXTRA_ARGS_SAVE_FAIL', error)
168+
return
169+
}
170+
await AutopilotManager.restart()
171+
},
172+
},
173+
})
174+
</script>

core/frontend/src/components/autopilot/AutopilotManagerUpdater.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,34 @@ export async function fetchFirmwareVehicleType(): Promise<void> {
114114
}
115115
}
116116

117+
export async function fetchExtraArguments(): Promise<void> {
118+
try {
119+
const response = await back_axios({
120+
method: 'get',
121+
url: `${autopilot.API_URL}/extra_arguments`,
122+
timeout: 10000,
123+
})
124+
autopilot.setExtraArguments(response.data)
125+
} catch (error) {
126+
autopilot.setExtraArguments({})
127+
notifier.pushBackError('AUTOPILOT_EXTRA_ARGS_FETCH_FAIL', error)
128+
}
129+
}
130+
131+
export async function fetchProcessStatus(): Promise<void> {
132+
try {
133+
const response = await back_axios({
134+
method: 'get',
135+
url: `${autopilot.API_URL}/process_status`,
136+
timeout: 10000,
137+
})
138+
autopilot.setProcessStatus(response.data)
139+
} catch (error) {
140+
autopilot.setProcessStatus(null)
141+
notifier.pushBackError('AUTOPILOT_PROCESS_STATUS_FETCH_FAIL', error)
142+
}
143+
}
144+
117145
export async function availableFirmwares(vehicleType: Vehicle): Promise<Firmware[]> {
118146
return back_axios({
119147
method: 'get',

core/frontend/src/store/autopilot_manager.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ import {
55
import store from '@/store'
66
import {
77
AutopilotEndpoint, FirmwareInfo, FirmwareVehicleType,
8-
FlightController, SerialEndpoint,
8+
FlightController, ProcessStatus, SerialEndpoint,
99
} from '@/types/autopilot'
10+
import { Dictionary } from '@/types/common'
1011

1112
@Module({
1213
dynamic: true,
@@ -37,6 +38,10 @@ class AutopilotManagerStore extends VuexModule {
3738

3839
autopilot_serials: SerialEndpoint[] = []
3940

41+
extra_arguments: Dictionary<string> = {}
42+
43+
process_status: ProcessStatus | null = null
44+
4045
@Mutation
4146
setAutopilotSerialConfigurations(serials: SerialEndpoint[]): void {
4247
this.autopilot_serials = serials
@@ -83,6 +88,16 @@ class AutopilotManagerStore extends VuexModule {
8388
this.available_boards = boards
8489
this.updating_boards = false
8590
}
91+
92+
@Mutation
93+
setExtraArguments(arguments_: Dictionary<string>): void {
94+
this.extra_arguments = arguments_
95+
}
96+
97+
@Mutation
98+
setProcessStatus(process_status: ProcessStatus | null): void {
99+
this.process_status = process_status
100+
}
86101
}
87102

88103
export { AutopilotManagerStore }

core/frontend/src/types/autopilot.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,8 @@ export interface SerialEndpoint {
9898
port: string
9999
endpoint: string
100100
}
101+
102+
export interface ProcessStatus {
103+
running: boolean
104+
exit_code: number | null
105+
}

core/frontend/src/views/Autopilot.vue

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,16 @@
7474
</v-expansion-panel-content>
7575
</v-expansion-panel>
7676
</v-expansion-panels>
77+
<v-expansion-panels v-if="settings.is_pirate_mode && isLinuxFlightController">
78+
<v-expansion-panel>
79+
<v-expansion-panel-header>
80+
Extra Arguments
81+
</v-expansion-panel-header>
82+
<v-expansion-panel-content>
83+
<autopilot-extra-arguments />
84+
</v-expansion-panel-content>
85+
</v-expansion-panel>
86+
</v-expansion-panels>
7787
</v-card-text>
7888
<v-card-actions class="d-flex justify-end align-center flex-wrap">
7989
<v-spacer />
@@ -131,6 +141,7 @@ import Vue from 'vue'
131141
import ArduPilotBanner from '@/assets/img/banners/ArduPilot.svg'
132142
import OpenPilotBanner from '@/assets/img/banners/OpenPilot.svg'
133143
import PX4Banner from '@/assets/img/banners/PX4.svg'
144+
import AutopilotExtraArguments from '@/components/autopilot/AutopilotExtraArguments.vue'
134145
import * as AutopilotManager from '@/components/autopilot/AutopilotManagerUpdater'
135146
import {
136147
fetchAvailableBoards, fetchCurrentBoard, fetchFirmwareInfo, fetchFirmwareVehicleType, fetchVehicleType,
@@ -156,6 +167,7 @@ const notifier = new Notifier(autopilot_service)
156167
export default Vue.extend({
157168
name: 'Autopilot',
158169
components: {
170+
AutopilotExtraArguments,
159171
BoardChangeDialog,
160172
FirmwareManager,
161173
AutopilotSerialConfiguration,

core/services/ardupilot_manager/api/v1/routers/index.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import shutil
44
from functools import wraps
55
from pathlib import Path
6-
from typing import Any, Callable, List, Optional, Tuple
6+
from typing import Any, Callable, Dict, List, Optional, Tuple
77

88
from autopilot_manager import AutoPilotManager
99
from commonwealth.mavlink_comm.exceptions import (
@@ -24,6 +24,7 @@
2424
FlightController,
2525
FlightControllerFlags,
2626
Parameters,
27+
ProcessStatus,
2728
Serial,
2829
SITLFrame,
2930
Vehicle,
@@ -136,6 +137,24 @@ async def set_sitl_frame(frame: SITLFrame) -> Any:
136137
return autopilot.set_sitl_frame(frame)
137138

138139

140+
@index_router_v1.get("/extra_arguments", response_model=Dict[str, str], summary="Get extra ArduPilot arguments.")
141+
@index_to_http_exception
142+
def get_extra_arguments() -> Any:
143+
return autopilot.get_extra_arguments()
144+
145+
146+
@index_router_v1.put("/extra_arguments", status_code=status.HTTP_200_OK, summary="Set extra ArduPilot arguments.")
147+
@index_to_http_exception
148+
def set_extra_arguments(arguments: Dict[str, str] = Body(...)) -> Any:
149+
autopilot.set_extra_arguments(arguments)
150+
151+
152+
@index_router_v1.get("/process_status", response_model=ProcessStatus, summary="Get ArduPilot process status.")
153+
@index_to_http_exception
154+
def get_process_status() -> Any:
155+
return autopilot.get_process_status()
156+
157+
139158
@index_router_v1.get("/firmware_vehicle_type", response_model=str, summary="Get firmware vehicle type.")
140159
@index_to_http_exception
141160
async def get_firmware_vehicle_type() -> Any:

0 commit comments

Comments
 (0)