# 刷写启动加载器

此脚本将向连接的 OAK
相机刷写[出厂启动加载器](https://docs.luxonis.com/software/depthai-components/bootloader.md)，同时会清除[用户启动加载器](https://docs.luxonis.com/software/depthai-components/bootloader.md)（如果存在）。
启动加载器只能刷写到带有板载闪存存储的设备上。

> 我们建议使用
> [设备管理器](https://docs.luxonis.com/software/depthai/examples/device_information.md)
> ，这是一个用于与启动加载器及其配置交互的 GUI 工具。

## 演示

示例脚本输出

```bash
~/depthai-python/examples$ python3 flash_bootloader.py
    [0] 1844301041C83D0E00 [X_LINK_USB_VSC]
    Which DepthAI device to flash bootloader for [0..0]: 0
    Booting latest bootloader first, will take a tad longer...
    Bootloader version to flash: 0.0.26
    No config found, skipping erasing user bootloader
    Flashing USB bootloader...
    Flashing progress: 0.0%
    Flashing progress: 18.8%
    Flashing progress: 31.2%
    Flashing progress: 48.2%
    Flashing progress: 94.2%
    Flashing progress: 100.0%
    Flashing successful. Took 7.55600329185836 seconds
```

## 设置

请运行[安装脚本](https://github.com/luxonis/depthai-python/blob/main/examples/install_requirements.py)以下载所有必需的依赖项。请注意，此脚本必须在 git
上下文中运行，因此您需要先下载 [depthai-python](https://github.com/luxonis/depthai-python) 仓库，然后运行该脚本。

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

更多信息，请参考[安装指南](https://docs.luxonis.com/software/depthai/manual-install.md)。

## 源代码

#### Python

```python
#!/usr/bin/env python3

import depthai as dai
import sys
import time

blType = dai.DeviceBootloader.Type.AUTO
if len(sys.argv) > 1:
    if sys.argv[1] == 'usb':
        blType = dai.DeviceBootloader.Type.USB
    elif sys.argv[1] == 'network':
        blType = dai.DeviceBootloader.Type.NETWORK
    else:
        print("Specify either 'usb' or 'network' bootloader type")
        exit()

deviceInfos = dai.DeviceBootloader.getAllAvailableDevices()
if len(deviceInfos) == 0:
    print("No device found to flash. Exiting.")
    exit(-1)
else:
    for i, di in enumerate(deviceInfos):
        print(f'[{i}] {di.getMxId()} [{di.protocol.name}]', end='')
        if di.state == dai.XLinkDeviceState.X_LINK_BOOTLOADER:
            with dai.DeviceBootloader(di) as bl:
                print(f' current bootloader: {bl.getVersion()}', end='')
        print()
    selected = input(f'Which OAK device to flash factory bootloader for [0..{len(deviceInfos)-1}]: ')
    info = deviceInfos[int(selected)]

hasBootloader = (info.state == dai.XLinkDeviceState.X_LINK_BOOTLOADER)
if hasBootloader:
    print("Warning! Flashing factory bootloader can potentially soft brick your device and should be done with caution.")
    print("Do not unplug your device while the bootloader is flashing.")
    print("Type 'y' and press enter to proceed, otherwise exits: ")
    if input() != 'y':
        print("Prompt declined, exiting...")
        exit(-1)

# Open DeviceBootloader and allow flashing bootloader
print(f"Booting latest bootloader first, will take a tad longer...")
with dai.DeviceBootloader(info, allowFlashingBootloader=True) as bl:
    print("Bootloader version to flash:", bl.getVersion())
    currentBlType = bl.getType()

    if blType == dai.DeviceBootloader.Type.AUTO:
        blType = currentBlType

    # Check if bootloader type is the same, if already booted by bootloader (not in USB recovery mode)
    if currentBlType != blType and hasBootloader:
        print(f"Are you sure you want to flash '{blType.name}' bootloader over current '{currentBlType.name}' bootloader?")
        print(f"Type 'y' and press enter to proceed, otherwise exits: ")
        if input() != 'y':
            print("Prompt declined, exiting...")
            exit(-1)

    try:
        # Clears out user bootloader
        configJson = bl.readConfigData()
        configJson["userBlSize"] = 0
        bl.flashConfigData(configJson)
    except:
        print('No config found, skipping erasing user bootloader')

    # Create a progress callback lambda
    progress = lambda p : print(f'Flashing progress: {p*100:.1f}%')

    print(f"Flashing {blType.name} bootloader...")
    startTime = time.monotonic()
    (res, message) = bl.flashBootloader(dai.DeviceBootloader.Memory.FLASH, blType, progress)
    if res:
        print("Flashing successful. Took", time.monotonic() - startTime, "seconds")
    else:
        print("Flashing failed:", message)
```

#### C++

```cpp
#include <chrono>
#include <string>

#include "XLink/XLink.h"
#include "depthai/depthai.hpp"
#include "depthai/xlink/XLinkConnection.hpp"

static const char* ProtocolToStr(XLinkProtocol_t val) {
    switch(val) {
        case X_LINK_USB_VSC:
            return "X_LINK_USB_VSC";
        case X_LINK_USB_CDC:
            return "X_LINK_USB_CDC";
        case X_LINK_PCIE:
            return "X_LINK_PCIE";
        case X_LINK_IPC:
            return "X_LINK_IPC";
        case X_LINK_TCP_IP:
            return "X_LINK_TCP_IP";
        case X_LINK_NMB_OF_PROTOCOLS:
            return "X_LINK_NMB_OF_PROTOCOLS";
        case X_LINK_ANY_PROTOCOL:
            return "X_LINK_ANY_PROTOCOL";
        default:
            return "INVALID_ENUM_VALUE";
            break;
    }
}

int main(int argc, char** argv) {
    using namespace std::chrono;

    dai::DeviceBootloader::Type blType = dai::DeviceBootloader::Type::AUTO;
    if(argc > 1) {
        std::string blTypeStr(argv[1]);
        if(blTypeStr == "usb") {
            blType = dai::DeviceBootloader::Type::USB;
        } else if(blTypeStr == "network") {
            blType = dai::DeviceBootloader::Type::NETWORK;
        } else {
            std::cout << "Specify either 'usb' or 'network' bootloader type\n";
            return 0;
        }
    }

    dai::DeviceInfo info;
    auto deviceInfos = dai::DeviceBootloader::getAllAvailableDevices();
    if(deviceInfos.empty()) {
        std::cout << "No device found to flash. Exiting." << std::endl;
        return -1;
    } else {
        for(int i = 0; i < deviceInfos.size(); i++) {
            const auto& devInfo = deviceInfos[i];
            std::cout << "[" << i << "] " << devInfo.getMxId() << "[" << ProtocolToStr(devInfo.protocol) << "]";
            if(devInfo.state == X_LINK_BOOTLOADER) {
                dai::DeviceBootloader bl(devInfo);
                std::cout << " current bootloader: " << bl.getVersion();
            }
            std::cout << std::endl;
        }
        int selected = 0;
        std::cout << "Which DepthAI device to flash bootloader for [0.." << deviceInfos.size() - 1 << "]\n";
        std::cin >> selected;
        info = deviceInfos[selected];
    }

    bool hasBootloader = (info.state == X_LINK_BOOTLOADER);
    if(hasBootloader) {
        std::cout << "Warning! Flashing bootloader can potentially soft brick your device and should be done with caution." << std::endl;
        std::cout << "Do not unplug your device while the bootloader is flashing." << std::endl;
        std::cout << "Type 'y' and press enter to proceed, otherwise exits: ";
        std::cin.ignore();
        if(std::cin.get() != 'y') {
            std::cout << "Prompt declined, exiting..." << std::endl;
            return -1;
        }
    }

    // Open DeviceBootloader and allow flashing bootloader
    std::cout << "Booting latest bootloader first, will take a tad longer..." << std::endl;
    dai::DeviceBootloader bl(info, true);
    auto currentBlType = bl.getType();

    if(blType == dai::DeviceBootloader::Type::AUTO) {
        blType = currentBlType;
    }

    // Check if bootloader type is the same, if already booted by bootloader (not in USB recovery mode)
    if(currentBlType != blType && hasBootloader) {
        std::cout << "Are you sure you want to flash '" << blType << "' bootloader over current '" << currentBlType << "' bootloader?" << std::endl;
        std::cout << "Type 'y' and press enter to proceed, otherwise exits: ";
        std::cin.ignore();
        if(std::cin.get() != 'y') {
            std::cout << "Prompt declined, exiting..." << std::endl;
            return -1;
        }
    }

    // Create a progress callback lambda
    auto progress = [](float p) { std::cout << "Flashing Progress..." << p * 100 << "%" << std::endl; };

    std::cout << "Flashing " << blType << " bootloader..." << std::endl;
    auto t1 = steady_clock::now();
    bool success = false;
    std::string message;
    std::tie(success, message) = bl.flashBootloader(dai::DeviceBootloader::Memory::FLASH, blType, progress);
    if(success) {
        std::cout << "Flashing successful. Took " << duration_cast<milliseconds>(steady_clock::now() - t1).count() << "ms" << std::endl;
    } else {
        std::cout << "Flashing failed: " << message << std::endl;
    }
    return 0;
}
```

### 需要帮助？

请前往 [OAKChina 官网](https://www.oakchina.cn/) 获取技术支持或解答您的任何疑问。
