parent
27b5a727e3
commit
99ef66de4b
2 changed files with 125 additions and 1 deletions
@ -0,0 +1,122 @@ |
|||||||
|
#!/usr/bin/env python3 |
||||||
|
import os |
||||||
|
import pyray as rl |
||||||
|
import sys |
||||||
|
import threading |
||||||
|
from enum import IntEnum |
||||||
|
|
||||||
|
from openpilot.system.ui.lib.application import gui_app, FontWeight |
||||||
|
from openpilot.system.ui.lib.button import gui_button |
||||||
|
from openpilot.system.ui.lib.label import gui_label |
||||||
|
|
||||||
|
NVME = "/dev/nvme0n1" |
||||||
|
USERDATA = "/dev/disk/by-partlabel/userdata" |
||||||
|
|
||||||
|
|
||||||
|
class ResetMode(IntEnum): |
||||||
|
USER_RESET = 0 # user initiated a factory reset from openpilot |
||||||
|
RECOVER = 1 # userdata is corrupt for some reason, give a chance to recover |
||||||
|
FORMAT = 2 # finish up a factory reset from a tool that doesn't flash an empty partition to userdata |
||||||
|
|
||||||
|
|
||||||
|
class ResetState(IntEnum): |
||||||
|
NONE = 0 |
||||||
|
CONFIRM = 1 |
||||||
|
RESETTING = 2 |
||||||
|
FAILED = 3 |
||||||
|
|
||||||
|
|
||||||
|
class Reset: |
||||||
|
def __init__(self, mode): |
||||||
|
self.mode = mode |
||||||
|
self.reset_state = ResetState.NONE |
||||||
|
|
||||||
|
def do_reset(self): |
||||||
|
# Best effort to wipe NVME |
||||||
|
os.system(f"sudo umount {NVME}") |
||||||
|
os.system(f"yes | sudo mkfs.ext4 {NVME}") |
||||||
|
|
||||||
|
# Removing data and formatting |
||||||
|
rm = os.system("sudo rm -rf /data/*") |
||||||
|
os.system(f"sudo umount {USERDATA}") |
||||||
|
fmt = os.system(f"yes | sudo mkfs.ext4 {USERDATA}") |
||||||
|
|
||||||
|
if rm == 0 or fmt == 0: |
||||||
|
os.system("sudo reboot") |
||||||
|
else: |
||||||
|
self.reset_state = ResetState.FAILED |
||||||
|
|
||||||
|
def start_reset(self): |
||||||
|
self.reset_state = ResetState.RESETTING |
||||||
|
threading.Timer(0.1, self.do_reset).start() |
||||||
|
|
||||||
|
def render(self, rect: rl.Rectangle): |
||||||
|
rl.gui_set_font(gui_app.font(FontWeight.BOLD)) |
||||||
|
label_rect = rl.Rectangle(rect.x + 140, rect.y, rect.width - 280, rect.height) |
||||||
|
gui_label(label_rect, "System Reset", 90) |
||||||
|
rl.gui_set_font(gui_app.font(FontWeight.NORMAL)) |
||||||
|
|
||||||
|
label_rect.y += 150 |
||||||
|
gui_label(label_rect, self.get_body_text(), 80) |
||||||
|
|
||||||
|
button_height = 160 |
||||||
|
button_spacing = 50 |
||||||
|
button_top = rect.y + rect.height - button_height |
||||||
|
button_width = (rect.width - button_spacing) / 2.0 |
||||||
|
|
||||||
|
if self.reset_state != ResetState.RESETTING: |
||||||
|
if self.mode == ResetMode.RECOVER or self.reset_state == ResetState.FAILED: |
||||||
|
if gui_button(rl.Rectangle(rect.x, button_top, button_width, button_height), "Reboot"): |
||||||
|
os.system("sudo reboot") |
||||||
|
elif self.mode == ResetMode.USER_RESET: |
||||||
|
if gui_button(rl.Rectangle(rect.x, button_top, button_width, button_height), "Cancel"): |
||||||
|
return False |
||||||
|
|
||||||
|
if self.reset_state != ResetState.FAILED: |
||||||
|
if gui_button(rl.Rectangle(rect.x + button_width + 50, button_top, button_width, button_height), "Confirm", rl.Color(70, 91, 234, 255)): |
||||||
|
self.confirm() |
||||||
|
|
||||||
|
return True |
||||||
|
|
||||||
|
def confirm(self): |
||||||
|
if self.reset_state == ResetState.CONFIRM: |
||||||
|
self.start_reset() |
||||||
|
else: |
||||||
|
self.reset_state = ResetState.CONFIRM |
||||||
|
|
||||||
|
def get_body_text(self): |
||||||
|
if self.reset_state == ResetState.CONFIRM: |
||||||
|
return "Are you sure you want to reset your device?" |
||||||
|
if self.reset_state == ResetState.RESETTING: |
||||||
|
return "Resetting device...\nThis may take up to a minute." |
||||||
|
if self.reset_state == ResetState.FAILED: |
||||||
|
return "Reset failed. Reboot to try again." |
||||||
|
if self.mode == ResetMode.RECOVER: |
||||||
|
return "Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device." |
||||||
|
return "System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot." |
||||||
|
|
||||||
|
|
||||||
|
def main(): |
||||||
|
mode = ResetMode.USER_RESET |
||||||
|
if len(sys.argv) > 1: |
||||||
|
if sys.argv[1] == '--recover': |
||||||
|
mode = ResetMode.RECOVER |
||||||
|
elif sys.argv[1] == "--format": |
||||||
|
mode = ResetMode.FORMAT |
||||||
|
|
||||||
|
gui_app.init_window("System Reset") |
||||||
|
reset = Reset(mode) |
||||||
|
|
||||||
|
if mode == ResetMode.FORMAT: |
||||||
|
reset.start_reset() |
||||||
|
|
||||||
|
while not rl.window_should_close(): |
||||||
|
rl.begin_drawing() |
||||||
|
rl.clear_background(rl.BLACK) |
||||||
|
if not reset.render(rl.Rectangle(45, 200, gui_app.width - 90, gui_app.height - 245)): |
||||||
|
break |
||||||
|
rl.end_drawing() |
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__": |
||||||
|
main() |
Loading…
Reference in new issue