diff --git a/README.md b/README.md index fb8f26bb2..6f499b9a8 100644 --- a/README.md +++ b/README.md @@ -174,7 +174,7 @@ The following environment variables can be set to alter default behavior of the | DEPTHAI_SEARCH_TIMEOUT | Specifies timeout in milliseconds for device searching in blocking functions. | | DEPTHAI_CONNECT_TIMEOUT | Specifies timeout in milliseconds for establishing a connection to a given device. | | DEPTHAI_BOOTUP_TIMEOUT | Specifies timeout in milliseconds for waiting the device to boot after sending the binary. | -| DEPTHAI_PROTOCOL | Restricts default search to the specified protocol. Options: `any`, `usb`, `tcpip`. | +| DEPTHAI_PROTOCOL | Restricts default search to the specified protocol. Options: `any`, `usb`, `tcpip`, `tcpshd`. | | DEPTHAI_PLATFORM | Restricts default search to the specified platform. Options: `any`, `rvc2`, `rvc3`, `rvc4`. | | DEPTHAI_DEVICE_MXID_LIST | Restricts default search to the specified MXIDs. Accepts comma separated list of MXIDs. Lists filter results in an "AND" manner and not "OR" | | DEPTHAI_DEVICE_ID_LIST | Alias to MXID list. Lists filter results in an "AND" manner and not "OR" | diff --git a/cmake/Hunter/config.cmake b/cmake/Hunter/config.cmake index f26a73995..5932c1cc4 100644 --- a/cmake/Hunter/config.cmake +++ b/cmake/Hunter/config.cmake @@ -11,9 +11,9 @@ hunter_config( hunter_config( XLink - VERSION "luxonis-2021.4.3-develop" - URL "https://github.com/luxonis/XLink/archive/061709357b06a74510b5b9e3e2832d9d80efd3ff.tar.gz" - SHA1 "affa1bdd7487cf70c9caf40365844967ae761ea3" + VERSION "luxonis-develop-server" + URL "https://github.com/luxonis/XLink/archive/585a38fe4707e5f023de277135d8cb6ff9c4e0c4.tar.gz" + SHA1 "d82827dec8b6f2702f4b31d8186fd70265cd0ca4" CMAKE_ARGS XLINK_ENABLE_LIBUSB=${DEPTHAI_ENABLE_LIBUSB} ) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index e8cc34382..feefcb52d 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,2 +1,2 @@ add_subdirectory(cpp) -# add_subdirectory(python) +# add_subdirectory(python) \ No newline at end of file diff --git a/include/depthai/pipeline/datatype/ADatatype.hpp b/include/depthai/pipeline/datatype/ADatatype.hpp index 2d6988d75..8299e9c2a 100644 --- a/include/depthai/pipeline/datatype/ADatatype.hpp +++ b/include/depthai/pipeline/datatype/ADatatype.hpp @@ -6,6 +6,7 @@ #include "depthai/utility/Memory.hpp" #include "depthai/utility/Serialization.hpp" #include "depthai/utility/VectorMemory.hpp" + namespace dai { /// Abstract message diff --git a/include/depthai/pipeline/datatype/Buffer.hpp b/include/depthai/pipeline/datatype/Buffer.hpp index e8bfdf6ed..0bd1795ca 100644 --- a/include/depthai/pipeline/datatype/Buffer.hpp +++ b/include/depthai/pipeline/datatype/Buffer.hpp @@ -17,6 +17,8 @@ class Buffer : public ADatatype { public: Buffer() = default; Buffer(size_t size); + Buffer(long fd); + Buffer(long fd, size_t size); virtual ~Buffer() = default; virtual void serialize(std::vector& metadata, DatatypeEnum& datatype) const { @@ -35,6 +37,7 @@ class Buffer : public ADatatype { * @param data Copies data to internal buffer */ void setData(const std::vector& data); + void setData(const long fd); /** * @param data Moves data to internal buffer diff --git a/include/depthai/pipeline/datatype/ImgFrame.hpp b/include/depthai/pipeline/datatype/ImgFrame.hpp index 982fd05bf..491da71e8 100644 --- a/include/depthai/pipeline/datatype/ImgFrame.hpp +++ b/include/depthai/pipeline/datatype/ImgFrame.hpp @@ -70,7 +70,9 @@ class ImgFrame : public Buffer { * Timestamp is set to now */ ImgFrame(); + ImgFrame(long fd); ImgFrame(size_t size); + ImgFrame(long fd, size_t size); virtual ~ImgFrame() = default; ImgTransformations transformations; diff --git a/include/depthai/utility/Memory.hpp b/include/depthai/utility/Memory.hpp index d5a813820..7fbf68d23 100644 --- a/include/depthai/utility/Memory.hpp +++ b/include/depthai/utility/Memory.hpp @@ -107,6 +107,12 @@ holder(std::move(holder)) {} }; */ +enum MemoryKinds { + MEMORY_KIND_VECTOR, + MEMORY_KIND_SHARED, + MEMORY_KINDS_COUNT, +}; + // memory as interface class Memory { public: @@ -120,6 +126,13 @@ class Memory { std::size_t getSize() const { return getData().size(); }; + + MemoryKinds getKind() { + return kind; + } + + protected: + MemoryKinds kind; }; } // namespace dai diff --git a/include/depthai/utility/SharedMemory.hpp b/include/depthai/utility/SharedMemory.hpp new file mode 100644 index 000000000..5c0d97f71 --- /dev/null +++ b/include/depthai/utility/SharedMemory.hpp @@ -0,0 +1,125 @@ +#pragma once + +// std +#include +#include +#include +#include +#ifdef __unix__ + #include + #include + #include + #include + #include +#endif + +// project +#include "depthai/utility/Memory.hpp" + +namespace dai { + +// memory as interface +class SharedMemory : public Memory { + protected: + long fd = -1; + void* mapping; + void mapFd() { + if(fd < 0) { + /* Error handling here */ + } + + mapping = mmap(NULL, getSize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if(mapping == NULL) { + /* Error handling here */ + } + } + void unmapFd() { + if(mapping == NULL) { + return; + } + + munmap(mapping, getSize()); + } + + public: + SharedMemory() { + kind = MemoryKinds::MEMORY_KIND_SHARED; + fd = -1; + } + + SharedMemory(long argFd) : fd(argFd) { + kind = MemoryKinds::MEMORY_KIND_SHARED; + mapFd(); + } + + SharedMemory(long argFd, std::size_t size) : fd(argFd) { + kind = MemoryKinds::MEMORY_KIND_SHARED; + setSize(size); + mapFd(); + } + + SharedMemory(const char* name) { + kind = MemoryKinds::MEMORY_KIND_SHARED; + fd = memfd_create(name, 0); + mapFd(); + } + + SharedMemory(const char* name, std::size_t size) { + kind = MemoryKinds::MEMORY_KIND_SHARED; + fd = memfd_create(name, 0); + + setSize(size); + mapFd(); + } + + ~SharedMemory() { + unmapFd(); + close(fd); + } + + SharedMemory& operator=(long argFd) { + unmapFd(); + fd = argFd; + mapFd(); + + return *this; + } + + span getData() override { + if(mapping == NULL) { + mapFd(); + } + + return {(uint8_t*)mapping, getSize()}; + } + span getData() const override { + return {(const uint8_t*)mapping, getSize()}; + } + std::size_t getMaxSize() const override { + struct stat fileStats; + fstat(fd, &fileStats); + + return fileStats.st_size; + } + std::size_t getOffset() const override { + return ftell(fdopen(fd, "r")); + } + void setSize(std::size_t size) override { + if(mapping != NULL) { + unmapFd(); + } + + ftruncate(fd, size); + mapFd(); + } + + std::size_t getSize() const { + return getMaxSize(); + } + + long getFd() const { + return fd; + } +}; + +} // namespace dai diff --git a/include/depthai/utility/VectorMemory.hpp b/include/depthai/utility/VectorMemory.hpp index f9c8a954b..ffab3b382 100644 --- a/include/depthai/utility/VectorMemory.hpp +++ b/include/depthai/utility/VectorMemory.hpp @@ -14,9 +14,15 @@ namespace dai { class VectorMemory : public std::vector, public Memory { public: // using std::vector::vector; - VectorMemory() = default; - VectorMemory(const std::vector& d) : vector(std::move(d)) {} - VectorMemory(std::vector&& d) : vector(std::move(d)) {} + VectorMemory() { + kind = MemoryKinds::MEMORY_KIND_VECTOR; + } + VectorMemory(const std::vector& d) : vector(std::move(d)) { + kind = MemoryKinds::MEMORY_KIND_VECTOR; + } + VectorMemory(std::vector&& d) : vector(std::move(d)) { + kind = MemoryKinds::MEMORY_KIND_VECTOR; + } VectorMemory& operator=(std::vector&& d) { std::vector::operator=(std::move(d)); return *this; diff --git a/include/depthai/xlink/XLinkStream.hpp b/include/depthai/xlink/XLinkStream.hpp index b54d44a81..95be5e004 100644 --- a/include/depthai/xlink/XLinkStream.hpp +++ b/include/depthai/xlink/XLinkStream.hpp @@ -28,7 +28,7 @@ namespace dai { class StreamPacketDesc : public streamPacketDesc_t { public: - StreamPacketDesc() noexcept : streamPacketDesc_t{nullptr, 0, {}, {}} {}; + StreamPacketDesc() noexcept : streamPacketDesc_t{nullptr, 0, -1, {}, {}} {}; StreamPacketDesc(const StreamPacketDesc&) = delete; StreamPacketDesc(StreamPacketDesc&& other) noexcept; StreamPacketDesc& operator=(const StreamPacketDesc&) = delete; @@ -89,11 +89,15 @@ class XLinkStream { // Blocking void write(span data, span data2); void write(span data); + void write(long fd); + void write(long fd, span data); void write(const void* data, std::size_t size); std::vector read(); std::vector read(XLinkTimespec& timestampReceived); void read(std::vector& data); + void read(std::vector& data, long& fd); void read(std::vector& data, XLinkTimespec& timestampReceived); + void read(std::vector& data, long& fd, XLinkTimespec& timestampReceived); // split write helper void writeSplit(const void* data, std::size_t size, std::size_t split); void writeSplit(const std::vector& data, std::size_t split); diff --git a/src/device/DataQueue.cpp b/src/device/DataQueue.cpp index dbe80e448..ff94b3b3a 100644 --- a/src/device/DataQueue.cpp +++ b/src/device/DataQueue.cpp @@ -9,6 +9,7 @@ #include "depthai/pipeline/datatype/ADatatype.hpp" #include "depthai/pipeline/datatype/DatatypeEnum.hpp" #include "depthai/pipeline/datatype/MessageGroup.hpp" +#include "depthai/utility/SharedMemory.hpp" #include "depthai/xlink/XLinkStream.hpp" #include "pipeline/datatype/MessageGroup.hpp" #include "pipeline/datatype/StreamMessageParser.hpp" @@ -205,8 +206,14 @@ DataInputQueue::DataInputQueue( // Blocking auto t1 = steady_clock::now(); + if(outgoing->data->getSize() > 0) { - stream.write(outgoing->data->getData(), metadata); + if(outgoing->data->getKind() == dai::MemoryKinds::MEMORY_KIND_VECTOR) { + stream.write(outgoing->data->getData(), metadata); + } else if(outgoing->data->getKind() == dai::MemoryKinds::MEMORY_KIND_VECTOR) { + std::shared_ptr memory = std::dynamic_pointer_cast(outgoing->data); + stream.write(memory->getFd(), metadata); + } } else { stream.write(metadata); } @@ -227,7 +234,12 @@ DataInputQueue::DataInputQueue( logger::trace("Sending part of a group message: {}", msg.first); auto metadata = StreamMessageParser::serializeMetadata(msg.second); if(msg.second->data->getSize() > 0) { - stream.write(msg.second->data->getData(), metadata); + if(msg.second->data->getKind() == dai::MemoryKinds::MEMORY_KIND_VECTOR) { + stream.write(msg.second->data->getData(), metadata); + } else if(msg.second->data->getKind() == dai::MemoryKinds::MEMORY_KIND_VECTOR) { + std::shared_ptr memory = std::dynamic_pointer_cast(msg.second->data); + stream.write(memory->getFd(), metadata); + } } else { stream.write(metadata); } diff --git a/src/pipeline/datatype/Buffer.cpp b/src/pipeline/datatype/Buffer.cpp index bf1b7567b..342e0ef6e 100644 --- a/src/pipeline/datatype/Buffer.cpp +++ b/src/pipeline/datatype/Buffer.cpp @@ -1,5 +1,6 @@ #include "depthai/pipeline/datatype/Buffer.hpp" +#include "depthai/utility/SharedMemory.hpp" #include "depthai/utility/VectorMemory.hpp" namespace dai { @@ -9,6 +10,16 @@ Buffer::Buffer(size_t size) : Buffer() { data = mem; } +Buffer::Buffer(long fd) : Buffer() { + auto mem = std::make_shared(fd); + data = mem; +} + +Buffer::Buffer(long fd, size_t size) : Buffer() { + auto mem = std::make_shared(fd, size); + data = mem; +} + span Buffer::getData() { return data->getData(); } @@ -27,6 +38,10 @@ void Buffer::setData(const std::vector& d) { } } +void Buffer::setData(const long fd) { + data = std::make_shared(fd); +} + void Buffer::setData(std::vector&& d) { // allocate new holder data = std::make_shared(std::move(d)); diff --git a/src/pipeline/datatype/ImgFrame.cpp b/src/pipeline/datatype/ImgFrame.cpp index a7ed218f4..cba75c2cd 100644 --- a/src/pipeline/datatype/ImgFrame.cpp +++ b/src/pipeline/datatype/ImgFrame.cpp @@ -1,6 +1,7 @@ #define _USE_MATH_DEFINES #include "depthai/pipeline/datatype/ImgFrame.hpp" +#include "depthai/utility/SharedMemory.hpp" #include "spdlog/fmt/fmt.h" #include "spdlog/spdlog.h" namespace dai { @@ -16,6 +17,16 @@ ImgFrame::ImgFrame(size_t size) : ImgFrame() { data = mem; } +ImgFrame::ImgFrame(long fd) : ImgFrame() { + auto mem = std::make_shared(fd); + data = mem; +} + +ImgFrame::ImgFrame(long fd, size_t size) : ImgFrame() { + auto mem = std::make_shared(fd, size); + data = mem; +} + std::chrono::time_point ImgFrame::getTimestamp(CameraExposureOffset offset) const { auto ts = getTimestamp(); auto expTime = getExposureTime(); diff --git a/src/pipeline/datatype/StreamMessageParser.cpp b/src/pipeline/datatype/StreamMessageParser.cpp index 630688403..08cfdd057 100644 --- a/src/pipeline/datatype/StreamMessageParser.cpp +++ b/src/pipeline/datatype/StreamMessageParser.cpp @@ -40,6 +40,7 @@ // shared #include "depthai/pipeline/datatype/DatatypeEnum.hpp" #include "depthai/utility/Serialization.hpp" +#include "utility/SharedMemory.hpp" #include "utility/VectorMemory.hpp" #include "xlink/XLinkStream.hpp" @@ -54,13 +55,16 @@ inline int readIntLE(uint8_t* data) { } template -inline std::shared_ptr parseDatatype(std::uint8_t* metadata, size_t size, std::vector& data) { +inline std::shared_ptr parseDatatype(std::uint8_t* metadata, size_t size, std::vector& data, long fd) { auto tmp = std::make_shared(); // deserialize utility::deserialize(metadata, size, *tmp); - // Move data - TODO(Morato) change this back to zero copy - tmp->data = std::make_shared(std::move(data)); + if(fd < 0) { + tmp->data = std::make_shared(std::move(data)); + } else { + tmp->data = std::make_shared(fd); + } return tmp; } @@ -97,12 +101,15 @@ std::shared_ptr StreamMessageParser::parseMessage(streamPacketDesc_t* DatatypeEnum objectType; size_t serializedObjectSize; size_t bufferLength; + long fd; std::tie(objectType, serializedObjectSize, bufferLength) = parseHeader(packet); auto* const metadataStart = packet->data + bufferLength; // copy data part std::vector data(packet->data, packet->data + bufferLength); + fd = packet->fd; + // Create corresponding object switch(objectType) { // ADatatype is a special case, since no metadata is actually serialized @@ -111,99 +118,99 @@ std::shared_ptr StreamMessageParser::parseMessage(streamPacketDesc_t* return pBuf; } case DatatypeEnum::Buffer: { - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; } case DatatypeEnum::ImgFrame: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::EncodedFrame: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::NNData: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::ImageManipConfig: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::CameraControl: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::ImgDetections: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::SpatialImgDetections: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::SystemInformation: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::SystemInformationS3: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::SpatialLocationCalculatorData: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::SpatialLocationCalculatorConfig: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::AprilTags: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::AprilTagConfig: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::Tracklets: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::IMUData: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::StereoDepthConfig: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::EdgeDetectorConfig: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::TrackedFeatures: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::FeatureTrackerConfig: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::BenchmarkReport: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::ToFConfig: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::PointCloudConfig: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::PointCloudData: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::MessageGroup: - return parseDatatype(metadataStart, serializedObjectSize, data); + return parseDatatype(metadataStart, serializedObjectSize, data, fd); break; case DatatypeEnum::TransformData: return parseDatatype(metadataStart, serializedObjectSize, data); diff --git a/src/utility/LogCollection.cpp b/src/utility/LogCollection.cpp index 9c3122220..30204e8e9 100644 --- a/src/utility/LogCollection.cpp +++ b/src/utility/LogCollection.cpp @@ -54,6 +54,10 @@ std::string protocolToString(XLinkProtocol_t protocol) { return "X_LINK_IPC"; case X_LINK_TCP_IP: return "X_LINK_TCP_IP"; + case X_LINK_LOCAL_SHDMEM: + return "X_LINK_LOCAL_SHDMEM"; + case X_LINK_TCP_IP_OR_LOCAL_SHDMEM: + return "X_LINK_TCP_IP_OR_LOCAL_SHDMEM"; case X_LINK_NMB_OF_PROTOCOLS: return "X_LINK_NMB_OF_PROTOCOLS"; case X_LINK_ANY_PROTOCOL: @@ -236,4 +240,4 @@ void logCrashDump(const std::optional& pipelineSchema, const Cra } } // namespace logCollection -} // namespace dai \ No newline at end of file +} // namespace dai diff --git a/src/xlink/XLinkConnection.cpp b/src/xlink/XLinkConnection.cpp index 870f14a54..b5c9b3701 100644 --- a/src/xlink/XLinkConnection.cpp +++ b/src/xlink/XLinkConnection.cpp @@ -98,6 +98,10 @@ static XLinkProtocol_t getDefaultProtocol() { defaultProtocol = X_LINK_USB_VSC; } else if(protocolStr == "tcpip") { defaultProtocol = X_LINK_TCP_IP; + } else if(protocolStr == "tcpshd") { + defaultProtocol = X_LINK_TCP_IP_OR_LOCAL_SHDMEM; + } else if(protocolStr == "shdmem") { + defaultProtocol = X_LINK_LOCAL_SHDMEM; } else { logger::warn("Unsupported protocol specified"); } @@ -514,6 +518,7 @@ void XLinkConnection::initDevice(const DeviceInfo& deviceToInit, XLinkDeviceStat deviceLinkId = connectionHandler.linkId; deviceInfo = lastDeviceInfo; deviceInfo.state = X_LINK_BOOTED; + deviceInfo.protocol = connectionHandler.protocol; } } diff --git a/src/xlink/XLinkStream.cpp b/src/xlink/XLinkStream.cpp index 0d9214475..13a0321c7 100644 --- a/src/xlink/XLinkStream.cpp +++ b/src/xlink/XLinkStream.cpp @@ -5,6 +5,7 @@ #include "spdlog/fmt/fmt.h" // project +#include "depthai/utility/SharedMemory.hpp" #include "depthai/xlink/XLinkConnection.hpp" namespace dai { @@ -54,7 +55,8 @@ XLinkStream::~XLinkStream() { } } -StreamPacketDesc::StreamPacketDesc(StreamPacketDesc&& other) noexcept : streamPacketDesc_t{other.data, other.length, other.tRemoteSent, other.tReceived} { +StreamPacketDesc::StreamPacketDesc(StreamPacketDesc&& other) noexcept + : streamPacketDesc_t{other.data, other.length, other.fd, other.tRemoteSent, other.tReceived} { other.data = nullptr; other.length = 0; } @@ -63,6 +65,7 @@ StreamPacketDesc& StreamPacketDesc::operator=(StreamPacketDesc&& other) noexcept if(this != &other) { data = std::exchange(other.data, nullptr); length = std::exchange(other.length, 0); + fd = std::exchange(other.fd, -1); tRemoteSent = std::exchange(other.tRemoteSent, {}); tReceived = std::exchange(other.tReceived, {}); } @@ -94,22 +97,52 @@ void XLinkStream::write(const void* data, std::size_t size) { write(span(reinterpret_cast(data), size)); } -void XLinkStream::read(std::vector& data) { - StreamPacketDesc packet; - const auto status = XLinkReadMoveData(streamId, &packet); +void XLinkStream::write(long fd) { + auto status = XLinkWriteFd(streamId, fd); + if(status != X_LINK_SUCCESS) { - throw XLinkReadError(status, streamName); + throw XLinkWriteError(status, streamName); } - data = std::vector(packet.data, packet.data + packet.length); +} + +void XLinkStream::write(long fd, span data) { + auto status = XLinkWriteFdData(streamId, fd, data.data(), data.size()); + + if(status != X_LINK_SUCCESS) { + throw XLinkWriteError(status, streamName); + } +} + +void XLinkStream::read(std::vector& data) { + XLinkTimespec timestampReceived; + read(data, timestampReceived); } void XLinkStream::read(std::vector& data, XLinkTimespec& timestampReceived) { + long fd; + read(data, fd, timestampReceived); + + if(fd >= 0) { + SharedMemory mem = SharedMemory(fd); + uint8_t* memoryData = (uint8_t*)mem.getData().data(); + std::size_t memoryLength = mem.getData().size(); + data.insert(data.end(), &memoryData[0], &memoryData[memoryLength - 1]); + } +} + +void XLinkStream::read(std::vector& data, long& fd) { + XLinkTimespec timestampReceived; + read(data, fd, timestampReceived); +} + +void XLinkStream::read(std::vector& data, long& fd, XLinkTimespec& timestampReceived) { StreamPacketDesc packet; const auto status = XLinkReadMoveData(streamId, &packet); if(status != X_LINK_SUCCESS) { throw XLinkReadError(status, streamName); } data = std::vector(packet.data, packet.data + packet.length); + fd = packet.fd; timestampReceived = packet.tReceived; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 98d211d2a..4b7be90bd 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -17,7 +17,7 @@ set(test_poe_env # Misc "UBSAN_OPTIONS=halt_on_error=1" # DepthAI - "DEPTHAI_PROTOCOL=tcpip;DEPTHAI_SEARCH_TIMEOUT=15000" + "DEPTHAI_PROTOCOL=tcpshd;DEPTHAI_SEARCH_TIMEOUT=15000" ) # Function for adding new tests