diff --git a/cmake/Depthai/DepthaiDeviceSideConfig.cmake b/cmake/Depthai/DepthaiDeviceSideConfig.cmake index ee644ce360..708a9b0227 100644 --- a/cmake/Depthai/DepthaiDeviceSideConfig.cmake +++ b/cmake/Depthai/DepthaiDeviceSideConfig.cmake @@ -2,7 +2,7 @@ set(DEPTHAI_DEVICE_SIDE_MATURITY "snapshot") # "full commit hash of device side binary" -set(DEPTHAI_DEVICE_SIDE_COMMIT "e88cdb4afa8be3cbbf8c739601f1aa1b2fd5395b") +set(DEPTHAI_DEVICE_SIDE_COMMIT "3f22c4cf67ca3ec8dcf5e01fffdf9137f49aefbf") # "version if applicable" set(DEPTHAI_DEVICE_SIDE_VERSION "") diff --git a/examples/src/rgb_preview.cpp b/examples/src/rgb_preview.cpp index 911f7d1d95..eba6edca35 100644 --- a/examples/src/rgb_preview.cpp +++ b/examples/src/rgb_preview.cpp @@ -25,11 +25,10 @@ int main() { camRgb->preview.link(xoutRgb->input); // Connect to device and start pipeline - dai::Device device(pipeline); + dai::Device device(pipeline, dai::UsbSpeed::SUPER); cout << "Connected cameras: "; for(const auto& cam : device.getConnectedCameras()) { - cout << static_cast(cam) << " "; cout << cam << " "; } cout << endl; diff --git a/include/depthai/device/Device.hpp b/include/depthai/device/Device.hpp index 240f71466d..125670ac2c 100644 --- a/include/depthai/device/Device.hpp +++ b/include/depthai/device/Device.hpp @@ -13,7 +13,7 @@ #include "depthai/common/CameraBoardSocket.hpp" #include "depthai/common/UsbSpeed.hpp" #include "depthai/device/CalibrationHandler.hpp" -#include "depthai/pipeline/Pipeline.hpp" +#include "depthai/openvino/OpenVINO.hpp" #include "depthai/utility/Pimpl.hpp" #include "depthai/xlink/XLinkConnection.hpp" #include "depthai/xlink/XLinkStream.hpp" @@ -22,12 +22,15 @@ #include "depthai-shared/common/ChipTemperature.hpp" #include "depthai-shared/common/CpuUsage.hpp" #include "depthai-shared/common/MemoryInfo.hpp" +#include "depthai-shared/device/PrebootConfig.hpp" #include "depthai-shared/log/LogLevel.hpp" #include "depthai-shared/log/LogMessage.hpp" +#include "tl/optional.hpp" namespace dai { -// Device (RAII), connects to device and maintains watchdog, timesync, ... +// Forward declare Pipeline +class Pipeline; /** * Represents the DepthAI device with the methods to interact with it. @@ -42,6 +45,18 @@ class Device { static constexpr std::size_t EVENT_QUEUE_MAXIMUM_SIZE{2048}; /// Default rate at which system information is logged static constexpr float DEFAULT_SYSTEM_INFORMATION_LOGGING_RATE_HZ{1.0f}; + /// Default UsbSpeed for device connection + static constexpr UsbSpeed DEFAULT_USB_SPEED{UsbSpeed::SUPER}; + + // Structures + + /** + * Device specific configuration + */ + struct Config { + OpenVINO::Version version; + PrebootConfig preboot; + }; // static API @@ -86,7 +101,7 @@ class Device { * @param version Version of OpenVINO which firmware will support * @returns Firmware binary */ - static std::vector getEmbeddedDeviceBinary(bool usb2Mode, OpenVINO::Version version = Pipeline::DEFAULT_OPENVINO_VERSION); + static std::vector getEmbeddedDeviceBinary(bool usb2Mode, OpenVINO::Version version = OpenVINO::DEFAULT_VERSION); /** * Connects to any available device with a DEFAULT_SEARCH_TIME timeout. @@ -104,15 +119,16 @@ class Device { /** * Connects to any available device with a DEFAULT_SEARCH_TIME timeout. * @param pipeline Pipeline to be executed on the device - * @param pathToCmd Path to custom device firmware + * @param maxUsbSpeed Maximum allowed USB speed */ - Device(const Pipeline& pipeline, const char* pathToCmd); + Device(const Pipeline& pipeline, UsbSpeed maxUsbSpeed); /** * Connects to any available device with a DEFAULT_SEARCH_TIME timeout. * @param pipeline Pipeline to be executed on the device * @param pathToCmd Path to custom device firmware */ + Device(const Pipeline& pipeline, const char* pathToCmd); Device(const Pipeline& pipeline, const std::string& pathToCmd); /** @@ -127,23 +143,24 @@ class Device { * Connects to device specified by devInfo. * @param pipeline Pipeline to be executed on the device * @param devInfo DeviceInfo which specifies which device to connect to - * @param pathToCmd Path to custom device firmware + * @param maxUsbSpeed Maximum allowed USB speed */ - Device(const Pipeline& pipeline, const DeviceInfo& devInfo, const char* pathToCmd); + Device(const Pipeline& pipeline, const DeviceInfo& devInfo, UsbSpeed maxUsbSpeed); /** * Connects to device specified by devInfo. * @param pipeline Pipeline to be executed on the device * @param devInfo DeviceInfo which specifies which device to connect to - * @param usb2Mode Path to custom device firmware + * @param pathToCmd Path to custom device firmware */ + Device(const Pipeline& pipeline, const DeviceInfo& devInfo, const char* pathToCmd); Device(const Pipeline& pipeline, const DeviceInfo& devInfo, const std::string& pathToCmd); /** * Connects to any available device with a DEFAULT_SEARCH_TIME timeout. - * @param version OpenVINO version which the device will be booted with. Default is Pipeline::DEFAULT_OPENVINO_VERSION + * @param version OpenVINO version which the device will be booted with. Default is OpenVINO::DEFAULT_VERSION */ - explicit Device(OpenVINO::Version version = Pipeline::DEFAULT_OPENVINO_VERSION); + explicit Device(OpenVINO::Version version = OpenVINO::DEFAULT_VERSION); /** * Connects to any available device with a DEFAULT_SEARCH_TIME timeout. @@ -155,15 +172,16 @@ class Device { /** * Connects to any available device with a DEFAULT_SEARCH_TIME timeout. * @param version OpenVINO version which the device will be booted with - * @param pathToCmd Path to custom device firmware + * @param maxUsbSpeed Maximum allowed USB speed */ - Device(OpenVINO::Version version, const char* pathToCmd); + Device(OpenVINO::Version version, UsbSpeed maxUsbSpeed); /** * Connects to any available device with a DEFAULT_SEARCH_TIME timeout. * @param version OpenVINO version which the device will be booted with * @param pathToCmd Path to custom device firmware */ + Device(OpenVINO::Version version, const char* pathToCmd); Device(OpenVINO::Version version, const std::string& pathToCmd); /** @@ -178,18 +196,32 @@ class Device { * Connects to device specified by devInfo. * @param version OpenVINO version which the device will be booted with * @param devInfo DeviceInfo which specifies which device to connect to - * @param pathToCmd Path to custom device firmware + * @param maxUsbSpeed Maximum USB speed */ - Device(OpenVINO::Version version, const DeviceInfo& devInfo, const char* pathToCmd); + Device(OpenVINO::Version version, const DeviceInfo& devInfo, UsbSpeed maxUsbSpeed); /** * Connects to device specified by devInfo. * @param version OpenVINO version which the device will be booted with * @param devInfo DeviceInfo which specifies which device to connect to - * @param usb2Mode Path to custom device firmware + * @param pathToCmd Path to custom device firmware */ + Device(OpenVINO::Version version, const DeviceInfo& devInfo, const char* pathToCmd); Device(OpenVINO::Version version, const DeviceInfo& devInfo, const std::string& pathToCmd); + /** + * Connects to any available device with custom config. + * @param config Device custom configuration to boot with + */ + explicit Device(Config config); + + /** + * Connects to device 'devInfo' with custom config. + * @param devInfo DeviceInfo which specifies which device to connect to + * @param config Device custom configuration to boot with + */ + Device(const DeviceInfo& devInfo, Config config); + /** * Device destructor. Closes the connection and data queues. */ @@ -499,10 +531,12 @@ class Device { bool isClosed() const; private: - // private static - void init(OpenVINO::Version version, bool embeddedMvcmd, bool usb2Mode, const std::string& pathToMvcmd); - void init(const Pipeline& pipeline, bool embeddedMvcmd, bool usb2Mode, const std::string& pathToMvcmd); - void init2(bool embeddedMvcmd, bool usb2Mode, const std::string& pathToMvcmd, tl::optional pipeline); + // private + void init(OpenVINO::Version version, bool usb2Mode, const std::string& pathToMvcmd); + void init(const Pipeline& pipeline, bool usb2Mode, const std::string& pathToMvcmd); + void init(OpenVINO::Version version, UsbSpeed maxUsbSpeed, const std::string& pathToMvcmd); + void init(const Pipeline& pipeline, UsbSpeed maxUsbSpeed, const std::string& pathToMvcmd); + void init2(Config cfg, const std::string& pathToMvcmd, tl::optional pipeline); void checkClosed() const; std::shared_ptr connection; @@ -544,8 +578,8 @@ class Device { class Impl; Pimpl pimpl; - // OpenVINO version device was booted with - OpenVINO::Version openvinoVersion; + // Device config + Config config; }; } // namespace dai diff --git a/include/depthai/openvino/OpenVINO.hpp b/include/depthai/openvino/OpenVINO.hpp index beb9da4a41..228821c1db 100644 --- a/include/depthai/openvino/OpenVINO.hpp +++ b/include/depthai/openvino/OpenVINO.hpp @@ -15,6 +15,9 @@ class OpenVINO { /// OpenVINO Version supported version information enum Version { VERSION_2020_3, VERSION_2020_4, VERSION_2021_1, VERSION_2021_2, VERSION_2021_3, VERSION_2021_4 }; + /// Main OpenVINO version + constexpr static const Version DEFAULT_VERSION = VERSION_2021_4; + /** * @returns Supported versions */ diff --git a/include/depthai/pipeline/Pipeline.hpp b/include/depthai/pipeline/Pipeline.hpp index 11d5f0d549..153db114a0 100644 --- a/include/depthai/pipeline/Pipeline.hpp +++ b/include/depthai/pipeline/Pipeline.hpp @@ -10,9 +10,11 @@ #include "AssetManager.hpp" #include "Node.hpp" #include "depthai/device/CalibrationHandler.hpp" +#include "depthai/device/Device.hpp" #include "depthai/openvino/OpenVINO.hpp" // shared +#include "depthai-shared/device/PrebootConfig.hpp" #include "depthai-shared/pipeline/PipelineSchema.hpp" #include "depthai-shared/properties/GlobalProperties.hpp" @@ -34,7 +36,9 @@ class PipelineImpl { // Functions Node::Id getNextUniqueId(); PipelineSchema getPipelineSchema() const; - OpenVINO::Version getPipelineOpenVINOVersion() const; + tl::optional getPipelineOpenVINOVersion() const; + bool isOpenVINOVersionCompatible(OpenVINO::Version version) const; + Device::Config getDeviceConfig() const; void setCameraTuningBlobPath(const std::string& path); // Access to nodes @@ -43,7 +47,7 @@ class PipelineImpl { std::shared_ptr getNode(Node::Id id) const; std::shared_ptr getNode(Node::Id id); - void serialize(PipelineSchema& schema, Assets& assets, std::vector& assetStorage, OpenVINO::Version& version) const; + void serialize(PipelineSchema& schema, Assets& assets, std::vector& assetStorage) const; void remove(std::shared_ptr node); std::vector getConnections() const; @@ -56,8 +60,6 @@ class PipelineImpl { Node::Id latestId = 0; // Pipeline asset manager AssetManager assetManager; - // Default version - constexpr static auto DEFAULT_OPENVINO_VERSION = OpenVINO::Version::VERSION_2021_4; // Optionally forced version tl::optional forceRequiredOpenVINOVersion; // Global pipeline properties @@ -106,9 +108,6 @@ class Pipeline { /// Clone the pipeline (Creates a copy) Pipeline clone() const; - /// Default Pipeline openvino version - constexpr static auto DEFAULT_OPENVINO_VERSION = PipelineImpl::DEFAULT_OPENVINO_VERSION; - /** * @returns Global properties of current pipeline */ @@ -120,8 +119,8 @@ class Pipeline { PipelineSchema getPipelineSchema(); // void loadAssets(AssetManager& assetManager); - void serialize(PipelineSchema& schema, Assets& assets, std::vector& assetStorage, OpenVINO::Version& version) const { - impl()->serialize(schema, assets, assetStorage, version); + void serialize(PipelineSchema& schema, Assets& assets, std::vector& assetStorage) const { + impl()->serialize(schema, assets, assetStorage); } /** @@ -231,8 +230,13 @@ class Pipeline { return impl()->getCalibrationData(); } - /// Get required OpenVINO version to run this pipeline + /// Get possible OpenVINO version to run this pipeline OpenVINO::Version getOpenVINOVersion() const { + return impl()->getPipelineOpenVINOVersion().value_or(OpenVINO::DEFAULT_VERSION); + } + + /// Get required OpenVINO version to run this pipeline. Can be none + tl::optional getRequiredOpenVINOVersion() const { return impl()->getPipelineOpenVINOVersion(); } @@ -240,6 +244,16 @@ class Pipeline { void setCameraTuningBlobPath(const std::string& path) { impl()->setCameraTuningBlobPath(path); } + + /// Checks whether a given OpenVINO version is compatible with the pipeline + bool isOpenVINOVersionCompatible(OpenVINO::Version version) const { + return impl()->isOpenVINOVersionCompatible(version); + } + + /// Get device configuration needed for this pipeline + Device::Config getDeviceConfig() const { + return impl()->getDeviceConfig(); + } }; } // namespace dai diff --git a/shared/depthai-shared b/shared/depthai-shared index cb3164a3a4..ed716b8306 160000 --- a/shared/depthai-shared +++ b/shared/depthai-shared @@ -1 +1 @@ -Subproject commit cb3164a3a41e013cd8841eb90e4898276c3517fc +Subproject commit ed716b830630e3fdfdc1323473e913ef06939721 diff --git a/shared/depthai-shared.cmake b/shared/depthai-shared.cmake index 3e2f95285e..39722c9b1b 100644 --- a/shared/depthai-shared.cmake +++ b/shared/depthai-shared.cmake @@ -4,6 +4,7 @@ set(DEPTHAI_SHARED_3RDPARTY_HEADERS_PATH "depthai-shared/3rdparty") set(DEPTHAI_SHARED_SOURCES ${DEPTHAI_SHARED_FOLDER}/src/datatype/DatatypeEnum.cpp + ${DEPTHAI_SHARED_FOLDER}/src/utility/Checksum.cpp ) set(DEPTHAI_SHARED_PUBLIC_INCLUDE @@ -21,7 +22,7 @@ set(DEPTHAI_SHARED_INCLUDE # Try retriving depthai-shared commit hash (if cloned and not sources only) find_package(Git) if(GIT_FOUND AND NOT DEPTHAI_DOWNLOADED_SOURCES) - + # Check that submodule is initialized and updated execute_process( COMMAND ${GIT_EXECUTABLE} submodule status ${DEPTHAI_SHARED_FOLDER} @@ -32,7 +33,7 @@ if(GIT_FOUND AND NOT DEPTHAI_DOWNLOADED_SOURCES) string(SUBSTRING ${statusCommit} 0 1 status) if(${status} STREQUAL "-") message(FATAL_ERROR "Submodule 'depthai-shared' not initialized/updated. Run 'git submodule update --init --recursive' first") - endif() + endif() # Get depthai-shared current commit execute_process( diff --git a/src/device/CallbackHandler.cpp b/src/device/CallbackHandler.cpp index cf2176929f..1e4fe30036 100644 --- a/src/device/CallbackHandler.cpp +++ b/src/device/CallbackHandler.cpp @@ -18,7 +18,7 @@ CallbackHandler::CallbackHandler(std::shared_ptr conn, t = std::thread([this, streamName]() { try { // open stream with 1B write size (no writing will happen here) - XLinkStream stream(*connection, streamName, XLINK_USB_BUFFER_MAX_SIZE); + XLinkStream stream(*connection, streamName, device::XLINK_USB_BUFFER_MAX_SIZE); while(running) { // read packet diff --git a/src/device/DataQueue.cpp b/src/device/DataQueue.cpp index 9ee802213a..34e743a4f8 100644 --- a/src/device/DataQueue.cpp +++ b/src/device/DataQueue.cpp @@ -171,7 +171,7 @@ bool DataOutputQueue::removeCallback(int callbackId) { DataInputQueue::DataInputQueue(const std::shared_ptr& conn, const std::string& streamName, unsigned int maxSize, bool blocking) : queue(maxSize, blocking), name(streamName) { // open stream with default XLINK_USB_BUFFER_MAX_SIZE write size - XLinkStream stream(*conn, name, dai::XLINK_USB_BUFFER_MAX_SIZE); + XLinkStream stream(*conn, name, device::XLINK_USB_BUFFER_MAX_SIZE); writingThread = std::thread([this, stream = std::move(stream)]() mutable { std::uint64_t numPacketsSent = 0; diff --git a/src/device/Device.cpp b/src/device/Device.cpp index 4ac2637283..ee5060472d 100644 --- a/src/device/Device.cpp +++ b/src/device/Device.cpp @@ -27,6 +27,7 @@ // libraries #include "nanorpc/core/client.h" #include "nanorpc/packer/nlohmann_msgpack.h" +#include "spdlog/details/os.h" #include "spdlog/fmt/chrono.h" #include "spdlog/sinks/stdout_color_sinks.h" #include "spdlog/spdlog.h" @@ -88,6 +89,7 @@ template std::tuple Device::getAnyAvailableDevice(std::chrono: constexpr std::chrono::seconds Device::DEFAULT_SEARCH_TIME; constexpr std::size_t Device::EVENT_QUEUE_MAXIMUM_SIZE; constexpr float Device::DEFAULT_SYSTEM_INFORMATION_LOGGING_RATE_HZ; +constexpr UsbSpeed Device::DEFAULT_USB_SPEED; template std::tuple Device::getAnyAvailableDevice(std::chrono::duration timeout) { @@ -220,15 +222,19 @@ LogLevel Device::Impl::getLogLevel() { /////////////////////////////////////////////// Device::Device(const Pipeline& pipeline, const DeviceInfo& devInfo, bool usb2Mode) : deviceInfo(devInfo) { - init(pipeline, true, usb2Mode, ""); + init(pipeline, usb2Mode, ""); +} + +Device::Device(const Pipeline& pipeline, const DeviceInfo& devInfo, UsbSpeed maxUsbSpeed) : deviceInfo(devInfo) { + init(pipeline, maxUsbSpeed, ""); } Device::Device(const Pipeline& pipeline, const DeviceInfo& devInfo, const char* pathToCmd) : deviceInfo(devInfo) { - init(pipeline, false, false, std::string(pathToCmd)); + init(pipeline, false, std::string(pathToCmd)); } Device::Device(const Pipeline& pipeline, const DeviceInfo& devInfo, const std::string& pathToCmd) : deviceInfo(devInfo) { - init(pipeline, false, false, pathToCmd); + init(pipeline, false, pathToCmd); } Device::Device(const Pipeline& pipeline) { @@ -239,7 +245,7 @@ Device::Device(const Pipeline& pipeline) { // If no device found, throw if(!found) throw std::runtime_error("No available devices"); - init(pipeline, true, false, ""); + init(pipeline, false, ""); } Device::Device(const Pipeline& pipeline, const char* pathToCmd) { @@ -250,7 +256,7 @@ Device::Device(const Pipeline& pipeline, const char* pathToCmd) { // If no device found, throw if(!found) throw std::runtime_error("No available devices"); - init(pipeline, false, false, std::string(pathToCmd)); + init(pipeline, false, std::string(pathToCmd)); } Device::Device(const Pipeline& pipeline, const std::string& pathToCmd) { @@ -260,7 +266,17 @@ Device::Device(const Pipeline& pipeline, const std::string& pathToCmd) { // If no device found, throw if(!found) throw std::runtime_error("No available devices"); - init(pipeline, false, false, pathToCmd); + init(pipeline, false, pathToCmd); +} + +Device::Device(const Pipeline& pipeline, UsbSpeed maxUsbSpeed) { + // Searches for any available device for 'default' timeout + bool found = false; + std::tie(found, deviceInfo) = getAnyAvailableDevice(); + + // If no device found, throw + if(!found) throw std::runtime_error("No available devices"); + init(pipeline, maxUsbSpeed, ""); } Device::Device(const Pipeline& pipeline, bool usb2Mode) { @@ -270,19 +286,23 @@ Device::Device(const Pipeline& pipeline, bool usb2Mode) { // If no device found, throw if(!found) throw std::runtime_error("No available devices"); - init(pipeline, true, usb2Mode, ""); + init(pipeline, usb2Mode, ""); } Device::Device(OpenVINO::Version version, const DeviceInfo& devInfo, bool usb2Mode) : deviceInfo(devInfo) { - init(version, true, usb2Mode, ""); + init(version, usb2Mode, ""); +} + +Device::Device(OpenVINO::Version version, const DeviceInfo& devInfo, UsbSpeed maxUsbSpeed) : deviceInfo(devInfo) { + init(version, maxUsbSpeed, ""); } Device::Device(OpenVINO::Version version, const DeviceInfo& devInfo, const char* pathToCmd) : deviceInfo(devInfo) { - init(version, false, false, std::string(pathToCmd)); + init(version, false, std::string(pathToCmd)); } Device::Device(OpenVINO::Version version, const DeviceInfo& devInfo, const std::string& pathToCmd) : deviceInfo(devInfo) { - init(version, false, false, pathToCmd); + init(version, false, pathToCmd); } Device::Device(OpenVINO::Version version) { @@ -293,7 +313,7 @@ Device::Device(OpenVINO::Version version) { // If no device found, throw if(!found) throw std::runtime_error("No available devices"); - init(version, true, false, ""); + init(version, false, ""); } Device::Device(OpenVINO::Version version, const char* pathToCmd) { @@ -304,7 +324,7 @@ Device::Device(OpenVINO::Version version, const char* pathToCmd) { // If no device found, throw if(!found) throw std::runtime_error("No available devices"); - init(version, false, false, std::string(pathToCmd)); + init(version, false, std::string(pathToCmd)); } Device::Device(OpenVINO::Version version, const std::string& pathToCmd) { @@ -314,7 +334,7 @@ Device::Device(OpenVINO::Version version, const std::string& pathToCmd) { // If no device found, throw if(!found) throw std::runtime_error("No available devices"); - init(version, false, false, pathToCmd); + init(version, false, pathToCmd); } Device::Device(OpenVINO::Version version, bool usb2Mode) { @@ -324,7 +344,32 @@ Device::Device(OpenVINO::Version version, bool usb2Mode) { // If no device found, throw if(!found) throw std::runtime_error("No available devices"); - init(version, true, usb2Mode, ""); + init(version, usb2Mode, ""); +} + +Device::Device(OpenVINO::Version version, UsbSpeed maxUsbSpeed) { + // Searches for any available device for 'default' timeout + bool found = false; + std::tie(found, deviceInfo) = getAnyAvailableDevice(); + + // If no device found, throw + if(!found) throw std::runtime_error("No available devices"); + init(version, maxUsbSpeed, ""); +} + +Device::Device(Config config) { + // Searches for any available device for 'default' timeout + bool found = false; + std::tie(found, deviceInfo) = getAnyAvailableDevice(); + + // If no device found, throw + if(!found) throw std::runtime_error("No available devices"); + init2(config, {}, {}); +} + +Device::Device(const DeviceInfo& devInfo, Config config) { + deviceInfo = devInfo; + init2(config, {}, {}); } void Device::close() { @@ -382,46 +427,73 @@ Device::~Device() { close(); } -void Device::init(OpenVINO::Version version, bool embeddedMvcmd, bool usb2Mode, const std::string& pathToMvcmd) { - // Initalize depthai library if not already - initialize(); - +void Device::init(OpenVINO::Version version, bool usb2Mode, const std::string& pathToMvcmd) { + Config cfg; + // Specify usb speed + cfg.preboot.usb.maxSpeed = usb2Mode ? UsbSpeed::HIGH : Device::DEFAULT_USB_SPEED; // Specify the OpenVINO version - openvinoVersion = version; - - spdlog::debug("Device - OpenVINO version: {}", OpenVINO::getVersionName(openvinoVersion)); - - init2(embeddedMvcmd, usb2Mode, pathToMvcmd, tl::nullopt); + cfg.version = version; + init2(cfg, pathToMvcmd, {}); +} +void Device::init(const Pipeline& pipeline, bool usb2Mode, const std::string& pathToMvcmd) { + Config cfg = pipeline.getDeviceConfig(); + // Modify usb speed + cfg.preboot.usb.maxSpeed = usb2Mode ? UsbSpeed::HIGH : Device::DEFAULT_USB_SPEED; + init2(cfg, pathToMvcmd, pipeline); +} +void Device::init(OpenVINO::Version version, UsbSpeed maxUsbSpeed, const std::string& pathToMvcmd) { + Config cfg; + // Specify usb speed + cfg.preboot.usb.maxSpeed = maxUsbSpeed; + // Specify the OpenVINO version + cfg.version = version; + init2(cfg, pathToMvcmd, {}); +} +void Device::init(const Pipeline& pipeline, UsbSpeed maxUsbSpeed, const std::string& pathToMvcmd) { + Config cfg = pipeline.getDeviceConfig(); + // Modify usb speed + cfg.preboot.usb.maxSpeed = maxUsbSpeed; + init2(cfg, pathToMvcmd, pipeline); } -void Device::init(const Pipeline& pipeline, bool embeddedMvcmd, bool usb2Mode, const std::string& pathToMvcmd) { +void Device::init2(Config cfg, const std::string& pathToMvcmd, tl::optional pipeline) { // Initalize depthai library if not already initialize(); - // Mark the OpenVINO version - openvinoVersion = pipeline.getOpenVINOVersion(); + // Specify cfg + config = cfg; - spdlog::debug("Device - pipeline serialized, OpenVINO version: {}", OpenVINO::getVersionName(openvinoVersion)); - - init2(embeddedMvcmd, usb2Mode, pathToMvcmd, pipeline); -} + if(pipeline) { + spdlog::debug("Device - pipeline serialized, OpenVINO version: {}", OpenVINO::getVersionName(config.version)); + } else { + spdlog::debug("Device - OpenVINO version: {}", OpenVINO::getVersionName(config.version)); + } -void Device::init2(bool embeddedMvcmd, bool usb2Mode, const std::string& pathToMvcmd, tl::optional pipeline) { // Set logging pattern of device (device id + shared pattern) pimpl->setPattern(fmt::format("[{}] {}", deviceInfo.getMxId(), LOG_DEFAULT_PATTERN)); - // Get embedded mvcmd - std::vector embeddedFw = Resources::getInstance().getDeviceFirmware(usb2Mode, openvinoVersion); + // Check if WD env var is set + std::chrono::milliseconds watchdogTimeout = device::XLINK_WATCHDOG_TIMEOUT; + auto watchdogMsStr = spdlog::details::os::getenv("DEPTHAI_WATCHDOG"); + if(!watchdogMsStr.empty()) { + // Try parsing the string as a number + try { + std::chrono::milliseconds watchdog{std::stoi(watchdogMsStr)}; + config.preboot.watchdogTimeoutMs = watchdog.count(); + watchdogTimeout = watchdog; + spdlog::debug("Using a custom watchdog value of {}", watchdogTimeout); + } catch(const std::invalid_argument& e) { + spdlog::warn("DEPTHAI_WATCHDOG value invalid: {}", e.what()); + } + } + + // Get embedded mvcmd or external with applied config + std::vector fwWithConfig = Resources::getInstance().getDeviceFirmware(config, pathToMvcmd); // Init device (if bootloader, handle correctly - issue USB boot command) if(deviceInfo.state == X_LINK_UNBOOTED) { // Unbooted device found, boot and connect with XLinkConnection constructor - if(embeddedMvcmd) { - connection = std::make_shared(deviceInfo, embeddedFw); - } else { - connection = std::make_shared(deviceInfo, pathToMvcmd); - } - + connection = std::make_shared(deviceInfo, fwWithConfig); } else if(deviceInfo.state == X_LINK_BOOTLOADER) { // Scope so bootloaderConnection is desctructed and XLink cleans its state { @@ -464,8 +536,8 @@ void Device::init2(bool embeddedMvcmd, bool usb2Mode, const std::string& pathToM if(version >= DeviceBootloader::Version(0, 0, 12)) { // Send request to boot firmware directly from bootloader dai::bootloader::request::BootMemory bootMemory; - bootMemory.totalSize = static_cast(embeddedFw.size()); - bootMemory.numPackets = ((static_cast(embeddedFw.size()) - 1) / bootloader::XLINK_STREAM_MAX_SIZE) + 1; + bootMemory.totalSize = static_cast(fwWithConfig.size()); + bootMemory.numPackets = ((static_cast(fwWithConfig.size()) - 1) / bootloader::XLINK_STREAM_MAX_SIZE) + 1; if(!sendBootloaderRequest(stream.getStreamId(), bootMemory)) { throw std::runtime_error("Error trying to connect to device"); } @@ -473,7 +545,7 @@ void Device::init2(bool embeddedMvcmd, bool usb2Mode, const std::string& pathToM using namespace std::chrono; auto t1 = steady_clock::now(); // After that send numPackets of data - stream.writeSplit(embeddedFw.data(), embeddedFw.size(), bootloader::XLINK_STREAM_MAX_SIZE); + stream.writeSplit(fwWithConfig.data(), fwWithConfig.size(), bootloader::XLINK_STREAM_MAX_SIZE); spdlog::debug( "Booting FW with Bootloader. Version {}, Time taken: {}", version.toString(), duration_cast(steady_clock::now() - t1)); @@ -505,19 +577,11 @@ void Device::init2(bool embeddedMvcmd, bool usb2Mode, const std::string& pathToM } // Boot and connect with XLinkConnection constructor - if(embeddedMvcmd) { - connection = std::make_shared(deviceInfo, embeddedFw); - } else { - connection = std::make_shared(deviceInfo, pathToMvcmd); - } + connection = std::make_shared(deviceInfo, fwWithConfig); } else if(deviceInfo.state == X_LINK_BOOTED) { // Connect without booting - if(embeddedMvcmd) { - connection = std::make_shared(deviceInfo, embeddedFw); - } else { - connection = std::make_shared(deviceInfo, pathToMvcmd); - } + connection = std::make_shared(deviceInfo, fwWithConfig); } else { throw std::runtime_error("Cannot find any device with given deviceInfo"); } @@ -525,7 +589,7 @@ void Device::init2(bool embeddedMvcmd, bool usb2Mode, const std::string& pathToM deviceInfo.state = X_LINK_BOOTED; // prepare rpc for both attached and host controlled mode - pimpl->rpcStream = std::make_unique(*connection, dai::XLINK_CHANNEL_MAIN_RPC, dai::XLINK_USB_BUFFER_MAX_SIZE); + pimpl->rpcStream = std::make_unique(*connection, device::XLINK_CHANNEL_MAIN_RPC, device::XLINK_USB_BUFFER_MAX_SIZE); pimpl->rpcClient = std::make_unique>([this](nanorpc::core::type::buffer request) { // Lock for time of the RPC call, to not mix the responses between calling threads. @@ -546,16 +610,19 @@ void Device::init2(bool embeddedMvcmd, bool usb2Mode, const std::string& pathToM }); // prepare watchdog thread, which will keep device alive - watchdogThread = std::thread([this]() { - std::shared_ptr conn = this->connection; - while(watchdogRunning) { - try { - pimpl->rpcClient->call("watchdogKeepalive"); - } catch(const std::exception&) { - break; + // separate stream so it doesn't miss between potentially long RPC calls + watchdogThread = std::thread([this, watchdogTimeout]() { + try { + XLinkStream stream(*this->connection, device::XLINK_CHANNEL_WATCHDOG, 128); + std::vector watchdogKeepalive = {0, 0, 0, 0}; + while(watchdogRunning) { + stream.write(watchdogKeepalive); + // Ping with a period half of that of the watchdog timeout + std::this_thread::sleep_for(watchdogTimeout / 2); } - // Ping with a period half of that of the watchdog timeout - std::this_thread::sleep_for(XLINK_WATCHDOG_TIMEOUT / 2); + } catch(const std::exception& ex) { + // ignore + spdlog::debug("Watchdog thread exception caught: {}", ex.what()); } // Watchdog ended. Useful for checking disconnects @@ -567,7 +634,7 @@ void Device::init2(bool embeddedMvcmd, bool usb2Mode, const std::string& pathToM using namespace std::chrono; try { - XLinkStream stream(*this->connection, XLINK_CHANNEL_TIMESYNC, 128); + XLinkStream stream(*this->connection, device::XLINK_CHANNEL_TIMESYNC, 128); Timestamp timestamp = {}; while(timesyncRunning) { // Block @@ -594,7 +661,7 @@ void Device::init2(bool embeddedMvcmd, bool usb2Mode, const std::string& pathToM using namespace std::chrono; std::vector messages; try { - XLinkStream stream(*this->connection, XLINK_CHANNEL_LOG, 128); + XLinkStream stream(*this->connection, device::XLINK_CHANNEL_LOG, 128); while(loggingRunning) { // Block auto log = stream.read(); @@ -1012,16 +1079,16 @@ bool Device::startPipeline(const Pipeline& pipeline) { throw std::runtime_error("Pipeline is already running"); } + // Check openvino version + if(!pipeline.isOpenVINOVersionCompatible(config.version)) { + throw std::runtime_error("Device booted with different OpenVINO version that pipeline requires"); + } + + // Serialize the pipeline PipelineSchema schema; Assets assets; std::vector assetStorage; - - // Mark the OpenVINO version and serialize the pipeline - OpenVINO::Version pipelineOpenvinoVersion; - pipeline.serialize(schema, assets, assetStorage, pipelineOpenvinoVersion); - if(openvinoVersion != pipelineOpenvinoVersion) { - throw std::runtime_error("Device booted with different OpenVINO version that pipeline requires"); - } + pipeline.serialize(schema, assets, assetStorage); // Open queues upfront, let queues know about data sizes (input queues) // Go through Pipeline and check for 'XLinkIn' and 'XLinkOut' nodes @@ -1088,10 +1155,10 @@ bool Device::startPipeline(const Pipeline& pipeline) { // Transfer the whole assetStorage in a separate thread const std::string streamAssetStorage = "__stream_asset_storage"; std::thread t1([this, &streamAssetStorage, &assetStorage]() { - XLinkStream stream(*connection, streamAssetStorage, XLINK_USB_BUFFER_MAX_SIZE); + XLinkStream stream(*connection, streamAssetStorage, device::XLINK_USB_BUFFER_MAX_SIZE); int64_t offset = 0; do { - int64_t toTransfer = std::min(static_cast(XLINK_USB_BUFFER_MAX_SIZE), static_cast(assetStorage.size() - offset)); + int64_t toTransfer = std::min(static_cast(device::XLINK_USB_BUFFER_MAX_SIZE), static_cast(assetStorage.size() - offset)); stream.write(&assetStorage[offset], toTransfer); offset += toTransfer; } while(offset < static_cast(assetStorage.size())); diff --git a/src/device/DeviceBootloader.cpp b/src/device/DeviceBootloader.cpp index 43ebc7667d..878077b583 100644 --- a/src/device/DeviceBootloader.cpp +++ b/src/device/DeviceBootloader.cpp @@ -59,8 +59,10 @@ std::vector DeviceBootloader::createDepthaiApplicationPackage(Pipeline& PipelineSchema schema; Assets assets; std::vector assetStorage; - OpenVINO::Version version; - pipeline.serialize(schema, assets, assetStorage, version); + pipeline.serialize(schema, assets, assetStorage); + + // Get openvino version + OpenVINO::Version version = pipeline.getOpenVINOVersion(); // Prepare device firmware std::vector deviceFirmware; diff --git a/src/openvino/OpenVINO.cpp b/src/openvino/OpenVINO.cpp index d2f4d8cd47..816cd77065 100644 --- a/src/openvino/OpenVINO.cpp +++ b/src/openvino/OpenVINO.cpp @@ -11,6 +11,9 @@ namespace dai { +// Definition +constexpr OpenVINO::Version OpenVINO::DEFAULT_VERSION; + // static member init // {{major, minor}, 'latest openvino version to support it'} // major and minor represent openvino NN blob version information diff --git a/src/pipeline/Pipeline.cpp b/src/pipeline/Pipeline.cpp index 68f9491537..2b8587b56a 100644 --- a/src/pipeline/Pipeline.cpp +++ b/src/pipeline/Pipeline.cpp @@ -12,9 +12,6 @@ namespace dai { -constexpr OpenVINO::Version PipelineImpl::DEFAULT_OPENVINO_VERSION; -constexpr OpenVINO::Version Pipeline::DEFAULT_OPENVINO_VERSION; - Node::Id PipelineImpl::getNextUniqueId() { return latestId++; } @@ -82,7 +79,7 @@ std::vector> PipelineImpl::getAllNodes() { return nodes; } -void PipelineImpl::serialize(PipelineSchema& schema, Assets& assets, std::vector& assetStorage, OpenVINO::Version& version) const { +void PipelineImpl::serialize(PipelineSchema& schema, Assets& assets, std::vector& assetStorage) const { // Set schema schema = getPipelineSchema(); @@ -95,10 +92,8 @@ void PipelineImpl::serialize(PipelineSchema& schema, Assets& assets, std::vector for(const auto& kv : nodeMap) { kv.second->getAssetManager().serialize(mutableAssets, assetStorage, fmt::format("/node/{}/", kv.second->id)); } - assets = mutableAssets; - // detect and set openvino version - version = getPipelineOpenVINOVersion(); + assets = mutableAssets; } PipelineSchema PipelineImpl::getPipelineSchema() const { @@ -183,7 +178,16 @@ PipelineSchema PipelineImpl::getPipelineSchema() const { return schema; } -OpenVINO::Version PipelineImpl::getPipelineOpenVINOVersion() const { +bool PipelineImpl::isOpenVINOVersionCompatible(OpenVINO::Version version) const { + auto ver = getPipelineOpenVINOVersion(); + if(ver) { + return OpenVINO::areVersionsBlobCompatible(version, *ver); + } else { + return true; + } +} + +tl::optional PipelineImpl::getPipelineOpenVINOVersion() const { // Loop over nodes, and get the required information tl::optional version; std::string lastNodeNameWithRequiredVersion = ""; @@ -223,17 +227,24 @@ OpenVINO::Version PipelineImpl::getPipelineOpenVINOVersion() const { } } - // After iterating over, set openvinoVersion - OpenVINO::Version openvinoVersion = DEFAULT_OPENVINO_VERSION; + // After iterating over, return appropriate version if(forceRequiredOpenVINOVersion) { - // set to forced version - openvinoVersion = *forceRequiredOpenVINOVersion; + // Return forced version + return forceRequiredOpenVINOVersion; } else if(version) { - // set to detected version - openvinoVersion = *version; + // Return detected version + return version; + } else { + // Return null + return tl::nullopt; } +} - return openvinoVersion; +Device::Config PipelineImpl::getDeviceConfig() const { + Device::Config config; + config.version = getPipelineOpenVINOVersion().value_or(OpenVINO::DEFAULT_VERSION); + // TODO(themarpe) - fill out rest of preboot config + return config; } void PipelineImpl::setCameraTuningBlobPath(const std::string& path) { diff --git a/src/utility/Resources.cpp b/src/utility/Resources.cpp index 3f8e00f19b..ceeb1868f8 100644 --- a/src/utility/Resources.cpp +++ b/src/utility/Resources.cpp @@ -16,6 +16,10 @@ #include "spdlog/fmt/chrono.h" #include "spdlog/spdlog.h" +// shared +#include "depthai-shared/device/PrebootConfig.hpp" +#include "depthai-shared/utility/Checksum.hpp" + extern "C" { #include "bspatch/bspatch.h" } @@ -28,157 +32,142 @@ CMRC_DECLARE(depthai); namespace dai { +static std::vector createPrebootHeader(const std::vector& payload, uint32_t magic1, uint32_t magic2); + constexpr static auto CMRC_DEPTHAI_DEVICE_TAR_XZ = "depthai-device-fwp-" DEPTHAI_DEVICE_VERSION ".tar.xz"; // Main FW constexpr static auto DEPTHAI_CMD_OPENVINO_2021_4_PATH = "depthai-device-openvino-2021.4-" DEPTHAI_DEVICE_VERSION ".cmd"; +constexpr static auto MAIN_FW_PATH = DEPTHAI_CMD_OPENVINO_2021_4_PATH; +constexpr static auto& MAIN_FW_VERSION = OpenVINO::DEFAULT_VERSION; // Patches from Main FW - constexpr static auto DEPTHAI_CMD_OPENVINO_2020_3_PATCH_PATH = "depthai-device-openvino-2020.3-" DEPTHAI_DEVICE_VERSION ".patch"; constexpr static auto DEPTHAI_CMD_OPENVINO_2020_4_PATCH_PATH = "depthai-device-openvino-2020.4-" DEPTHAI_DEVICE_VERSION ".patch"; constexpr static auto DEPTHAI_CMD_OPENVINO_2021_1_PATCH_PATH = "depthai-device-openvino-2021.1-" DEPTHAI_DEVICE_VERSION ".patch"; constexpr static auto DEPTHAI_CMD_OPENVINO_2021_2_PATCH_PATH = "depthai-device-openvino-2021.2-" DEPTHAI_DEVICE_VERSION ".patch"; constexpr static auto DEPTHAI_CMD_OPENVINO_2021_3_PATCH_PATH = "depthai-device-openvino-2021.3-" DEPTHAI_DEVICE_VERSION ".patch"; -// Usb2 patches -constexpr static auto DEPTHAI_CMD_OPENVINO_2020_3_USB2_PATCH_PATH = "depthai-device-usb2-patch-openvino-2020.3-" DEPTHAI_DEVICE_VERSION ".patch"; -constexpr static auto DEPTHAI_CMD_OPENVINO_2020_4_USB2_PATCH_PATH = "depthai-device-usb2-patch-openvino-2020.4-" DEPTHAI_DEVICE_VERSION ".patch"; -constexpr static auto DEPTHAI_CMD_OPENVINO_2021_1_USB2_PATCH_PATH = "depthai-device-usb2-patch-openvino-2021.1-" DEPTHAI_DEVICE_VERSION ".patch"; -constexpr static auto DEPTHAI_CMD_OPENVINO_2021_2_USB2_PATCH_PATH = "depthai-device-usb2-patch-openvino-2021.2-" DEPTHAI_DEVICE_VERSION ".patch"; -constexpr static auto DEPTHAI_CMD_OPENVINO_2021_3_USB2_PATCH_PATH = "depthai-device-usb2-patch-openvino-2021.3-" DEPTHAI_DEVICE_VERSION ".patch"; -constexpr static auto DEPTHAI_CMD_OPENVINO_2021_4_USB2_PATCH_PATH = "depthai-device-usb2-patch-openvino-2021.4-" DEPTHAI_DEVICE_VERSION ".patch"; - -constexpr static std::array RESOURCE_LIST_DEVICE = { - DEPTHAI_CMD_OPENVINO_2020_3_PATCH_PATH, - DEPTHAI_CMD_OPENVINO_2020_4_PATCH_PATH, - DEPTHAI_CMD_OPENVINO_2021_1_PATCH_PATH, - DEPTHAI_CMD_OPENVINO_2021_2_PATCH_PATH, - DEPTHAI_CMD_OPENVINO_2021_3_PATCH_PATH, - DEPTHAI_CMD_OPENVINO_2021_4_PATH, - DEPTHAI_CMD_OPENVINO_2020_3_USB2_PATCH_PATH, - DEPTHAI_CMD_OPENVINO_2020_4_USB2_PATCH_PATH, - DEPTHAI_CMD_OPENVINO_2021_1_USB2_PATCH_PATH, - DEPTHAI_CMD_OPENVINO_2021_2_USB2_PATCH_PATH, - DEPTHAI_CMD_OPENVINO_2021_3_USB2_PATCH_PATH, - DEPTHAI_CMD_OPENVINO_2021_4_USB2_PATCH_PATH, +// Creates std::array without explicitly needing to state the size +template +static constexpr auto array_of(T&&... t) -> std::array { + return {{std::forward(t)...}}; +} -}; +constexpr static auto RESOURCE_LIST_DEVICE = array_of(DEPTHAI_CMD_OPENVINO_2021_4_PATH, + DEPTHAI_CMD_OPENVINO_2020_3_PATCH_PATH, + DEPTHAI_CMD_OPENVINO_2020_4_PATCH_PATH, + DEPTHAI_CMD_OPENVINO_2021_1_PATCH_PATH, + DEPTHAI_CMD_OPENVINO_2021_2_PATCH_PATH, + DEPTHAI_CMD_OPENVINO_2021_3_PATCH_PATH); + +std::vector Resources::getDeviceFirmware(Device::Config config, std::string pathToMvcmd) { + // Acquire mutex (this mutex signifies that lazy load is complete) + // It is necessary when accessing resourceMap variable + std::unique_lock lock(mtxDevice); -std::vector Resources::getDeviceBinary(OpenVINO::Version version, bool usb2Mode) { - std::vector finalCmd; + std::vector finalFwBinary; - // Check if env variable DEPTHAI_DEVICE_BINARY is set + // Get OpenVINO version + auto& version = config.version; + + // Check if pathToMvcmd variable is set + std::string finalFwBinaryPath = ""; + if(!pathToMvcmd.empty()) { + finalFwBinaryPath = pathToMvcmd; + } + // Override if env variable DEPTHAI_DEVICE_BINARY is set auto fwBinaryPath = spdlog::details::os::getenv("DEPTHAI_DEVICE_BINARY"); if(!fwBinaryPath.empty()) { + finalFwBinaryPath = fwBinaryPath; + } + // Return binary from file if any of above paths are present + if(!finalFwBinaryPath.empty()) { // Load binary file at path - std::ifstream stream(fwBinaryPath, std::ios::binary); + std::ifstream stream(finalFwBinaryPath, std::ios::binary); if(!stream.is_open()) { // Throw an error // TODO(themarpe) - Unify exceptions into meaningful groups throw std::runtime_error(fmt::format("File at path {} pointed to by DEPTHAI_DEVICE_BINARY doesn't exist.", fwBinaryPath)); } // Read the file and return its contents - return std::vector(std::istreambuf_iterator(stream), {}); - } - + finalFwBinary = std::vector(std::istreambuf_iterator(stream), {}); + } else { // Binaries are resource compiled #ifdef DEPTHAI_RESOURCE_COMPILED_BINARIES - // Temporary binary - std::vector tmpDepthaiBinary; - // Main FW - std::vector depthaiBinary = resourceMapDevice[DEPTHAI_CMD_OPENVINO_2021_4_PATH]; - // Patch from main to specified - std::vector depthaiPatch = resourceMapDevice[DEPTHAI_CMD_OPENVINO_2021_3_PATCH_PATH]; - // Patch from specified to usb2 specified - std::vector depthaiUsb2Patch = resourceMapDevice[DEPTHAI_CMD_OPENVINO_2021_4_USB2_PATCH_PATH]; - - switch(version) { - case OpenVINO::VERSION_2020_3: - depthaiPatch = resourceMapDevice[DEPTHAI_CMD_OPENVINO_2020_3_PATCH_PATH]; - depthaiUsb2Patch = resourceMapDevice[DEPTHAI_CMD_OPENVINO_2020_3_USB2_PATCH_PATH]; - break; - - case OpenVINO::VERSION_2020_4: - depthaiPatch = resourceMapDevice[DEPTHAI_CMD_OPENVINO_2020_4_PATCH_PATH]; - depthaiUsb2Patch = resourceMapDevice[DEPTHAI_CMD_OPENVINO_2020_4_USB2_PATCH_PATH]; - break; - - case OpenVINO::VERSION_2021_1: - depthaiPatch = resourceMapDevice[DEPTHAI_CMD_OPENVINO_2021_1_PATCH_PATH]; - depthaiUsb2Patch = resourceMapDevice[DEPTHAI_CMD_OPENVINO_2021_1_USB2_PATCH_PATH]; - break; - - case OpenVINO::VERSION_2021_2: - depthaiPatch = resourceMapDevice[DEPTHAI_CMD_OPENVINO_2021_2_PATCH_PATH]; - depthaiUsb2Patch = resourceMapDevice[DEPTHAI_CMD_OPENVINO_2021_2_USB2_PATCH_PATH]; - break; - - case OpenVINO::VERSION_2021_3: - depthaiPatch = resourceMapDevice[DEPTHAI_CMD_OPENVINO_2021_3_PATCH_PATH]; - depthaiUsb2Patch = resourceMapDevice[DEPTHAI_CMD_OPENVINO_2021_3_USB2_PATCH_PATH]; - break; - - case OpenVINO::VERSION_2021_4: - depthaiBinary = resourceMapDevice[DEPTHAI_CMD_OPENVINO_2021_4_PATH]; - depthaiUsb2Patch = resourceMapDevice[DEPTHAI_CMD_OPENVINO_2021_4_USB2_PATCH_PATH]; - break; - } - - // is patching required? - if(version != OpenVINO::VERSION_2021_4) { - spdlog::debug("Patching OpenVINO FW version from {} to {}", OpenVINO::getVersionName(OpenVINO::VERSION_2021_4), OpenVINO::getVersionName(version)); - - // Get new size - int64_t patchedSize = bspatch_mem_get_newsize(depthaiPatch.data(), depthaiPatch.size()); + // Main FW + std::vector depthaiBinary; + // Patch from main to specified + std::vector depthaiPatch; - // Reserve space for patched binary - tmpDepthaiBinary.resize(patchedSize); + switch(version) { + case OpenVINO::VERSION_2020_3: + depthaiPatch = resourceMapDevice[DEPTHAI_CMD_OPENVINO_2020_3_PATCH_PATH]; + break; - // Patch - int error = bspatch_mem(depthaiBinary.data(), depthaiBinary.size(), depthaiPatch.data(), depthaiPatch.size(), tmpDepthaiBinary.data()); + case OpenVINO::VERSION_2020_4: + depthaiPatch = resourceMapDevice[DEPTHAI_CMD_OPENVINO_2020_4_PATCH_PATH]; + break; - // if patch not successful - if(error > 0) throw std::runtime_error("Error while patching cmd for usb2 mode"); + case OpenVINO::VERSION_2021_1: + depthaiPatch = resourceMapDevice[DEPTHAI_CMD_OPENVINO_2021_1_PATCH_PATH]; + break; - // Change depthaiBinary to tmpDepthaiBinary - depthaiBinary = tmpDepthaiBinary; - } + case OpenVINO::VERSION_2021_2: + depthaiPatch = resourceMapDevice[DEPTHAI_CMD_OPENVINO_2021_2_PATCH_PATH]; + break; - if(usb2Mode) { - #ifdef DEPTHAI_PATCH_ONLY_MODE + case OpenVINO::VERSION_2021_3: + depthaiPatch = resourceMapDevice[DEPTHAI_CMD_OPENVINO_2021_3_PATCH_PATH]; + break; - spdlog::debug("Patching FW version {} to USB2 mode", OpenVINO::getVersionName(version)); + case MAIN_FW_VERSION: + depthaiBinary = resourceMapDevice[MAIN_FW_PATH]; + break; + } - // Get new size - int64_t patchedSize = bspatch_mem_get_newsize(depthaiUsb2Patch.data(), depthaiUsb2Patch.size()); + // is patching required? + if(!depthaiPatch.empty()) { + spdlog::debug("Patching OpenVINO FW version from {} to {}", OpenVINO::getVersionName(MAIN_FW_VERSION), OpenVINO::getVersionName(version)); - // Reserve space for patched binary - finalCmd.resize(patchedSize); + // Load full binary for patch + depthaiBinary = resourceMapDevice[MAIN_FW_PATH]; - // Patch - int error = bspatch_mem(depthaiBinary.data(), depthaiBinary.size(), depthaiUsb2Patch.data(), depthaiUsb2Patch.size(), finalCmd.data()); + // Get new size + int64_t patchedSize = bspatch_mem_get_newsize(depthaiPatch.data(), depthaiPatch.size()); - // if patch not successful - if(error > 0) throw std::runtime_error("Error while patching cmd for usb2 mode"); + // Reserve space for patched binary + std::vector tmpDepthaiBinary{}; + tmpDepthaiBinary.resize(patchedSize); - #else + // Patch + int error = bspatch_mem(depthaiBinary.data(), depthaiBinary.size(), depthaiPatch.data(), depthaiPatch.size(), tmpDepthaiBinary.data()); - static_assert("Unsupported currently"); + // if patch not successful + if(error > 0) { + throw std::runtime_error(fmt::format( + "Error while patching OpenVINO FW version from {} to {}", OpenVINO::getVersionName(MAIN_FW_VERSION), OpenVINO::getVersionName(version))); + } - #endif + // Change depthaiBinary to tmpDepthaiBinary + depthaiBinary = std::move(tmpDepthaiBinary); + } - } else { - return depthaiBinary; - } + finalFwBinary = std::move(depthaiBinary); #else - // Binaries from default path (TODO) + // Binaries from default path (TODO) #endif + } + + // Prepend preboot config + auto prebootHeader = createPrebootHeader(nlohmann::json::to_msgpack(config.preboot), PREBOOT_CONFIG_MAGIC1, PREBOOT_CONFIG_MAGIC2); + finalFwBinary.insert(finalFwBinary.begin(), prebootHeader.begin(), prebootHeader.end()); - return finalCmd; + // Return created firmware + return finalFwBinary; } constexpr static auto CMRC_DEPTHAI_BOOTLOADER_TAR_XZ = "depthai-bootloader-fwp-" DEPTHAI_BOOTLOADER_VERSION ".tar.xz"; @@ -353,12 +342,65 @@ Resources::~Resources() { // Get device firmware std::vector Resources::getDeviceFirmware(bool usb2Mode, OpenVINO::Version version) { - // Acquire mutex (this mutex signifies that lazy load is complete) - // It is necessary when accessing resourceMapDevice variable - std::unique_lock lock(mtxDevice); + Device::Config cfg; + if(usb2Mode) { + cfg.preboot.usb.maxSpeed = UsbSpeed::HIGH; + } else { + cfg.preboot.usb.maxSpeed = Device::DEFAULT_USB_SPEED; + } + cfg.version = version; + + return getDeviceFirmware(cfg); +} + +std::vector createPrebootHeader(const std::vector& payload, uint32_t magic1, uint32_t magic2) { + const std::uint8_t HEADER[] = {77, + 65, + 50, + 120, + 0x8A, + static_cast((magic1 >> 0) & 0xFF), + static_cast((magic1 >> 8) & 0xFF), + static_cast((magic1 >> 16) & 0xFF), + static_cast((magic1 >> 24) & 0xFF)}; + + // Store the constructed preboot information + std::vector prebootHeader; + + // Store initial header + prebootHeader.insert(prebootHeader.begin(), std::begin(HEADER), std::end(HEADER)); + + // Calculate size + std::size_t totalPayloadSize = payload.size() + sizeof(magic2) + sizeof(uint32_t) + sizeof(uint32_t); + std::size_t toAddBytes = 0; + if(totalPayloadSize % 4 != 0) { + toAddBytes = 4 - (totalPayloadSize % 4); + } + std::size_t totalSize = totalPayloadSize + toAddBytes; + std::size_t totalSizeWord = totalSize / 4; + + // Write size in words in little endian + prebootHeader.push_back((totalSizeWord >> 0) & 0xFF); + prebootHeader.push_back((totalSizeWord >> 8) & 0xFF); + + // Compute payload checksum + auto checksum = utility::checksum(payload.data(), payload.size()); + + // Write checksum & payload size as uint32_t LE + for(const auto& field : {magic2, checksum, static_cast(payload.size())}) { + for(int i = 0; i < 4; i++) { + prebootHeader.push_back((field >> (i * 8)) & 0xFF); + } + } + + // Copy payload + prebootHeader.insert(prebootHeader.end(), payload.begin(), payload.end()); + // Add missing bytes + for(std::size_t i = 0; i < toAddBytes; i++) { + prebootHeader.push_back(0x00); + } - // Return device firmware - return getDeviceBinary(version, usb2Mode); + return prebootHeader; } } // namespace dai diff --git a/src/utility/Resources.hpp b/src/utility/Resources.hpp index 1ebb9051fc..57f6e8cdbb 100644 --- a/src/utility/Resources.hpp +++ b/src/utility/Resources.hpp @@ -9,10 +9,10 @@ // project #include +#include #include -namespace dai -{ +namespace dai { class Resources { // private constructor @@ -27,7 +27,7 @@ class Resources { std::thread lazyThreadBootloader; std::unordered_map> resourceMapBootloader; - std::vector getDeviceBinary(OpenVINO::Version version, bool usb2Mode); + std::vector getDeviceBinary(Device::Config config); public: static Resources& getInstance(); @@ -35,7 +35,8 @@ class Resources { void operator=(Resources const&) = delete; // Available resources - std::vector getDeviceFirmware(bool usb2Mode, OpenVINO::Version version = OpenVINO::VERSION_2021_4); + std::vector getDeviceFirmware(bool usb2Mode, OpenVINO::Version version = OpenVINO::DEFAULT_VERSION); + std::vector getDeviceFirmware(Device::Config config, std::string pathToMvcmd = ""); std::vector getBootloaderFirmware(DeviceBootloader::Type type = DeviceBootloader::Type::USB); }; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6b258c53bb..0dfd3c6278 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -99,5 +99,5 @@ target_compile_definitions(openvino_blob PRIVATE OPENVINO_2021_4_BLOB_PATH="${openvino_2021_4_blob}" ) - - +# Device USB Speed test +dai_add_test(device_usbspeed_test src/device_usbspeed_test.cpp) diff --git a/tests/src/device_usbspeed_test.cpp b/tests/src/device_usbspeed_test.cpp new file mode 100644 index 0000000000..7df9e61e21 --- /dev/null +++ b/tests/src/device_usbspeed_test.cpp @@ -0,0 +1,24 @@ +#define CATCH_CONFIG_MAIN +#include + +// std +#include +#include + +// Include depthai library +#include + +TEST_CASE("UsbSpeed::HIGH") { + dai::Pipeline p; + dai::Device d(p, dai::UsbSpeed::HIGH); +} + +TEST_CASE("UsbSpeed::SUPER") { + dai::Pipeline p; + dai::Device d(p, dai::UsbSpeed::SUPER); +} + +TEST_CASE("UsbSpeed::SUPER_PLUS") { + dai::Pipeline p; + dai::Device d(p, dai::UsbSpeed::SUPER_PLUS); +}