# Flashing USB Recovery Boot Header

This script flashes a special USB "Recovery Header" to the device's on-board flash memory.

> **Boot Header**
> Script allows the flashing of different boot headers. This example focuses only on the USB recovery header since other headers
are not commonly used.

Some devices, like the [OAK-FFC 4P](https://docs.luxonis.com/hardware/products/OAK-FFC%25204P.md) can be flashed with a
bootloader. By writing the USB recovery header, the device will no longer use the bootloader and will instead boot like a standard
USB device (similar to OAK-1).

This can be beneficial in scenarios where you want to:

 * Eliminate the bootloader’s extra power consumption in idle mode
 * Revert to a simple USB-only setup, removing advanced bootloader features

> Overwriting the bootloader means the device no longer supports advanced bootloader capabilities. Only do this if you understand
the implications. This can be reversed by flashing the bootloader back.

## Demo

An example script might produce output like:

```bash
~/depthai-python/examples$ python3 flash_boot_header.py USB_RECOVERY
Found device with name: 1.1
Successfully flashed boot header!
```

## Setup

Please run the [install script](https://github.com/luxonis/depthai-python/blob/main/examples/install_requirements.py) to download
all required dependencies. Please note that this script must be ran from git context, so you have to download the
[depthai-python](https://github.com/luxonis/depthai-python) repository first and then run the script

```bash
git clone https://github.com/luxonis/depthai-python.git
cd depthai-python/examples
python3 install_requirements.py
```

For additional information, please follow the [installation guide](https://docs.luxonis.com/software/depthai/manual-install.md).

## Source code

#### Python

```python
import sys
from typing import Callable, Tuple
from enum import Enum
import depthai

FLASH = depthai.DeviceBootloader.Memory.FLASH

def main():
    if len(sys.argv) < 2:
        print(f"Usage: {sys.argv[0]} [GPIO_MODE/USB_RECOVERY/NORMAL/FAST] [params]")
        print("\tOptions:")
        print(f"\t\t{sys.argv[0]} GPIO_MODE gpioModeNum")
        print(f"\t\t{sys.argv[0]} USB_RECOVERY")
        print(f"\t\t{sys.argv[0]} NORMAL [frequency] [location] [dummyCycles] [offset]")
        print(f"\t\t{sys.argv[0]} FAST [frequency] [location] [dummyCycles] [offset]")
        return 0

    mode = sys.argv[1].lower()
    flash_func = None

    if mode == "gpio_mode":
        # gpio mode header
        if len(sys.argv) < 3:
            print(f"Usage: {sys.argv[0]} GPIO_MODE gpioModeNum")
            return 0
        
        gpio_mode = int(sys.argv[2])
        def flash_gpio(bl: 'depthai.DeviceBootloader') -> Tuple[bool, str]:
            return bl.flashGpioModeBootHeader(FLASH, gpio_mode)
        flash_func = flash_gpio

    elif mode == "usb_recovery":
        # usb recovery header
        def flash_usb(bl: 'depthai.DeviceBootloader') -> Tuple[bool, str]:
            return bl.flashUsbRecoveryBootHeader(FLASH)
        flash_func = flash_usb

    elif mode in ("normal", "fast"):
        if len(sys.argv) != 2 and len(sys.argv) != 3 and len(sys.argv) <= 3:
            print(f"Usage: {sys.argv[0]} NORMAL/FAST [frequency] [location] [dummyCycles] [offset]")
            print(f"Usage: {sys.argv[0]} NORMAL/FAST [frequency]")
            return 0

        offset = -1
        location = -1
        dummy_cycles = -1
        frequency = -1

        if len(sys.argv) > 3:
            if len(sys.argv) >= 3:
                offset = int(sys.argv[2])
            if len(sys.argv) >= 4:
                location = int(sys.argv[3])
            if len(sys.argv) >= 5:
                dummy_cycles = int(sys.argv[4])
            if len(sys.argv) >= 6:
                frequency = int(sys.argv[5])
        elif len(sys.argv) == 3:
            frequency = int(sys.argv[2])

        if mode == "normal":
            def flash_normal(bl: 'depthai.DeviceBootloader') -> Tuple[bool, str]:
                return bl.flashBootHeader(FLASH, frequency, location, dummy_cycles, offset)
            flash_func = flash_normal
        elif mode == "fast":
            def flash_fast(bl: 'depthai.DeviceBootloader') -> Tuple[bool, str]:
                return bl.flashFastBootHeader(FLASH, frequency, location, dummy_cycles, offset)
            flash_func = flash_fast

    # Find device and flash specified boot header
    success, info = depthai.DeviceBootloader.getFirstAvailableDevice()
    
    if success:
        print(f"Found device with name: {info.name}")
        bl = depthai.DeviceBootloader(info)

        # Flash the specified boot header
        if flash_func:
            success, error_msg = flash_func(bl)
            if success:
                print("Successfully flashed boot header!")
            else:
                print(f"Couldn't flash boot header: {error_msg}")
        else:
            print("Invalid boot option header specified")
    else:
        print("No devices found")

    return 0

if __name__ == "__main__":
    main()
```

#### C++

```cpp
#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <fstream>
#include <string>

#include "depthai/depthai.hpp"

int main(int argc, char** argv) {
    if(argc < 2) {
        std::cout << "Usage: " << argv[0] << " [GPIO_MODE/USB_RECOVERY/NORMAL/FAST] [params]" << std::endl;
        std::cout << "\tOptions:\n";
        std::cout << "\t\t" << argv[0] << " GPIO_MODE gpioModeNum" << std::endl;
        std::cout << "\t\t" << argv[0] << " USB_RECOVERY" << std::endl;
        std::cout << "\t\t" << argv[0] << " NORMAL [frequency] [location] [dummyCycles] [offset]" << std::endl;
        std::cout << "\t\t" << argv[0] << " FAST [frequency] [location] [dummyCycles] [offset]" << std::endl;
        return 0;
    }
    std::string mode{argv[1]};
    std::transform(mode.begin(), mode.end(), mode.begin(), ::tolower);
    std::function<std::tuple<bool, std::string>(dai::DeviceBootloader&)> flash = nullptr;

    if(mode == "gpio_mode") {
        // gpio mode header
        if(argc < 3) {
            std::cout << "Usage: " << argv[0] << " GPIO_MODE gpioModeNum" << std::endl;
            return 0;
        }
        int gpioMode = std::stoi(std::string(argv[2]));

        flash = [gpioMode](dai::DeviceBootloader& bl) { return bl.flashGpioModeBootHeader(dai::DeviceBootloader::Memory::FLASH, gpioMode); };
    } else if(mode == "usb_recovery") {
        // usb recovery header
        flash = [](dai::DeviceBootloader& bl) { return bl.flashUsbRecoveryBootHeader(dai::DeviceBootloader::Memory::FLASH); };
    } else if(mode == "normal" || mode == "fast") {
        if(argc != 2 && argc != 3 && argc <= 3) {
            std::cout << "Usage: " << argv[0] << " NORMAL/FAST [frequency] [location] [dummyCycles] [offset]" << std::endl;
            std::cout << "Usage: " << argv[0] << " NORMAL/FAST [frequency]" << std::endl;
            return 0;
        }
        int64_t offset = -1;
        int64_t location = -1;
        int32_t dummyCycles = -1;
        int32_t frequency = -1;
        if(argc > 3) {
            if(argc >= 3) {
                offset = std::stoi(std::string(argv[2]));
            }
            if(argc >= 4) {
                location = std::stoi(std::string(argv[3]));
            }
            if(argc >= 5) {
                dummyCycles = std::stoi(std::string(argv[4]));
            }
            if(argc >= 6) {
                frequency = std::stoi(std::string(argv[5]));
            }
        } else if(argc == 3) {
            frequency = std::stoi(std::string(argv[2]));
        }

        if(mode == "normal") {
            flash = [offset, location, dummyCycles, frequency](dai::DeviceBootloader& bl) {
                return bl.flashBootHeader(dai::DeviceBootloader::Memory::FLASH, frequency, location, dummyCycles, offset);
            };
        } else if(mode == "fast") {
            flash = [offset, location, dummyCycles, frequency](dai::DeviceBootloader& bl) {
                return bl.flashFastBootHeader(dai::DeviceBootloader::Memory::FLASH, frequency, location, dummyCycles, offset);
            };
        }
    }

    // Find device and flash specified boot header
    bool res = false;
    dai::DeviceInfo info;
    std::tie(res, info) = dai::DeviceBootloader::getFirstAvailableDevice();

    if(res) {
        std::cout << "Found device with name: " << info.name << std::endl;
        dai::DeviceBootloader bl(info);
        // Flash the specified boot header
        if(flash) {
            bool success;
            std::string errorMsg;
            std::tie(success, errorMsg) = flash(bl);
            if(success) {
                std::cout << "Successfully flashed boot header!" << std::endl;
            } else {
                std::cout << "Couldn't flash boot header: " << errorMsg << std::endl;
            }
        } else {
            std::cout << "Invalid boot option header specified" << std::endl;
        }
    } else {
        std::cout << "No devices found" << std::endl;
    }

    return 0;
}
```

### Need assistance?

Head over to [Discussion Forum](https://discuss.luxonis.com/) for technical support or any other questions you might have.
