diff --git a/scripts/canflash/.gitignore b/scripts/canflash/.gitignore index 8fc0d8027..4b8b81a8a 100644 --- a/scripts/canflash/.gitignore +++ b/scripts/canflash/.gitignore @@ -1 +1,2 @@ uploads/ +metadata.json \ No newline at end of file diff --git a/scripts/canflash/flash_logic.py b/scripts/canflash/flash_logic.py index 9e8da61b1..0235f748b 100644 --- a/scripts/canflash/flash_logic.py +++ b/scripts/canflash/flash_logic.py @@ -2,6 +2,7 @@ import subprocess from datetime import datetime from constants import ECU_CONFIG, UPLOAD_DIR +from metadata import load_metadata, save_metadata def save_uploaded_file(ecu: str, file_name: str, file_content: bytes) -> str: @@ -12,6 +13,8 @@ def save_uploaded_file(ecu: str, file_name: str, file_content: bytes) -> str: os.makedirs(full_path, exist_ok=True) file_path = os.path.join(full_path, file_name) + save_metadata(file_name, "", timestamp, ecu.lower(), ecu_dir) + with open(file_path, "wb") as f: f.write(file_content) diff --git a/scripts/canflash/main.py b/scripts/canflash/main.py index 723f0ad27..0fcc4431b 100644 --- a/scripts/canflash/main.py +++ b/scripts/canflash/main.py @@ -1,10 +1,24 @@ from nicegui import ui from nicegui.events import UploadEventArguments from flash_logic import save_uploaded_file, flash_file -from constants import ECU_CONFIG +from metadata import load_metadata, save_metadata +from constants import ECU_CONFIG, UPLOAD_DIR import os +import json +class home_page: + def __init__(self): + self.build_ui() + + def build_ui(self): + ui.colors(primary="#AA1F26") + ui.label('Welcome to CAN Flash!') + ui.label('Select to flash a new binary file') + ui.button('Upload a new binary file', on_click=lambda e: ui.navigate.to('/upload_new_bin')) + ui.label('Select to flash an existing binary file or update its notes') + ui.button('Flash an existing binary file', on_click=lambda e: ui.navigate.to('/upload_old_bin')) +# Upload new binary file and flash class CanFlashApp: def __init__(self): self.starting_ecu = "Select ECU" @@ -35,7 +49,6 @@ def handle_flash(self): else: ui.notify(str(exception), type="negative") - def build_ui(self): ui.colors(primary="#AA1F26") ui.markdown("Welcome to CAN Flash! Select an ECU and upload a file to flash. See [docs](https://macformula.github.io/racecar/) for more information.") @@ -58,11 +71,136 @@ def build_ui(self): self.flash_button = ui.button("Flash", on_click=self.handle_flash) self.flash_button.disable() + +# Flash an existing binary file or update notes +# Upload new binary file and flash +class CanFlashUploadExisting(CanFlashApp): + def __init__(self): + self.starting_ecu = "Select ECU" + self.selected_ecu = self.starting_ecu + self.bin_file = "Select Binary File" + self.selected_bin_file = self.bin_file + self.uploaded_file_path = None + self.build_ui() + + def save_notes(self, notes: str, file_name: str): + try: + metadata = load_metadata() + except FileNotFoundError: + metadata = {} + + if file_name in metadata: + # Update or add the notes for this file + metadata[file_name]["notes"] = notes + + with open("metadata.json", 'w') as f: + json.dump(metadata, f, indent=2) + + ui.notify(f"Notes updated for {file_name}", position="center") + else: + ui.notify(f"File {file_name} not found in metadata", type="negative") + + def on_file_selection(self): + # Don't do anything if no file is selected + if self.selected_bin_file == self.bin_file: + return + + # Load metadata for the selected file + metadata = load_metadata() + file_metadata = metadata.get(self.selected_bin_file, {}) + + if not file_metadata: + ui.notify("Could not find file metadata", type="negative") + return + + # Construct the full file path + upload_name = file_metadata.get("upload name", "") + file_name = file_metadata.get("file name", "") + self.uploaded_file_path = os.path.join(UPLOAD_DIR, upload_name, file_name) + + # Set the ECU from metadata + stored_ecu = file_metadata.get("ecu", "").lower() + # Match it to the ECU_CONFIG keys (which are title case) + for ecu_key in ECU_CONFIG.keys(): + if ecu_key.lower() == stored_ecu: + self.selected_ecu = ecu_key + break + + # Enable buttons + if hasattr(self, "flash_button"): + self.flash_button.enable() + if hasattr(self, "save_notes_button"): + self.save_notes_button.enable() + + # Load existing notes into textbox + if hasattr(self, "textbox"): + self.textbox.value = file_metadata.get("notes", "") + + + + def build_ui(self): + ui.colors(primary="#AA1F26") + ui.markdown("Welcome to CAN Flash! Select an ECU and upload a file to flash. See [docs](https://macformula.github.io/racecar/) for more information.") + + # ECU Selection + self.ecu_select = ui.select([self.starting_ecu] + list(ECU_CONFIG.keys())) + self.ecu_select.bind_value(self, "selected_ecu") + + # Binary File Selection + self.file_dropdown = ui.select([self.selected_bin_file] + list(load_metadata().keys()), + on_change=self.on_file_selection) + self.file_dropdown.bind_value(self, "selected_bin_file") + + # Flash Button + ui.markdown("") + ui.markdown("Flash Binary File") + self.flash_button = ui.button("Flash", on_click=self.handle_flash) + self.flash_button.disable() + + # Update Notes + + ui.markdown("") + ui.markdown("Update Notes for previously Uploaded Files") + + self.textbox = ui.input(label='Enter Metadata Notes') + + self.save_notes_button = ui.button('Submit', on_click=lambda: + self.save_notes(self.textbox.value, self.selected_bin_file)) + self.save_notes_button.disable() + + # Delete Binary File + + #FIXME + '''ui.markdown("") + ui.markdown("Delete Binary File") + self.delete_button = ui.button("Delete Binary File", on_click=lambda: delete_metadata("uploads")) + self.delete_button.disable()''' + @ui.page("/") def main_page(): + home_page() + + +@ui.page("/upload_new_bin") +def upload_new_bin(): CanFlashApp() - + + #Navigation + ui.markdown("") + ui.markdown("Navigation") + ui.button('Home', on_click=lambda e: ui.navigate.to('/')) + ui.button('Flash an existing binary file or update notes', on_click=lambda e: ui.navigate.to('/upload_old_bin')) + +@ui.page("/upload_old_bin") +def reupload_existing_bin(): + CanFlashUploadExisting() + + #Navigation + ui.markdown("") + ui.markdown("Navigation") + ui.button('Home', on_click=lambda e: ui.navigate.to('/')) + ui.button('Upload a new binary file', on_click=lambda e: ui.navigate.to('/upload_new_bin')) if __name__ in {"__main__", "__mp_main__"}: ui.run( diff --git a/scripts/canflash/metadata.py b/scripts/canflash/metadata.py new file mode 100644 index 000000000..1368a1dda --- /dev/null +++ b/scripts/canflash/metadata.py @@ -0,0 +1,27 @@ +import os +import subprocess +import json + +METADATA_FILE = "metadata.json" + +def load_metadata(): + if os.path.exists(METADATA_FILE): + with open(METADATA_FILE, "r") as f: + return json.load(f) + return {} + +def save_metadata(file_name: str, notes: str, timestamp: str, ecu: str, upload_name: str): + + metadata = load_metadata() + + metadata[upload_name] = { + "file name": file_name, + "upload name": upload_name, + "ecu": ecu, + "notes": notes, + "uploaded_at": timestamp, + } + + + with open(METADATA_FILE, "w") as f: + json.dump(metadata, f, indent=2)