Change memory regions to prevent crashes; Improve GUI
|
|
@ -95,6 +95,14 @@ mod console;
|
|||
// For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description>
|
||||
esp_bootloader_esp_idf::esp_app_desc!();
|
||||
|
||||
// Memory allocation regions.
|
||||
// These can be debugged using `xtensa-esp32s3-elf-size -A <path-to-binary>`.
|
||||
|
||||
/// Total heap size
|
||||
const HEAP_SIZE: usize = 128 * 1024;
|
||||
/// Size of the app core's stack
|
||||
const STACK_SIZE_CORE_APP: usize = 64 * 1024;
|
||||
|
||||
// const FRAME_DURATION_MIN: Duration = Duration::from_millis(40); // 25 FPS
|
||||
const FRAME_DURATION_MIN: Duration = Duration::from_millis(100); // 10 FPS
|
||||
|
||||
|
|
@ -149,12 +157,10 @@ async fn main(_spawner: Spawner) {
|
|||
let alt_uart_rx_task = async {};
|
||||
|
||||
// Use the internal DRAM as the heap.
|
||||
// TODO: Can we combine the regular link section with dram2?
|
||||
// esp_alloc::heap_allocator!(size: 80 * 1024);
|
||||
// esp_alloc::heap_allocator!(#[unsafe(link_section = ".dram2_uninit")] size: 72 * 1024);
|
||||
//esp_alloc::heap_allocator!(#[unsafe(link_section = ".dram2_uninit")] size: 64 * 1024);
|
||||
esp_alloc::heap_allocator!(#[ram(reclaimed)] size: 64 * 1024);
|
||||
esp_alloc::heap_allocator!(size: 32 * 1024);
|
||||
// Memory reclaimed from the esp-idf bootloader.
|
||||
const HEAP_SIZE_RECLAIMED: usize = 64 * 1024;
|
||||
esp_alloc::heap_allocator!(#[ram(reclaimed)] size: HEAP_SIZE_RECLAIMED);
|
||||
esp_alloc::heap_allocator!(size: HEAP_SIZE - HEAP_SIZE_RECLAIMED);
|
||||
info!("Heap initialized! {:#?}", esp_alloc::HEAP.stats());
|
||||
|
||||
// Initialize the PSRAM allocator.
|
||||
|
|
@ -235,15 +241,15 @@ async fn main(_spawner: Spawner) {
|
|||
// Initialize USB
|
||||
#[cfg(not(feature = "no-usb"))]
|
||||
let usb_driver = {
|
||||
use core::ptr::addr_of_mut;
|
||||
use esp_hal::otg_fs::Usb;
|
||||
use esp_hal::otg_fs::asynch::{Config, Driver};
|
||||
|
||||
static mut EP_MEMORY: [u8; 1024] = [0; 1024];
|
||||
static EP_MEMORY: StaticCell<[u8; 1024]> = StaticCell::new();
|
||||
let ep_memory = EP_MEMORY.init_with(|| [0_u8; _]);
|
||||
let usb = Usb::new(peripherals.USB0, peripherals.GPIO20, peripherals.GPIO19);
|
||||
// Create the driver, from the HAL.
|
||||
let config = Config::default();
|
||||
let driver = Driver::new(usb, unsafe { &mut *addr_of_mut!(EP_MEMORY) }, config);
|
||||
let driver = Driver::new(usb, ep_memory, config);
|
||||
|
||||
info!("USB driver for RMK built!");
|
||||
|
||||
|
|
@ -381,7 +387,7 @@ async fn main(_spawner: Spawner) {
|
|||
let window_size = [framebuffer.height, framebuffer.width];
|
||||
let framebuffer_ptr = FramebufferPtr(framebuffer.as_target_pixels() as _);
|
||||
|
||||
static SECOND_CORE_STACK: StaticCell<Stack<{ 16 * 1024 }>> = StaticCell::new();
|
||||
static SECOND_CORE_STACK: StaticCell<Stack<STACK_SIZE_CORE_APP>> = StaticCell::new();
|
||||
let second_core_stack = SECOND_CORE_STACK.init(Stack::new());
|
||||
esp_rtos::start_second_core(
|
||||
peripherals.CPU_CTRL,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use alloc::{
|
|||
borrow::Cow,
|
||||
boxed::Box,
|
||||
ffi::CString,
|
||||
rc::Rc,
|
||||
string::{String, ToString},
|
||||
vec,
|
||||
vec::Vec,
|
||||
|
|
@ -25,7 +26,7 @@ use itertools::Itertools;
|
|||
use log::{info, warn};
|
||||
use rmk::futures::TryFutureExt;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use slint::SharedString;
|
||||
use slint::{ModelRc, SharedString, StandardListViewItem, VecModel};
|
||||
use spectre_api_sys::{
|
||||
SpectreAlgorithm, SpectreCounter, SpectreKeyPurpose, SpectreResultType, SpectreUserKey,
|
||||
};
|
||||
|
|
@ -243,7 +244,25 @@ pub async fn run_renderer_task(backend: SlintBackend, flash_part_acid: Partition
|
|||
|
||||
let main = AppWindow::new().unwrap();
|
||||
|
||||
main.on_accepted(|string| {
|
||||
main.on_login_pw_accepted({
|
||||
let main = main.clone_strong();
|
||||
move |username, password| {
|
||||
info!("username = {username:?}, password = {password:?}");
|
||||
main.set_app_state(AppState::UserSites);
|
||||
}
|
||||
});
|
||||
|
||||
// let sites = Rc::new(VecModel::default());
|
||||
// sites.push("First".into());
|
||||
// sites.push("Second".into());
|
||||
// main.set_sites(ModelRc::new(ModelRc::new(sites.clone()).map(
|
||||
// |mut site: StandardListViewItem| {
|
||||
// site.text += "10";
|
||||
// site
|
||||
// },
|
||||
// )));
|
||||
|
||||
main.on_site_pw_accepted(|string| {
|
||||
warn!("Accepted: {string}");
|
||||
let Ok(c_string) = CString::new(&*string) else {
|
||||
warn!("String cannot be converted to a C string: {string:?}");
|
||||
|
|
|
|||
3
firmware/acid-firmware/ui/globals.slint
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export global Style {
|
||||
in property <length> spacing: 8px;
|
||||
}
|
||||
1
firmware/acid-firmware/ui/images/help-circle.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-help-circle"><circle cx="12" cy="12" r="10"></circle><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>
|
||||
|
After Width: | Height: | Size: 365 B |
1
firmware/acid-firmware/ui/images/key.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-key"><path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"></path></svg>
|
||||
|
After Width: | Height: | Size: 352 B |
1
firmware/acid-firmware/ui/images/log-in.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-log-in"><path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"></path><polyline points="10 17 15 12 10 7"></polyline><line x1="15" y1="12" x2="3" y2="12"></line></svg>
|
||||
|
After Width: | Height: | Size: 368 B |
1
firmware/acid-firmware/ui/images/log-out.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-log-out"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path><polyline points="16 17 21 12 16 7"></polyline><line x1="21" y1="12" x2="9" y2="12"></line></svg>
|
||||
|
After Width: | Height: | Size: 367 B |
1
firmware/acid-firmware/ui/images/sliders.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-sliders"><line x1="4" y1="21" x2="4" y2="14"></line><line x1="4" y1="10" x2="4" y2="3"></line><line x1="12" y1="21" x2="12" y2="12"></line><line x1="12" y1="8" x2="12" y2="3"></line><line x1="20" y1="21" x2="20" y2="16"></line><line x1="20" y1="12" x2="20" y2="3"></line><line x1="1" y1="14" x2="7" y2="14"></line><line x1="9" y1="8" x2="15" y2="8"></line><line x1="17" y1="16" x2="23" y2="16"></line></svg>
|
||||
|
After Width: | Height: | Size: 611 B |
1
firmware/acid-firmware/ui/images/trash-2.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-trash-2"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></svg>
|
||||
|
After Width: | Height: | Size: 448 B |
1
firmware/acid-firmware/ui/images/users.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-users"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M23 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg>
|
||||
|
After Width: | Height: | Size: 400 B |
38
firmware/acid-firmware/ui/login-view.slint
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import { ComboBox, LineEdit } from "std-widgets.slint";
|
||||
import { Style } from "globals.slint";
|
||||
import { IconButton } from "widgets/icon-button.slint";
|
||||
|
||||
export component LoginView inherits VerticalLayout {
|
||||
padding: Style.spacing;
|
||||
spacing: Style.spacing;
|
||||
callback pw_accepted(string, string);
|
||||
Rectangle { }
|
||||
|
||||
HorizontalLayout {
|
||||
spacing: Style.spacing;
|
||||
IconButton {
|
||||
icon: @image-url("images/users.svg");
|
||||
}
|
||||
|
||||
combo_box_username := ComboBox {
|
||||
model: ["first", "second"];
|
||||
}
|
||||
|
||||
line_edit_user_pw := LineEdit {
|
||||
input-type: InputType.password;
|
||||
placeholder-text: "Password";
|
||||
accepted(text) => {
|
||||
root.pw_accepted(combo_box_username.current-value, text);
|
||||
}
|
||||
}
|
||||
|
||||
IconButton {
|
||||
icon: @image-url("images/log-in.svg");
|
||||
clicked => {
|
||||
root.pw_accepted(combo_box_username.current-value, line_edit_user_pw.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle { }
|
||||
}
|
||||
|
|
@ -8,27 +8,46 @@ import {
|
|||
Button,
|
||||
} from "std-widgets.slint";
|
||||
*/
|
||||
import { Button, VerticalBox, LineEdit, GridBox } from "std-widgets.slint";
|
||||
import {
|
||||
Button,
|
||||
VerticalBox,
|
||||
LineEdit,
|
||||
GridBox,
|
||||
StandardListView,
|
||||
ListView,
|
||||
ComboBox,
|
||||
} from "std-widgets.slint";
|
||||
|
||||
// See https://github.com/slint-ui/slint/issues/4956 for issues with fonts.
|
||||
import "../fonts/IBM_Plex_Mono/IBMPlexMono-Regular.ttf";
|
||||
import { UserSitesView } from "user-sites-view.slint";
|
||||
import { Style } from "globals.slint";
|
||||
import { UsersView } from "users-view.slint";
|
||||
import { LoginView } from "login-view.slint";
|
||||
|
||||
/*
|
||||
TODO: A bigger stack for the 2nd core might be needed to prevent crashing.
|
||||
export enum AppState {
|
||||
PasswordForm,
|
||||
login,
|
||||
user-sites,
|
||||
users,
|
||||
}
|
||||
*/
|
||||
|
||||
export component AppWindow inherits Window {
|
||||
in property <string> dummy: "ÄÖÜÁÉÍÓÚÝŔŚĹŹĆŃĚĽŽŠČŘĎŤŇŮÅäöüáéíóúýŕśĺźćńěľžščřďťňůåß„“”‘’—–@&$%+=¡¿¢£$¥€²³¼½¬¤¦§©®™°";
|
||||
in property <string> dummy: "ÄÖÜÁÉÍÓÚÝŔŚĹŹĆŃĚĽŽŠČŘĎŤŇŮÅäöüáéíóúýŕśĺźćńěľžščřďťňůåß„“”‘’—–@&$%+=¡¿¢£$¥€²³¼½¬¤¦§©®™°´ˇ¨";
|
||||
default-font-family: "IBM Plex Mono";
|
||||
default-font-size: 16pt;
|
||||
height: 368px;
|
||||
width: 960px;
|
||||
in-out property <int> counter: 42;
|
||||
callback request-increase-value();
|
||||
callback accepted(string);
|
||||
in property <AppState> app-state: AppState.login;
|
||||
// Login View
|
||||
callback login_pw_accepted <=> login_view.pw_accepted;
|
||||
// Sites View
|
||||
in property <[StandardListViewItem]> sites <=> user_sites_view.model;
|
||||
callback site_pw_edited <=> user_sites_view.pw_edited;
|
||||
callback site_pw_accepted <=> user_sites_view.pw_accepted;
|
||||
// Sites View
|
||||
in property <[StandardListViewItem]> usernames <=> users_view.model;
|
||||
callback user_username_edited <=> users_view.pw_edited;
|
||||
callback user_username_accepted <=> users_view.pw_accepted;
|
||||
VerticalBox {
|
||||
width: 960px;
|
||||
height: 368px;
|
||||
|
|
@ -36,53 +55,21 @@ export component AppWindow inherits Window {
|
|||
padding-top: 120px;
|
||||
padding-bottom: 8px;
|
||||
Rectangle {
|
||||
height: 240px;
|
||||
background: #00141d;
|
||||
// For debugging bounds.
|
||||
// background: #2c82ff;
|
||||
// border-color: #ffcf00;
|
||||
// border-width: 1px;
|
||||
GridBox {
|
||||
VerticalBox {
|
||||
Text {
|
||||
text: "Counter: \{root.counter}";
|
||||
login_view := LoginView {
|
||||
visible: app-state == AppState.login;
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Increase value";
|
||||
clicked => {
|
||||
root.counter += 1;
|
||||
root.request-increase-value();
|
||||
}
|
||||
user_sites_view := UserSitesView {
|
||||
visible: app-state == AppState.user-sites;
|
||||
}
|
||||
|
||||
LineEdit {
|
||||
input-type: InputType.text;
|
||||
text: "LineEdit";
|
||||
accepted(text) => {
|
||||
root.accepted(text);
|
||||
}
|
||||
/*changed text => {
|
||||
root.changed(self.text);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
TabWidget {
|
||||
Tab {
|
||||
title: "first";
|
||||
Button {
|
||||
text: "First";
|
||||
}
|
||||
}
|
||||
|
||||
Tab {
|
||||
title: "second";
|
||||
Button {
|
||||
text: "Second";
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
users_view := UsersView {
|
||||
visible: app-state == AppState.users;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
53
firmware/acid-firmware/ui/user-sites-view.slint
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import { LineEdit, StandardListView, Button } from "std-widgets.slint";
|
||||
import { Style } from "globals.slint";
|
||||
import { IconButton } from "widgets/icon-button.slint";
|
||||
|
||||
export component UserSitesView inherits HorizontalLayout {
|
||||
padding: Style.spacing;
|
||||
spacing: Style.spacing;
|
||||
in property <[StandardListViewItem]> model <=> list_view_sites.model;
|
||||
in-out property <int> current-item <=> list_view_sites.current-item;
|
||||
callback pw_edited <=> line_edit_site_pw.edited;
|
||||
callback pw_accepted <=> line_edit_site_pw.accepted;
|
||||
VerticalLayout {
|
||||
spacing: Style.spacing;
|
||||
Text {
|
||||
text: "Send password for:";
|
||||
}
|
||||
|
||||
line_edit_site_pw := LineEdit {
|
||||
input-type: InputType.text;
|
||||
placeholder-text: "example.org";
|
||||
}
|
||||
|
||||
list_view_sites := StandardListView {
|
||||
model: [
|
||||
{ text: "Test" },
|
||||
{ text: "Test" },
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
VerticalLayout {
|
||||
spacing: Style.spacing;
|
||||
// IconButton {
|
||||
// icon: @image-url("images/log-out.svg");
|
||||
// }
|
||||
|
||||
IconButton {
|
||||
icon: @image-url("images/sliders.svg");
|
||||
}
|
||||
|
||||
IconButton {
|
||||
icon: @image-url("images/help-circle.svg");
|
||||
}
|
||||
|
||||
IconButton {
|
||||
icon: @image-url("images/key.svg");
|
||||
}
|
||||
|
||||
IconButton {
|
||||
icon: @image-url("images/trash-2.svg");
|
||||
}
|
||||
}
|
||||
}
|
||||
41
firmware/acid-firmware/ui/users-view.slint
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import { LineEdit, StandardListView, Button } from "std-widgets.slint";
|
||||
import { Style } from "globals.slint";
|
||||
import { IconButton } from "widgets/icon-button.slint";
|
||||
|
||||
export component UsersView inherits HorizontalLayout {
|
||||
padding: Style.spacing;
|
||||
spacing: Style.spacing;
|
||||
in property <[StandardListViewItem]> model <=> list_view_sites.model;
|
||||
in-out property <int> current-item <=> list_view_sites.current-item;
|
||||
callback pw_edited <=> line_edit_site_pw.edited;
|
||||
callback pw_accepted <=> line_edit_site_pw.accepted;
|
||||
VerticalLayout {
|
||||
spacing: Style.spacing;
|
||||
Text {
|
||||
text: "Username:";
|
||||
}
|
||||
|
||||
line_edit_site_pw := LineEdit {
|
||||
input-type: InputType.text;
|
||||
placeholder-text: "Full Name";
|
||||
}
|
||||
|
||||
list_view_sites := StandardListView {
|
||||
model: [
|
||||
{ text: "Test" },
|
||||
{ text: "Test" },
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
VerticalLayout {
|
||||
spacing: Style.spacing;
|
||||
IconButton {
|
||||
icon: @image-url("images/key.svg");
|
||||
}
|
||||
|
||||
IconButton {
|
||||
icon: @image-url("images/trash-2.svg");
|
||||
}
|
||||
}
|
||||
}
|
||||
8
firmware/acid-firmware/ui/widgets/icon-button.slint
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { Button } from "std-widgets.slint";
|
||||
|
||||
export component IconButton inherits Button {
|
||||
colorize-icon: true;
|
||||
icon-size: 24px;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||