# Pico W Remote UF2 Flashing (OTA) – By aMiscreant

### This project demonstrates how to remotely upgrade the firmware of a Raspberry Pi Pico W by downloading a `.uf2` file from a server and flashing it directly into flash memory. Unlike standard MicroPython OTA examples, this approach writes the raw `UF2 payload` to flash, effectively performing a true firmware upgrade over Wi-Fi.

**WARNING:**         This method is dangerous. Writing directly to flash can permanently brick your Pico W if done incorrectly. Only use on test devices and understand the risks.

---

### Overview
#### Server:
    The server hosts the UF2 firmware files via Flask:

```python
@app.route("/firmware/<path:filename>", methods=["GET"])
@require_key
def firmware_files(filename):    """    Serve UF2 files from the firmware directory.    Example: /firmware/nuke.uf2    """    return send_from_directory(UPLOAD_DIR, filename, as_attachment=True)
```
    Files are served over HTTP with an API key.    Any Pico W on the network can fetch the UF2 if it has the correct key.

---

## Pico W
    The Pico W script handles:    Connecting to Wi-Fi.    Fetching the UF2 file from the server.    Extracting payload blocks from the UF2.    Overwriting flash memory.    Rebooting into the new firmware.

---

**Important Flash Parameters:**

```python
FLASH_BASE = 0x10000000  # RP2040 flash base
FLASH_SIZE = 2 * 1024 * 1024  # 2MB example
UF2_PAYLOAD_OFFSET = 0x200  # skip UF2 header to raw flash data
```

---

**Firmware Upgrade Function:**
```python
def fetch_nuke_brick_mode():    url = f"http://{SERVER_IP}:{SERVER_PORT}/firmware/nuke.uf2"    local_path = "/nuke.uf2"
    # Download UF2    response = urequests.get(url, headers={"X-API-KEY": API_KEY}, stream=True)    # ... handle download
    # Read UF2 and extract payload    uf2_data = open(local_path, "rb").read()    payloads = [uf2_data[i + UF2_PAYLOAD_OFFSET:i + 512] for i in range(0, len(uf2_data), 512)]
    # Direct flash write (dangerous!)    for idx, payload in enumerate(payloads):        addr = FLASH_BASE + idx * len(payload)        for i in range(len(payload)):            machine.mem32[addr + i] = payload[i]
    # Reboot into new firmware    machine.reset()
```

---

**Key points:**
    Each UF2 block is 512 bytes; the first 32 bytes are header.    We skip the header (UF2_PAYLOAD_OFFSET) and write the raw data.    Uses machine.mem32 to write directly to flash — high risk of bricking.

---

**Requirements:**
    Wi-Fi connection to reach the server.    API key to access the UF2 files.    Tested only on Raspberry Pi Pico W running MicroPython.


| Method                              | Description                           | Risk     |
| ----------------------------------- | ------------------------------------- | -------- |
| Standard MicroPython OTA            | Fetch `.py` files or use Git/SSH      | Low      |
| Custom Bootloader (Jakub Zimnol)    | Switch firmware using a bootloader    | Medium   |
| **UF2 Direct Flash (this project)** | Fetch `.uf2`, write raw flash, reboot | **High** |

__Most existing guides update code, not firmware. This approach replaces the firmware itself.__

---

# **Warnings:**

###    [!]️ Direct flash writes are `irreversible` if done incorrectly.
###    [!]️ Always test on disposable Pico W devices first.
###    [!]️ This method assumes `2MB` flash layout; adjust for other models.

---

# **Working Example:**

### [PicoW](https://github.com/aMiscreant/Subrosa-Pico)
### [Server](https://github.com/aMiscreant/Subrosa-Ducky)