Skip to content
Merged
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
37 changes: 36 additions & 1 deletion ostool-server/src/api/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,9 @@ fn normalize_boot_config(boot: &mut BootConfig) -> Result<(), ApiError> {
match boot {
BootConfig::Uboot(profile) => {
normalize_optional_string(&mut profile.dtb_name);
normalize_optional_string(&mut profile.kernel_load_addr);
normalize_optional_string(&mut profile.fit_load_addr);
normalize_optional_string(&mut profile.bootm_addr);
normalize_optional_string(&mut profile.board_ip);
normalize_optional_string(&mut profile.server_ip);
normalize_optional_string(&mut profile.netmask);
Expand Down Expand Up @@ -1647,7 +1650,8 @@ mod tests {
};
use crate::{
api::models::{
BoardPowerStatusResponse, BoardRuntimeStatusResponse, SessionDetailResponse,
AdminBoardUpsertRequest, BoardPowerStatusResponse, BoardRuntimeStatusResponse,
SessionDetailResponse,
},
build_app_state,
config::{
Expand Down Expand Up @@ -3301,6 +3305,37 @@ mod tests {
assert_eq!(profile.netmask.as_deref(), Some("255.255.255.0"));
}

#[test]
fn normalize_board_upsert_request_trims_uboot_load_addresses() {
let request = AdminBoardUpsertRequest {
id: Some("demo".into()),
board_type: "demo".into(),
tags: vec![],
notes: None,
disabled: false,
serial: None,
power_management: PowerManagementConfig::Custom(CustomPowerManagement {
power_on_cmd: "echo on".into(),
power_off_cmd: "echo off".into(),
}),
boot: BootConfig::Uboot(crate::config::UbootProfile {
kernel_load_addr: Some(" 0x80200000 ".into()),
fit_load_addr: Some(" ".into()),
bootm_addr: Some(" 0x82200000 ".into()),
..Default::default()
}),
};

let request = super::normalize_board_upsert_request(request).unwrap();
let BootConfig::Uboot(profile) = request.boot else {
panic!("expected uboot profile");
};

assert_eq!(profile.kernel_load_addr.as_deref(), Some("0x80200000"));
assert_eq!(profile.fit_load_addr, None);
assert_eq!(profile.bootm_addr.as_deref(), Some("0x82200000"));
}

#[tokio::test]
async fn session_file_list_supports_multiple_paths_and_overwrite() {
let app = test_router().await;
Expand Down
33 changes: 33 additions & 0 deletions ostool-server/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,12 @@ pub struct UbootProfile {
pub use_tftp: bool,
pub dtb_name: Option<String>,
#[serde(default)]
pub kernel_load_addr: Option<String>,
#[serde(default)]
pub fit_load_addr: Option<String>,
#[serde(default)]
pub bootm_addr: Option<String>,
#[serde(default)]
pub network_mode: UbootNetworkMode,
#[serde(default)]
pub board_ip: Option<String>,
Expand Down Expand Up @@ -722,6 +728,33 @@ network_mode = "static_ip"
assert_eq!(value["boot"]["dtb_name"], json!("board.dtb"));
}

#[test]
fn board_config_uboot_profile_supports_load_addresses() {
let config = r#"
id = "demo-1"
board_type = "demo"

[power_management]
kind = "custom"
power_on_cmd = "echo on"
power_off_cmd = "echo off"

[boot]
kind = "uboot"
kernel_load_addr = "0x80200000"
fit_load_addr = "0x82200000"
bootm_addr = "0x82200000"
"#;

let decoded: BoardConfig = toml::from_str(config).unwrap();
let BootConfig::Uboot(profile) = decoded.boot else {
panic!("expected uboot profile");
};
assert_eq!(profile.kernel_load_addr.as_deref(), Some("0x80200000"));
assert_eq!(profile.fit_load_addr.as_deref(), Some("0x82200000"));
assert_eq!(profile.bootm_addr.as_deref(), Some("0x82200000"));
}

#[test]
fn board_config_round_trip_supports_virtual_power_management() {
let board = BoardConfig {
Expand Down
3 changes: 3 additions & 0 deletions ostool-server/webui/src/types/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ export interface UbootProfile {
kind: "uboot";
use_tftp: boolean;
dtb_name: string | null;
kernel_load_addr: string | null;
fit_load_addr: string | null;
bootm_addr: string | null;
network_mode: UbootNetworkMode;
board_ip: string | null;
server_ip: string | null;
Expand Down
24 changes: 24 additions & 0 deletions ostool-server/webui/src/views/BoardEditorView.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ function makeBoard(id = "demo-board"): BoardConfig {
kind: "uboot",
use_tftp: true,
dtb_name: null,
kernel_load_addr: null,
fit_load_addr: null,
bootm_addr: null,
network_mode: "dhcp",
board_ip: null,
server_ip: null,
Expand All @@ -104,6 +107,9 @@ function makeStaticIpBoard(id = "static-board"): BoardConfig {
kind: "uboot",
use_tftp: true,
dtb_name: null,
kernel_load_addr: "0x80200000",
fit_load_addr: "0x82200000",
bootm_addr: "0x82200000",
network_mode: "static_ip",
board_ip: "192.168.10.20",
server_ip: "192.168.10.2",
Expand Down Expand Up @@ -225,6 +231,9 @@ describe("BoardEditorView", () => {
kind: "uboot",
use_tftp: false,
dtb_name: null,
kernel_load_addr: null,
fit_load_addr: null,
bootm_addr: null,
network_mode: "dhcp",
board_ip: null,
server_ip: null,
Expand Down Expand Up @@ -275,6 +284,9 @@ describe("BoardEditorView", () => {
await wrapper.get('input[placeholder="当前 serverip"]').setValue("192.168.10.2");
await wrapper.get('input[placeholder="当前 netmask"]').setValue("255.255.255.0");
await wrapper.get('input[placeholder="未配置"]').setValue("192.168.10.1");
await wrapper.get('input[placeholder="例如 0x80200000"]').setValue("0x80200000");
await wrapper.get('input[placeholder="例如 0x82200000"]').setValue("0x82200000");
await wrapper.get('input[placeholder="默认跟随 FIT load addr"]').setValue("0x82200000");

const saveButton = wrapper.findAll("button").find((button) => button.text() === "保存配置");
await saveButton!.trigger("click");
Expand All @@ -286,6 +298,9 @@ describe("BoardEditorView", () => {
kind: "uboot",
use_tftp: true,
dtb_name: null,
kernel_load_addr: "0x80200000",
fit_load_addr: "0x82200000",
bootm_addr: "0x82200000",
network_mode: "static_ip",
board_ip: "192.168.10.20",
server_ip: "192.168.10.2",
Expand Down Expand Up @@ -317,6 +332,15 @@ describe("BoardEditorView", () => {
expect((wrapper.get('input[placeholder="未配置"]').element as HTMLInputElement).value).toBe(
"192.168.10.1",
);
expect((wrapper.get('input[placeholder="例如 0x80200000"]').element as HTMLInputElement).value).toBe(
"0x80200000",
);
expect((wrapper.get('input[placeholder="例如 0x82200000"]').element as HTMLInputElement).value).toBe(
"0x82200000",
);
expect(
(wrapper.get('input[placeholder="默认跟随 FIT load addr"]').element as HTMLInputElement).value,
).toBe("0x82200000");
});

it("updates a board and keeps blank id as null in the payload", async () => {
Expand Down
34 changes: 32 additions & 2 deletions ostool-server/webui/src/views/BoardEditorView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ interface BoardEditorFormState {
boot_kind: BootKind;
use_tftp: boolean;
dtb_name: string;
kernel_load_addr: string;
fit_load_addr: string;
bootm_addr: string;
network_mode: UbootNetworkMode;
board_ip: string;
server_ip: string;
Expand Down Expand Up @@ -96,6 +99,9 @@ function defaultFormState(): BoardEditorFormState {
boot_kind: "uboot",
use_tftp: false,
dtb_name: "",
kernel_load_addr: "",
fit_load_addr: "",
bootm_addr: "",
network_mode: "dhcp",
board_ip: "",
server_ip: "",
Expand Down Expand Up @@ -134,6 +140,9 @@ function boardToFormState(board: BoardConfig): BoardEditorFormState {
next.boot_kind = "uboot";
next.use_tftp = board.boot.use_tftp;
next.dtb_name = board.boot.dtb_name ?? "";
next.kernel_load_addr = board.boot.kernel_load_addr ?? "";
next.fit_load_addr = board.boot.fit_load_addr ?? "";
next.bootm_addr = board.boot.bootm_addr ?? "";
next.network_mode = board.boot.network_mode ?? "dhcp";
next.board_ip = board.boot.board_ip ?? "";
next.server_ip = board.boot.server_ip ?? "";
Expand Down Expand Up @@ -166,6 +175,9 @@ function buildBootConfig(): BootConfig {
kind: "uboot",
use_tftp: form.value.use_tftp,
dtb_name: trimToNull(form.value.dtb_name),
kernel_load_addr: trimToNull(form.value.kernel_load_addr),
fit_load_addr: trimToNull(form.value.fit_load_addr),
bootm_addr: trimToNull(form.value.bootm_addr),
network_mode: useStaticIp ? "static_ip" : "dhcp",
board_ip: useStaticIp ? trimToNull(form.value.board_ip) : null,
server_ip: useStaticIp ? trimToNull(form.value.server_ip) : null,
Expand Down Expand Up @@ -733,7 +745,7 @@ onMounted(() => {
</div>
<label class="field">
<span>电源管理类型</span>
<select v-model="form.power_management_kind">
<select v-model="form.power_management_kind" aria-label="电源管理类型">
<option value="custom">Custom</option>
<option value="zhongsheng_relay">中盛继电模块</option>
</select>
Expand All @@ -750,7 +762,7 @@ onMounted(() => {
</label>
</div>

<label v-else class="field" style="margin-top: 16px">
<label v-else-if="form.power_management_kind === 'zhongsheng_relay'" class="field" style="margin-top: 16px">
<span>继电模块串口</span>
<select
:value="selectedRelaySerialOptionValue()"
Expand Down Expand Up @@ -841,6 +853,24 @@ onMounted(() => {
</label>
</div>

<div class="form-grid three-columns" style="margin-top: 18px">
<label class="field">
<span>kernel load addr</span>
<input v-model="form.kernel_load_addr" placeholder="例如 0x80200000" />
<small class="field-hint">板级默认内核加载地址;本地 .board.toml 同名字段优先。留空时使用 kernel_addr_r 或 loadaddr。</small>
</label>
<label class="field">
<span>FIT load addr</span>
<input v-model="form.fit_load_addr" placeholder="例如 0x82200000" />
<small class="field-hint">板级默认 FIT 上传/下载地址;本地 .board.toml 同名字段优先。留空时从 U-Boot 环境推断或自动计算。</small>
</label>
<label class="field">
<span>bootm addr</span>
<input v-model="form.bootm_addr" placeholder="默认跟随 FIT load addr" />
<small class="field-hint">板级默认 bootm 参数;本地 .board.toml 同名字段优先。留空且配置了 FIT load addr 时使用 FIT 地址,否则执行不带参数的 bootm。</small>
</label>
</div>

<div class="split-grid dtb-config-grid" style="margin-top: 18px">
<section class="panel nested-panel dtb-selection-panel">
<div class="panel-heading compact">
Expand Down
3 changes: 3 additions & 0 deletions ostool-server/webui/src/views/SessionsView.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ function makeBoard(id = "orangepi5plus-1"): BoardConfig {
kind: "uboot",
use_tftp: true,
dtb_name: null,
kernel_load_addr: null,
fit_load_addr: null,
bootm_addr: null,
network_mode: "dhcp",
board_ip: null,
server_ip: null,
Expand Down
14 changes: 13 additions & 1 deletion ostool/src/board/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ pub struct UbootProfile {
pub use_tftp: bool,
pub dtb_name: Option<String>,
#[serde(default)]
pub kernel_load_addr: Option<String>,
#[serde(default)]
pub fit_load_addr: Option<String>,
#[serde(default)]
pub bootm_addr: Option<String>,
#[serde(default)]
pub network_mode: UbootNetworkMode,
#[serde(default)]
pub board_ip: Option<String>,
Expand Down Expand Up @@ -461,7 +467,10 @@ mod tests {
r#"{
"boot": {
"kind": "uboot",
"use_tftp": true
"use_tftp": true,
"kernel_load_addr": "0x80200000",
"fit_load_addr": "0x82200000",
"bootm_addr": "0x82200000"
},
"server_ip": "10.0.0.2",
"netmask": "255.255.255.0",
Expand All @@ -474,6 +483,9 @@ mod tests {
match response.boot {
BootConfig::Uboot(profile) => {
assert!(profile.use_tftp);
assert_eq!(profile.kernel_load_addr.as_deref(), Some("0x80200000"));
assert_eq!(profile.fit_load_addr.as_deref(), Some("0x82200000"));
assert_eq!(profile.bootm_addr.as_deref(), Some("0x82200000"));
}
BootConfig::Pxe(_) => panic!("expected uboot profile"),
}
Expand Down
Loading