介紹
嵌入式系統(tǒng)開發(fā)中,燒錄是一個至關(guān)重要的環(huán)節(jié)。然而,長期以來,我們發(fā)現(xiàn)國產(chǎn)芯片現(xiàn)有的燒錄工具在跨平臺方面存在著一些不便之處。對于Synwit單片機而言, 暫時沒發(fā)現(xiàn)在Mac平臺上有合適的燒錄工具。因此,我們決定著手在Mac下開發(fā)一個全新的上位機工具,簡化燒錄過程,提高開發(fā)效率,并為Synwit單片機的使用者提供更多的選擇。為了實現(xiàn)這一目標,我們選擇了Rust作為主要開發(fā)語言,并借助Slint語言設(shè)計界面。
在這個項目中,我們將結(jié)合Rust的內(nèi)存安全和高性能優(yōu)勢,Slint優(yōu)雅的聲明式語言設(shè)計UI,來快速打造一個簡單、易于使用的燒錄工具,為嵌入式開發(fā)者帶來便利。接下來,我將分享部分Rust代碼和Slint界面代碼,探討這個項目的開發(fā)過程和功能特點。
Rust后臺部分代碼如下:
let lister = Lister::new();
let ui_weak = ui.as_weak();
ui.on_flash(move |probe, chip, file| {
let ui = ui_weak.unwrap();
let p = PROBES.lock().unwrap();
let pb = p.get(probe as usize).unwrap().clone();
let probe = pb.open(&lister);
let probe = if let Ok(probe) = probe {
probe
} else {
log::info!("open fail");
return;
};
let mut session = probe
.attach(String::from(chip).as_str(), Permissions::default())
.unwrap();
let flash_process = flashing::FlashProgress::new(move |e| match e {
flashing::ProgressEvent::Initialized { flash_layout: _ } => {
ui.invoke_print_log("Initialized".into());
}
flashing::ProgressEvent::FinishedProgramming => {
let cnt = ui.get_success_cnt() + 1;
ui.set_success_cnt(cnt);
}
flashing::ProgressEvent::FailedErasing
| flashing::ProgressEvent::FailedProgramming => {
let cnt = ui.get_fail_cnt() + 1;
ui.set_fail_cnt(cnt);
}
_a => ui.invoke_print_log(format!("{:?}", _a).into()),
});
let mut download_options = flashing::DownloadOptions::default();
download_options.verify = true;
download_options.progress = Some(flash_process);
let _ = flashing::download_file_with_options(
&mut session,
String::from(file).as_str(),
flashing::Format::Elf,
download_options,
)
.inspect_err(|e| {
log::error!("error: {}", e);
});
});
界面Slint代碼如下:
import { Button, VerticalBox , HorizontalBox, CheckBox, GroupBox} from "std-widgets.slint";
import { FileTextEdit } from "component/FileTextEdit.slint";
import { TitleComBox } from "component/TitleComBox.slint";
import { TextEdit } from "component/TextEdit.slint";
export struct Vender {
name: string,
chip: [string],
}
export component AppWindow inherits Window {
title: @tr("MCU Flash@Hysonglet");
in-out property <[Vender]> chip_set : [];
in-out property success_cnt;
in property fail_cnt;
in-out property firmware;
in property firmware_detail;
in property <[string]> probe_list: [
@tr("first"),
@tr("second")
];
in property <[string]> vender_list: [
];
in property <[string]> chip_list: [];
callback flash(int, string, string);
pure callback firmware_ready() -> bool;
pure callback process() -> int;
public function clear_log() {
log.clear()
}
public function print_log(txt: string) {
log.print(txt);
}
height: 480px;
width: 720px;
HorizontalBox {
alignment: LayoutAlignment.space-between;
left := VerticalBox {
alignment: LayoutAlignment.space-around;
spacing: 0px;
file_text_edit := FileTextEdit {
width: 210px;
height: 180px;
process: root.process()*1.0/100.0;
firmware <=> root.firmware;
file_detail: firmware_detail;
}
probe := TitleComBox {
title: @tr("Probe");
model: root.probe_list;
}
vender:= TitleComBox {
title: @tr("Vender");
model: root.vender-list;
}
chip:= TitleComBox {
title: @tr("Chip");
model: root.chip_set[vender.current_index].chip;
}
Button {
text: @tr("Flash");
clicked => {
flash(probe.current_index, chip.current_value, root.firmware);
}
enabled: firmware_ready();
}
}
VerticalBox {
width: 450px;
log := TextEdit {
height: parent.height/1.2;
}
HorizontalBox {
height: 45px;
alignment: space-between;
Button {
text: @tr("Success:") + root.success_cnt;
}
Button {
text: @tr("Fail: ") + root.fail_cnt;
}
Button {
text: @tr("Clear");
clicked => {
log.clear()
}
}
}
}
}
}
Rust后臺控制Jlink或CMISI-DAP工具,采用SWD協(xié)議,只需連接SWM341的SWC、SWIO、GND、VCC即可下載。
通過這個項目的開發(fā),我深刻體會到了Rust語言的強大之處,其內(nèi)存安全和高性能,為本項目提供了堅實的基礎(chǔ)。同時,使用slint設(shè)計界面,快速實現(xiàn)界面的定制,非常便捷優(yōu)雅。
工具界面