"""PlatformIO upload hook for env:versapad_usb. The board's actual bootloader (bootloader/, UF2/mass-storage) does not speak SAM-BA, so upload_protocol=sam-ba (the board.json default, inherited from an Arduino-Zero-style template) does not work here. This converts the built .bin to .uf2 and copies it onto the VERSABOOT mass-storage volume instead -- Windows only for now, matching the rest of this project's dev environment. """ import ctypes import os import string import sys Import("env") sys.path.insert(0, env.subst("$PROJECT_DIR")) import uf2conv VOLUME_LABEL = "VERSABOOT" DRIVE_UNKNOWN = 0 DRIVE_NO_ROOT_DIR = 1 def find_versaboot_drive(label=VOLUME_LABEL): for letter in string.ascii_uppercase: root = f"{letter}:\\" drive_type = ctypes.windll.kernel32.GetDriveTypeW(root) if drive_type in (DRIVE_UNKNOWN, DRIVE_NO_ROOT_DIR): continue vol_name_buf = ctypes.create_unicode_buffer(261) fs_name_buf = ctypes.create_unicode_buffer(261) ok = ctypes.windll.kernel32.GetVolumeInformationW( ctypes.c_wchar_p(root), vol_name_buf, ctypes.sizeof(vol_name_buf), None, None, None, fs_name_buf, ctypes.sizeof(fs_name_buf), ) if ok and vol_name_buf.value == label: return root return None def upload_via_uf2(source, target, env): build_dir = env.subst("$BUILD_DIR") bin_path = os.path.join(build_dir, "firmware.bin") uf2_path = os.path.join(build_dir, "firmware.uf2") if not os.path.isfile(bin_path): print(f"error: {bin_path} not found (expected as a normal build product)") env.Exit(1) num_blocks = uf2conv.convert(bin_path, uf2_path, base_addr=0x2000, family_id=uf2conv.SAMD21_FAMILY_ID) print(f"Wrote {uf2_path}: {num_blocks} blocks") drive = find_versaboot_drive() if drive is None: print(f"error: no drive labeled '{VOLUME_LABEL}' found.") print("Hold the bottom-right Cherry MX key while plugging in USB to enter the bootloader.") env.Exit(1) dest = os.path.join(drive, "firmware.uf2") print(f"Copying {uf2_path} -> {dest}") with open(uf2_path, "rb") as src, open(dest, "wb") as dst: dst.write(src.read()) print("Upload triggers a reset into the app on the device side; no further action needed.") env.Replace(UPLOADCMD=upload_via_uf2)