diff --git a/CMakeLists.txt b/CMakeLists.txt index ad1730e14..1ebca983b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,6 +157,7 @@ target_link_libraries(${TARGET_NAME} pybind11::pybind11 depthai::core # Use non-opencv target as we use opencv-python in bindings hedley + pybind11_json ) # Find Git diff --git a/depthai-core b/depthai-core index c807a982b..fb57b8978 160000 --- a/depthai-core +++ b/depthai-core @@ -1 +1 @@ -Subproject commit c807a982b944bf67977bdafdb2052499b8e58dfd +Subproject commit fb57b897826fb7feeb99522b5c63a2350764dde5 diff --git a/examples/bootloader_config.py b/examples/bootloader_config.py new file mode 100755 index 000000000..17c7d0d24 --- /dev/null +++ b/examples/bootloader_config.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 + +import depthai as dai +import sys + +usage = False +read = True +clear = False +path = '' +if len(sys.argv) >= 2: + op = sys.argv[1] + if op == 'read': + read = True + elif op == 'flash': + read = False + if len(sys.argv) >= 3: + path = sys.argv[2] + elif op == 'clear': + clear = True + read = False + else: + usage = True +else: + usage = True + +if usage: + print(f'Usage: {sys.argv[0]} [read/flash/clear] [flash: path/to/config/json]') + exit(-1) + +(res, info) = dai.DeviceBootloader.getFirstAvailableDevice() + +if res: + print(f'Found device with name: {info.desc.name}'); + with dai.DeviceBootloader(info) as bl: + if read: + print('Current flashed configuration') + print(f'{bl.readConfigData()}') + else: + success = None + error = None + if clear: + (success, error) = bl.flashConfigClear() + else: + if path == '': + (success, error) = bl.flashConfig(dai.DeviceBootloader.Config()) + else: + (success, error) = bl.flashConfigFile(path) + if success: + print('Successfully flashed bootloader configuration') + else: + print(f'Error flashing bootloader configuration: {error}') +else: + print('No devices found') diff --git a/examples/flash_bootloader.py b/examples/flash_bootloader.py new file mode 100755 index 000000000..3ea3e6077 --- /dev/null +++ b/examples/flash_bootloader.py @@ -0,0 +1,51 @@ +#!/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() + +print("Warning! Flashing 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) + +(found, info) = dai.DeviceBootloader.getFirstAvailableDevice() +if not found: + print("No device found to flash. 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: + currentBlType = bl.getType() + + # Check if bootloader type is the same + if blType != dai.DeviceBootloader.Type.AUTO and currentBlType != blType: + 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); + + # Create a progress callback lambda + progress = lambda p : print(f'Flashing progress: {p*100:.1f}%') + + print(f"Flashing {currentBlType.name} bootloader...") + startTime = time.monotonic() + (res, message) = bl.flashBootloader(dai.DeviceBootloader.Memory.FLASH, currentBlType, progress) + if res: + print("Flashing successful. Took", time.monotonic() - startTime, "seconds") + else: + print("Flashing failed:", message) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index ebc46f957..c0e240707 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -1,2 +1,4 @@ # Add 'hedley' library -add_subdirectory(hedley) \ No newline at end of file +add_subdirectory(hedley) +# Add 'pybind11_json' library +add_subdirectory(pybind11_json) \ No newline at end of file diff --git a/external/pybind11_json/CMakeLists.txt b/external/pybind11_json/CMakeLists.txt new file mode 100644 index 000000000..1e2842c70 --- /dev/null +++ b/external/pybind11_json/CMakeLists.txt @@ -0,0 +1,3 @@ +# pybind11_json library +add_library(pybind11_json INTERFACE) +target_include_directories(pybind11_json INTERFACE "${CMAKE_CURRENT_LIST_DIR}/include") diff --git a/external/pybind11_json/include/pybind11_json/pybind11_json.hpp b/external/pybind11_json/include/pybind11_json/pybind11_json.hpp new file mode 100644 index 000000000..773a30cf4 --- /dev/null +++ b/external/pybind11_json/include/pybind11_json/pybind11_json.hpp @@ -0,0 +1,223 @@ +/*************************************************************************** +* Copyright (c) 2019, Martin Renou * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef PYBIND11_JSON_HPP +#define PYBIND11_JSON_HPP + +#include +#include + +#include "nlohmann/json.hpp" + +#include "pybind11/pybind11.h" + +namespace py = pybind11; +namespace nl = nlohmann; + +namespace pyjson +{ + inline py::object from_json(const nl::json& j) + { + if (j.is_null()) + { + return py::none(); + } + else if (j.is_boolean()) + { + return py::bool_(j.get()); + } + else if (j.is_number_integer()) + { + return py::int_(j.get()); + } + else if (j.is_number_unsigned()) + { + return py::int_(j.get()); + } + else if (j.is_number_float()) + { + return py::float_(j.get()); + } + else if (j.is_string()) + { + return py::str(j.get()); + } + else if (j.is_array()) + { + py::list obj; + for (const auto& el : j) + { + obj.append(from_json(el)); + } + return std::move(obj); + } + else // Object + { + py::dict obj; + for (nl::json::const_iterator it = j.cbegin(); it != j.cend(); ++it) + { + obj[py::str(it.key())] = from_json(it.value()); + } + return std::move(obj); + } + } + + inline nl::json to_json(const py::handle& obj) + { + if (obj.ptr() == nullptr || obj.is_none()) + { + return nullptr; + } + if (py::isinstance(obj)) + { + return obj.cast(); + } + if (py::isinstance(obj)) + { + try + { + nl::json::number_integer_t s = obj.cast(); + if (py::int_(s).equal(obj)) + { + return s; + } + } + catch (...) + { + } + try + { + nl::json::number_unsigned_t u = obj.cast(); + if (py::int_(u).equal(obj)) + { + return u; + } + } + catch (...) + { + } + throw std::runtime_error("to_json received an integer out of range for both nl::json::number_integer_t and nl::json::number_unsigned_t type: " + py::repr(obj).cast()); + } + if (py::isinstance(obj)) + { + return obj.cast(); + } + if (py::isinstance(obj)) + { + py::module base64 = py::module::import("base64"); + return base64.attr("b64encode")(obj).attr("decode")("utf-8").cast(); + } + if (py::isinstance(obj)) + { + return obj.cast(); + } + if (py::isinstance(obj) || py::isinstance(obj)) + { + auto out = nl::json::array(); + for (const py::handle value : obj) + { + out.push_back(to_json(value)); + } + return out; + } + if (py::isinstance(obj)) + { + auto out = nl::json::object(); + for (const py::handle key : obj) + { + out[py::str(key).cast()] = to_json(obj[key]); + } + return out; + } + throw std::runtime_error("to_json not implemented for this type of object: " + py::repr(obj).cast()); + } +} + +// nlohmann_json serializers +namespace nlohmann +{ + #define MAKE_NLJSON_SERIALIZER_DESERIALIZER(T) \ + template <> \ + struct adl_serializer \ + { \ + inline static void to_json(json& j, const T& obj) \ + { \ + j = pyjson::to_json(obj); \ + } \ + \ + inline static T from_json(const json& j) \ + { \ + return pyjson::from_json(j); \ + } \ + } + + #define MAKE_NLJSON_SERIALIZER_ONLY(T) \ + template <> \ + struct adl_serializer \ + { \ + inline static void to_json(json& j, const T& obj) \ + { \ + j = pyjson::to_json(obj); \ + } \ + } + + MAKE_NLJSON_SERIALIZER_DESERIALIZER(py::object); + + MAKE_NLJSON_SERIALIZER_DESERIALIZER(py::bool_); + MAKE_NLJSON_SERIALIZER_DESERIALIZER(py::int_); + MAKE_NLJSON_SERIALIZER_DESERIALIZER(py::float_); + MAKE_NLJSON_SERIALIZER_DESERIALIZER(py::str); + + MAKE_NLJSON_SERIALIZER_DESERIALIZER(py::list); + MAKE_NLJSON_SERIALIZER_DESERIALIZER(py::tuple); + MAKE_NLJSON_SERIALIZER_DESERIALIZER(py::dict); + + MAKE_NLJSON_SERIALIZER_ONLY(py::handle); + MAKE_NLJSON_SERIALIZER_ONLY(py::detail::item_accessor); + MAKE_NLJSON_SERIALIZER_ONLY(py::detail::list_accessor); + MAKE_NLJSON_SERIALIZER_ONLY(py::detail::tuple_accessor); + MAKE_NLJSON_SERIALIZER_ONLY(py::detail::sequence_accessor); + MAKE_NLJSON_SERIALIZER_ONLY(py::detail::str_attr_accessor); + MAKE_NLJSON_SERIALIZER_ONLY(py::detail::obj_attr_accessor); + + #undef MAKE_NLJSON_SERIALIZER + #undef MAKE_NLJSON_SERIALIZER_ONLY +} + +// pybind11 caster +namespace pybind11 +{ + namespace detail + { + template <> struct type_caster + { + public: + PYBIND11_TYPE_CASTER(nl::json, _("json")); + + bool load(handle src, bool) + { + try { + value = pyjson::to_json(src); + return true; + } + catch (...) + { + return false; + } + } + + static handle cast(nl::json src, return_value_policy /* policy */, handle /* parent */) + { + object obj = pyjson::from_json(src); + return obj.release(); + } + }; + } +} + +#endif diff --git a/src/DeviceBootloaderBindings.cpp b/src/DeviceBootloaderBindings.cpp index 890364a30..a975bc10b 100644 --- a/src/DeviceBootloaderBindings.cpp +++ b/src/DeviceBootloaderBindings.cpp @@ -13,6 +13,9 @@ void DeviceBootloaderBindings::bind(pybind11::module& m, void* pCallstack){ py::enum_ deviceBootloaderType(deviceBootloader, "Type"); py::enum_ deviceBootloaderMemory(deviceBootloader, "Memory"); py::enum_ deviceBootloaderSection(deviceBootloader, "Section"); + py::class_ deviceBootlaoderUsbConfig(deviceBootloader, "UsbConfig"); + py::class_ deviceBootlaoderNetworkConfig(deviceBootloader, "NetworkConfig"); + py::class_ deviceBootloderConfig(deviceBootloader, "Config"); /////////////////////////////////////////////////////////////////////// @@ -39,20 +42,72 @@ void DeviceBootloaderBindings::bind(pybind11::module& m, void* pCallstack){ ; deviceBootloaderType + .value("AUTO", DeviceBootloader::Type::AUTO) .value("USB", DeviceBootloader::Type::USB) .value("NETWORK", DeviceBootloader::Type::NETWORK) ; deviceBootloaderMemory + .value("AUTO", DeviceBootloader::Memory::AUTO) .value("FLASH", DeviceBootloader::Memory::FLASH) .value("EMMC", DeviceBootloader::Memory::EMMC) ; deviceBootloaderSection + .value("AUTO", DeviceBootloader::Section::AUTO) .value("HEADER", DeviceBootloader::Section::HEADER) .value("BOOTLOADER", DeviceBootloader::Section::BOOTLOADER) .value("BOOTLOADER_CONFIG", DeviceBootloader::Section::BOOTLOADER_CONFIG) .value("APPLICATION", DeviceBootloader::Section::APPLICATION) ; + deviceBootlaoderUsbConfig + .def(py::init<>()) + .def_readwrite("timeoutMs", &DeviceBootloader::UsbConfig::timeoutMs) + .def_readwrite("maxUsbSpeed", &DeviceBootloader::UsbConfig::maxUsbSpeed) + .def_readwrite("vid", &DeviceBootloader::UsbConfig::vid) + .def_readwrite("pid", &DeviceBootloader::UsbConfig::pid) + ; + deviceBootlaoderNetworkConfig + .def(py::init<>()) + .def_readwrite("timeoutMs", &DeviceBootloader::NetworkConfig::timeoutMs) + .def_readwrite("ipv4", &DeviceBootloader::NetworkConfig::ipv4) + .def_readwrite("ipv4Mask", &DeviceBootloader::NetworkConfig::ipv4Mask) + .def_readwrite("ipv4Gateway", &DeviceBootloader::NetworkConfig::ipv4Gateway) + .def_readwrite("ipv4Dns", &DeviceBootloader::NetworkConfig::ipv4Dns) + .def_readwrite("ipv4DnsAlt", &DeviceBootloader::NetworkConfig::ipv4DnsAlt) + .def_readwrite("staticIpv4", &DeviceBootloader::NetworkConfig::staticIpv4) + .def_readwrite("ipv6", &DeviceBootloader::NetworkConfig::ipv6) + .def_readwrite("ipv6Prefix", &DeviceBootloader::NetworkConfig::ipv6Prefix) + .def_readwrite("ipv6Gateway", &DeviceBootloader::NetworkConfig::ipv6Gateway) + .def_readwrite("ipv6Dns", &DeviceBootloader::NetworkConfig::ipv6Dns) + .def_readwrite("ipv6DnsAlt", &DeviceBootloader::NetworkConfig::ipv6DnsAlt) + .def_readwrite("staticIpv6", &DeviceBootloader::NetworkConfig::staticIpv6) + .def_readwrite("mac", &DeviceBootloader::NetworkConfig::mac) + ; + + deviceBootloderConfig + .def(py::init<>()) + .def_readwrite("appMem", &DeviceBootloader::Config::appMem) + .def_readwrite("usb", &DeviceBootloader::Config::usb) + .def_readwrite("network", &DeviceBootloader::Config::network) + .def("setStaticIPv4", &DeviceBootloader::Config::setStaticIPv4) + .def("setDynamicIPv4", &DeviceBootloader::Config::setDynamicIPv4) + .def("isStaticIPV4", &DeviceBootloader::Config::isStaticIPV4) + .def("getIPv4", &DeviceBootloader::Config::getIPv4) + .def("getIPv4Mask", &DeviceBootloader::Config::getIPv4Mask) + .def("getIPv4Gateway", &DeviceBootloader::Config::getIPv4Gateway) + .def("setDnsIPv4", &DeviceBootloader::Config::setDnsIPv4) + .def("getDnsIPv4", &DeviceBootloader::Config::getDnsIPv4) + .def("getDnsAltIPv4", &DeviceBootloader::Config::getDnsAltIPv4) + .def("setUsbTimeout", &DeviceBootloader::Config::setUsbTimeout) + .def("getUsbTimeout", &DeviceBootloader::Config::getUsbTimeout) + .def("setNetworkTimeout", &DeviceBootloader::Config::setNetworkTimeout) + .def("getNetworkTimeout", &DeviceBootloader::Config::getNetworkTimeout) + .def("setMacAddress", &DeviceBootloader::Config::setMacAddress) + .def("getMacAddress", &DeviceBootloader::Config::getMacAddress) + .def("setUsbMaxSpeed", &DeviceBootloader::Config::setUsbMaxSpeed) + .def("getUsbMaxSpeed", &DeviceBootloader::Config::getUsbMaxSpeed) + ; + deviceBootloader // Python only methods .def("__enter__", [](py::object obj){ return obj; }) @@ -61,21 +116,38 @@ void DeviceBootloaderBindings::bind(pybind11::module& m, void* pCallstack){ .def_static("getFirstAvailableDevice", &DeviceBootloader::getFirstAvailableDevice, DOC(dai, DeviceBootloader, getFirstAvailableDevice)) .def_static("getAllAvailableDevices", &DeviceBootloader::getAllAvailableDevices, DOC(dai, DeviceBootloader, getAllAvailableDevices)) - .def_static("saveDepthaiApplicationPackage", &DeviceBootloader::saveDepthaiApplicationPackage, py::arg("path"), py::arg("pipeline"), py::arg("pathToCmd") = "", DOC(dai, DeviceBootloader, saveDepthaiApplicationPackage)) - .def_static("createDepthaiApplicationPackage", &DeviceBootloader::createDepthaiApplicationPackage, py::arg("pipeline"), py::arg("pathToCmd") = "", DOC(dai, DeviceBootloader, createDepthaiApplicationPackage)) + .def_static("saveDepthaiApplicationPackage", py::overload_cast(&DeviceBootloader::saveDepthaiApplicationPackage), py::arg("path"), py::arg("pipeline"), py::arg("pathToCmd") = "", py::arg("compress") = false, DOC(dai, DeviceBootloader, saveDepthaiApplicationPackage)) + .def_static("saveDepthaiApplicationPackage", py::overload_cast(&DeviceBootloader::saveDepthaiApplicationPackage), py::arg("path"), py::arg("pipeline"), py::arg("compress") = false, DOC(dai, DeviceBootloader, saveDepthaiApplicationPackage, 2)) + .def_static("createDepthaiApplicationPackage", py::overload_cast(&DeviceBootloader::createDepthaiApplicationPackage), py::arg("pipeline"), py::arg("pathToCmd") = "", py::arg("compress") = false, DOC(dai, DeviceBootloader, createDepthaiApplicationPackage)) + .def_static("createDepthaiApplicationPackage", py::overload_cast(&DeviceBootloader::createDepthaiApplicationPackage), py::arg("pipeline"), py::arg("compress"), DOC(dai, DeviceBootloader, createDepthaiApplicationPackage, 2)) .def_static("getEmbeddedBootloaderVersion", &DeviceBootloader::getEmbeddedBootloaderVersion, DOC(dai, DeviceBootloader, getEmbeddedBootloaderVersion)) .def_static("getEmbeddedBootloaderBinary", &DeviceBootloader::getEmbeddedBootloaderBinary, DOC(dai, DeviceBootloader, getEmbeddedBootloaderBinary)) - .def(py::init(), py::arg("deviceDesc"), DOC(dai, DeviceBootloader, DeviceBootloader)) - .def(py::init(), py::arg("deviceDesc"), py::arg("pathToCmd"), DOC(dai, DeviceBootloader, DeviceBootloader, 2)) - .def("flash", [](DeviceBootloader& db, std::function progressCallback, Pipeline& pipeline) { py::gil_scoped_release release; return db.flash(progressCallback, pipeline); }, py::arg("progressCallback"), py::arg("pipeline"), DOC(dai, DeviceBootloader, flash)) + .def(py::init(), py::arg("devInfo"), py::arg("allowFlashingBootloader") = false, DOC(dai, DeviceBootloader, DeviceBootloader)) + .def(py::init(), py::arg("devInfo"), py::arg("pathToCmd"), py::arg("allowFlashingBootloader") = false, DOC(dai, DeviceBootloader, DeviceBootloader, 2)) + .def("flash", [](DeviceBootloader& db, std::function progressCallback, const Pipeline& pipeline, bool compress) { py::gil_scoped_release release; return db.flash(progressCallback, pipeline, compress); }, py::arg("progressCallback"), py::arg("pipeline"), py::arg("compress") = false, DOC(dai, DeviceBootloader, flash)) + .def("flash", [](DeviceBootloader& db, const Pipeline& pipeline, bool compress) { py::gil_scoped_release release; return db.flash(pipeline, compress); }, py::arg("pipeline"), py::arg("compress") = false, DOC(dai, DeviceBootloader, flash, 2)) .def("flashDepthaiApplicationPackage", [](DeviceBootloader& db, std::function progressCallback, std::vector package) { py::gil_scoped_release release; return db.flashDepthaiApplicationPackage(progressCallback, package); }, py::arg("progressCallback"), py::arg("package"), DOC(dai, DeviceBootloader, flashDepthaiApplicationPackage)) + .def("flashDepthaiApplicationPackage", [](DeviceBootloader& db, std::vector package) { py::gil_scoped_release release; return db.flashDepthaiApplicationPackage(package); }, py::arg("package"), DOC(dai, DeviceBootloader, flashDepthaiApplicationPackage, 2)) .def("flashBootloader", [](DeviceBootloader& db, std::function progressCallback, std::string path) { py::gil_scoped_release release; return db.flashBootloader(progressCallback, path); }, py::arg("progressCallback"), py::arg("path") = "", DOC(dai, DeviceBootloader, flashBootloader)) .def("flashBootloader", [](DeviceBootloader& db, DeviceBootloader::Memory memory, DeviceBootloader::Type type, std::function progressCallback, std::string path) { py::gil_scoped_release release; return db.flashBootloader(memory, type, progressCallback, path); }, py::arg("memory"), py::arg("type"), py::arg("progressCallback"), py::arg("path") = "", DOC(dai, DeviceBootloader, flashBootloader, 2)) + + .def("readConfigData", [](DeviceBootloader& db, DeviceBootloader::Memory memory, DeviceBootloader::Type type) { py::gil_scoped_release release; return db.readConfigData(memory, type); }, py::arg("memory") = DeviceBootloader::Memory::AUTO, py::arg("type") = DeviceBootloader::Type::AUTO, DOC(dai, DeviceBootloader, readConfigData)) + .def("flashConfigData", [](DeviceBootloader& db, nlohmann::json configData, DeviceBootloader::Memory memory, DeviceBootloader::Type type) { py::gil_scoped_release release; return db.flashConfigData(configData, memory, type); }, py::arg("configData"), py::arg("memory") = DeviceBootloader::Memory::AUTO, py::arg("type") = DeviceBootloader::Type::AUTO, DOC(dai, DeviceBootloader, flashConfigData)) + .def("flashConfigFile", [](DeviceBootloader& db, std::string configPath, DeviceBootloader::Memory memory, DeviceBootloader::Type type) { py::gil_scoped_release release; return db.flashConfigFile(configPath, memory, type); }, py::arg("configData"), py::arg("memory") = DeviceBootloader::Memory::AUTO, py::arg("type") = DeviceBootloader::Type::AUTO, DOC(dai, DeviceBootloader, flashConfigFile)) + .def("flashConfigClear", [](DeviceBootloader& db, DeviceBootloader::Memory memory, DeviceBootloader::Type type) { py::gil_scoped_release release; return db.flashConfigClear(memory, type); }, py::arg("memory") = DeviceBootloader::Memory::AUTO, py::arg("type") = DeviceBootloader::Type::AUTO, DOC(dai, DeviceBootloader, flashConfigClear)) + .def("readConfig", [](DeviceBootloader& db, DeviceBootloader::Memory memory, DeviceBootloader::Type type) { py::gil_scoped_release release; return db.readConfig(memory, type); }, py::arg("memory") = DeviceBootloader::Memory::AUTO, py::arg("type") = DeviceBootloader::Type::AUTO, DOC(dai, DeviceBootloader, readConfig)) + .def("flashConfig", [](DeviceBootloader& db, const DeviceBootloader::Config& config, DeviceBootloader::Memory memory, DeviceBootloader::Type type) { py::gil_scoped_release release; return db.flashConfig(config, memory, type); }, py::arg("config"), py::arg("memory") = DeviceBootloader::Memory::AUTO, py::arg("type") = DeviceBootloader::Type::AUTO, DOC(dai, DeviceBootloader, flashConfig)) + + .def("bootMemory", [](DeviceBootloader& db, const std::vector& fw) { py::gil_scoped_release release; return db.bootMemory(fw); }, py::arg("fw"), DOC(dai, DeviceBootloader, bootMemory)) + .def("bootUsbRomBootloader", [](DeviceBootloader& db) { py::gil_scoped_release release; return db.bootUsbRomBootloader(); }, DOC(dai, DeviceBootloader, bootUsbRomBootloader)) + //.def("flashCustom", &DeviceBootloader::flashCustom, py::arg("memory"), py::arg("offset"), py::arg("progressCallback"), py::arg("data"), DOC(dai, DeviceBootloader, flashCustom)) .def("getVersion", [](DeviceBootloader& db) { py::gil_scoped_release release; return db.getVersion(); }, DOC(dai, DeviceBootloader, getVersion)) .def("isEmbeddedVersion", &DeviceBootloader::isEmbeddedVersion, DOC(dai, DeviceBootloader, isEmbeddedVersion)) + .def("getType", &DeviceBootloader::getType, DOC(dai, DeviceBootloader, getType)) + .def("isAllowedFlashingBootloader", &DeviceBootloader::isAllowedFlashingBootloader, DOC(dai, DeviceBootloader, isAllowedFlashingBootloader)) ; } diff --git a/src/pybind11_common.hpp b/src/pybind11_common.hpp index 8fbab8dd8..1669cdf40 100644 --- a/src/pybind11_common.hpp +++ b/src/pybind11_common.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include