Skip to content
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
53 changes: 53 additions & 0 deletions examples/bootloader_config.py
Original file line number Diff line number Diff line change
@@ -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')
51 changes: 51 additions & 0 deletions examples/flash_bootloader.py
Original file line number Diff line number Diff line change
@@ -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)
4 changes: 3 additions & 1 deletion external/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
# Add 'hedley' library
add_subdirectory(hedley)
add_subdirectory(hedley)
# Add 'pybind11_json' library
add_subdirectory(pybind11_json)
3 changes: 3 additions & 0 deletions external/pybind11_json/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# pybind11_json library
add_library(pybind11_json INTERFACE)
target_include_directories(pybind11_json INTERFACE "${CMAKE_CURRENT_LIST_DIR}/include")
223 changes: 223 additions & 0 deletions external/pybind11_json/include/pybind11_json/pybind11_json.hpp
Original file line number Diff line number Diff line change
@@ -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 <string>
#include <vector>

#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<bool>());
}
else if (j.is_number_integer())
{
return py::int_(j.get<nl::json::number_integer_t>());
}
else if (j.is_number_unsigned())
{
return py::int_(j.get<nl::json::number_unsigned_t>());
}
else if (j.is_number_float())
{
return py::float_(j.get<double>());
}
else if (j.is_string())
{
return py::str(j.get<std::string>());
}
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<py::bool_>(obj))
{
return obj.cast<bool>();
}
if (py::isinstance<py::int_>(obj))
{
try
{
nl::json::number_integer_t s = obj.cast<nl::json::number_integer_t>();
if (py::int_(s).equal(obj))
{
return s;
}
}
catch (...)
{
}
try
{
nl::json::number_unsigned_t u = obj.cast<nl::json::number_unsigned_t>();
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<std::string>());
}
if (py::isinstance<py::float_>(obj))
{
return obj.cast<double>();
}
if (py::isinstance<py::bytes>(obj))
{
py::module base64 = py::module::import("base64");
return base64.attr("b64encode")(obj).attr("decode")("utf-8").cast<std::string>();
}
if (py::isinstance<py::str>(obj))
{
return obj.cast<std::string>();
}
if (py::isinstance<py::tuple>(obj) || py::isinstance<py::list>(obj))
{
auto out = nl::json::array();
for (const py::handle value : obj)
{
out.push_back(to_json(value));
}
return out;
}
if (py::isinstance<py::dict>(obj))
{
auto out = nl::json::object();
for (const py::handle key : obj)
{
out[py::str(key).cast<std::string>()] = to_json(obj[key]);
}
return out;
}
throw std::runtime_error("to_json not implemented for this type of object: " + py::repr(obj).cast<std::string>());
}
}

// nlohmann_json serializers
namespace nlohmann
{
#define MAKE_NLJSON_SERIALIZER_DESERIALIZER(T) \
template <> \
struct adl_serializer<T> \
{ \
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<T> \
{ \
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<nl::json>
{
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
Loading