Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
2cd0570
Changed XLink commit.
Jul 1, 2025
e470ea6
Added new protocol handling in log collection
Jul 1, 2025
7a82389
Updated XLink to support USB EP discovery
Jul 10, 2025
74f5a3a
Updated XLink
Jul 10, 2025
ef65dd0
Updated xlink
Jul 10, 2025
c71236a
Reset example
Jul 11, 2025
461e015
Updated XLink
Jul 11, 2025
b539e7b
Updated xlink and added test for Gate Write
Jul 16, 2025
8a03d04
Added debug message
Jul 16, 2025
6784c4f
Testing request via USB.
Jul 17, 2025
1f362b0
Finalised GATE via USB.
Jul 18, 2025
fa9efd6
Null terminated all respBuffers
Jul 18, 2025
ff1ca69
Added error handler for create session
Jul 18, 2025
0bd8b42
Updated XLink
Aug 5, 2025
29abe4d
Updated to use wrappers of Gate functions.
Aug 5, 2025
27526a6
Removed the packed tag for device gate.
Aug 5, 2025
5acfb3f
Added Impl inside DepthaiGate to split USB and HTTP request + ran cla…
Sep 2, 2025
e0801fb
Removed depthai-shared
Sep 2, 2025
7159156
Added USB tests for RVC4
Sep 3, 2025
52a92ba
Fixed GateImpl destructors and removed unnecessary functions
Sep 3, 2025
a08d62b
Updated XLink with new Gate Discovery features.
Sep 4, 2025
8495aa5
Merge remote-tracking branch 'origin/develop' into oak4-usb-support
Sep 10, 2025
f2750d6
Updated XLink+
Sep 11, 2025
e69b2c9
DeviceGate: bugfixing for USB.
Sep 18, 2025
c80eb9d
XLink: Updated XLink for USB EPs
Sep 24, 2025
825dbf3
Merge branch 'develop' into oak4-usb-support
Sep 24, 2025
e0de70b
DeviceGate: Added serious error handling and ran clangformat.
Sep 25, 2025
94187c3
XLink: updated XLink with new fixes for USB EP.
Sep 25, 2025
748ed44
XLink: updated to merge between usb and usb_ep
Oct 1, 2025
596c5d7
XLink: updated with newer usb_ep
Oct 6, 2025
3ccb575
XLink: updated with server-side on usb_host
Oct 6, 2025
36e4581
DeviceGate: Updated with new gate updates.
Oct 7, 2025
d9ab27b
USB: Testing OS added.
Oct 8, 2025
dd41350
Update tests/run_tests.py
TheMutta Oct 8, 2025
9eb8f18
Update tests/run_tests.py
TheMutta Oct 8, 2025
5402984
Updated XLink and added usb-testing OS build in the CI.
Oct 8, 2025
4f37bf7
Merge branch 'develop' into oak4-usb-support
TheMutta Oct 8, 2025
3e95126
Updated XLink.
Oct 8, 2025
18a04b1
Merge branch 'oak4-usb-support' of github.com:luxonis/depthai-core in…
Oct 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmake/depthaiDependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ else()
FetchContent_Declare(
XLink
GIT_REPOSITORY https://github.com/luxonis/XLink.git
GIT_TAG 87785828fabdb1718760bb0a044405d5bbfbb3a2
GIT_TAG d46c049e30d2a56f7bbec2e25e7e2fa5c09ec6d0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we cross link the XLink PR in this PRs description? Thanks!

)

FetchContent_MakeAvailable(
Expand Down
2 changes: 1 addition & 1 deletion examples/cpp/Camera/camera_max_resolution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ int main() {
}

return 0;
}
}
2 changes: 1 addition & 1 deletion examples/cpp/Camera/camera_output.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ int main() {
}

return 0;
}
}
3 changes: 3 additions & 0 deletions include/depthai/device/DeviceGate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "depthai/device/Version.hpp"
#include "depthai/utility/Pimpl.hpp"
#include "depthai/xlink/XLinkConnection.hpp"
#include "depthai/xlink/XLinkStream.hpp"
namespace dai {

/**
Expand Down Expand Up @@ -65,6 +66,8 @@ class DeviceGate {
std::atomic_bool sessionCreated{false};

XLinkPlatform_t platform;
std::shared_ptr<XLinkConnection> gateConnection;
std::shared_ptr<XLinkStream> gateStream;
std::string version;
// pimpl
class Impl;
Expand Down
1 change: 1 addition & 0 deletions shared/depthai-shared
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs to be removed

Submodule depthai-shared added at 9762f3
251 changes: 242 additions & 9 deletions src/device/DeviceGate.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "device/DeviceGate.hpp"

#include <XLink/XLinkPublicDefines.h>
#include <XLink/XLinkPlatform.h>

// std
#include <fstream>
Expand All @@ -27,6 +28,27 @@ const std::string API_ROOT{"/api/v1"};
const auto sessionsEndpoint = API_ROOT + "/sessions";
const int DEFAULT_PORT{11492};

enum USBRequestID_t {
RESPONSE_OK,
RESPONSE_ERROR,
CREATE_SESSION,
START_SESSION,
UPLOAD_FWP,
STOP_SESSION,
DESTROY_SESSION,
DELETE_SESSION,
IS_OKAY,
GET_VERSION,
GET_STATE,
GET_FILE,
};

struct USBRequest_t {
uint16_t RequestNum;
uint32_t RequestSize;
}__attribute__((packed));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this cross platform?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My 2c, can just skip packed by making both uint32_t or swapping them around

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's definitely cross platform



class DeviceGate::Impl {
public:
Impl() = default;
Expand All @@ -44,7 +66,7 @@ DeviceGate::DeviceGate(const DeviceInfo& deviceInfo) : deviceInfo(deviceInfo) {
if(deviceInfo.platform != X_LINK_RVC3 && deviceInfo.platform != X_LINK_RVC4) {
throw std::invalid_argument("Gate only supports RVC3 and RVC4 platforms");
}
this->platform = deviceInfo.platform;
this->platform =deviceInfo.platform;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whitespace change

if(deviceInfo.platform == X_LINK_RVC3) {
version = DEPTHAI_DEVICE_RVC3_VERSION;
} else if(deviceInfo.platform == X_LINK_RVC4) {
Expand All @@ -56,12 +78,33 @@ DeviceGate::DeviceGate(const DeviceInfo& deviceInfo) : deviceInfo(deviceInfo) {
pimpl->cli = std::make_unique<httplib::Client>(deviceInfo.name, DEFAULT_PORT);
pimpl->cli->set_read_timeout(60); // 60 seconds timeout to allow for compressing the crash dumps without async
// pimpl->cli->set_connection_timeout(2);

}

bool DeviceGate::isOkay() {
if(auto res = pimpl->cli->Get("/api/v1/status")) {
return nlohmann::json::parse(res->body)["status"].get<bool>();
} else {
USBRequest_t request;
request.RequestNum = IS_OKAY;
request.RequestSize = 0;
XLinkPlatformGateWrite(&request, sizeof(USBRequest_t));

XLinkPlatformGateRead(&request, sizeof(request));
if(request.RequestNum == RESPONSE_ERROR) {
return false;
}

char *respBuffer = new char[request.RequestSize + 1];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets use C++ here - eg a vector /w reserve or resize and pass its "data()" to XLink to not have to manually new & delete

XLinkPlatformGateRead(respBuffer, request.RequestSize);
respBuffer[request.RequestSize]= '\0';

bool result = nlohmann::json::parse(respBuffer)["status"].get<bool>();
delete[] respBuffer;

return result;
}

return false;
}

Expand All @@ -70,6 +113,26 @@ Version DeviceGate::getVersion() {
if(res && res->status == 200) {
auto versionStr = nlohmann::json::parse(res->body)["version_gate"].get<std::string>();
return Version{versionStr};
} else {
USBRequest_t request;
request.RequestNum = GET_VERSION;
request.RequestSize = 0;
XLinkPlatformGateWrite(&request, sizeof(USBRequest_t));

XLinkPlatformGateRead(&request, sizeof(request));
if(request.RequestNum == RESPONSE_ERROR) {
return Version{0, 0, 0};
}

char *respBuffer = new char[request.RequestSize + 1];
XLinkPlatformGateRead(respBuffer, request.RequestSize);
respBuffer[request.RequestSize]= '\0';

auto result = nlohmann::json::parse(respBuffer)["version_gate"].get<std::string>();
delete[] respBuffer;

return Version{result};

}
return Version{0, 0, 0};
}
Expand All @@ -83,6 +146,28 @@ DeviceGate::VersionInfo DeviceGate::getAllVersion() {
info.gate = result.value("version_gate", "");
info.os = result.value("version_os", "");
return info;
} else {
USBRequest_t request;
request.RequestNum = GET_VERSION;
request.RequestSize = 0;
XLinkPlatformGateWrite(&request, sizeof(USBRequest_t));

XLinkPlatformGateRead(&request, sizeof(request));
if(request.RequestNum == RESPONSE_ERROR) {
return {};
}

char *respBuffer = new char[request.RequestSize + 1];
XLinkPlatformGateRead(respBuffer, request.RequestSize);
respBuffer[request.RequestSize]= '\0';
auto result = nlohmann::json::parse(respBuffer);
delete[] respBuffer;

VersionInfo info;
info.gate = result.value("version_gate", "");
info.os = result.value("version_os", "");
return info;

}
return {};
}
Expand Down Expand Up @@ -144,7 +229,50 @@ bool DeviceGate::createSession(bool exclusive) {
sessionCreated = true;
return true;
} else {
spdlog::warn("DeviceGate createSession not successful - got no response");
USBRequest_t request;
request.RequestNum = CREATE_SESSION;
request.RequestSize = createSessionBody.dump().size();
XLinkPlatformGateWrite(&request, sizeof(USBRequest_t));
XLinkPlatformGateWrite((void*)createSessionBody.dump().c_str(), createSessionBody.dump().size());

XLinkPlatformGateRead(&request, sizeof(request));
char *respBuffer = new char[request.RequestSize + 1];
XLinkPlatformGateRead(respBuffer, request.RequestSize);
respBuffer[request.RequestSize]= '\0';
auto resp = nlohmann::json::parse(respBuffer);
delete[] respBuffer;
spdlog::debug("DeviceGate createSession response: {}", resp.dump());

// Retrieve sessionId
sessionId = resp["id"];
bool fwpExists = resp["fwp_exists"].get<bool>();

if(!fwpExists) {
std::vector<uint8_t> package;
std::string path;
if(!path.empty()) {
std::ifstream fwStream(path, std::ios::binary);
if(!fwStream.is_open()) throw std::runtime_error(fmt::format("Cannot flash bootloader, binary at path: {} doesn't exist", path));
package = std::vector<std::uint8_t>(std::istreambuf_iterator<char>(fwStream), {});
} else {
package = platform == X_LINK_RVC3 ? Resources::getInstance().getDeviceRVC3Fwp() : Resources::getInstance().getDeviceRVC4Fwp();
}

nlohmann::json uploadFwpBody = {{"sessionId", sessionId},
{"file", package}};
request.RequestNum = UPLOAD_FWP;
request.RequestSize = uploadFwpBody.dump().size();
XLinkPlatformGateWrite(&request, sizeof(USBRequest_t));
XLinkPlatformGateWrite((void*)uploadFwpBody.dump().c_str(), uploadFwpBody.dump().size());

XLinkPlatformGateRead(&request, sizeof(request));
if(request.RequestNum == RESPONSE_ERROR) {
spdlog::warn("DeviceGate upload fwp not successful - got no response");
return false;
}
}
sessionCreated = true;
return true;
}
return false;
}
Expand All @@ -159,7 +287,19 @@ bool DeviceGate::startSession() {
spdlog::debug("DeviceGate start fwp successful");
return true;
} else {
spdlog::debug("DeviceGate start fwp not successful - got no response");
USBRequest_t request;
request.RequestNum = START_SESSION;
request.RequestSize = sessionId.size();
XLinkPlatformGateWrite(&request, sizeof(USBRequest_t));
XLinkPlatformGateWrite((void*)sessionId.c_str(), sessionId.size());

XLinkPlatformGateRead(&request, sizeof(request));
if(request.RequestNum == RESPONSE_ERROR) {
spdlog::debug("DeviceGate start fwp not successful - got no response");
return false;
}
spdlog::debug("DeviceGate start fwp successful");
return true;
}

return false;
Expand Down Expand Up @@ -188,7 +328,19 @@ bool DeviceGate::stopSession() {
spdlog::debug("DeviceGate stopSession successful");
return true;
} else {
spdlog::error("DeviceGate stopSession not successful - got no response");
USBRequest_t request;
request.RequestNum = STOP_SESSION;
request.RequestSize = sessionId.size();
XLinkPlatformGateWrite(&request, sizeof(USBRequest_t));
XLinkPlatformGateWrite((void*)sessionId.c_str(), sessionId.size());

XLinkPlatformGateRead(&request, sizeof(request));
if(request.RequestNum == RESPONSE_ERROR) {
spdlog::error("DeviceGate stopSession not successful - got no response");
return false;
}
spdlog::debug("DeviceGate stopSession successful");
return true;
}

return false;
Expand All @@ -214,7 +366,19 @@ bool DeviceGate::destroySession() {
spdlog::debug("DeviceGate destroySession successful");
return true;
} else {
spdlog::error("DeviceGate destroySession not successful - got no response");
USBRequest_t request;
request.RequestNum = DESTROY_SESSION;
request.RequestSize = sessionId.size();
XLinkPlatformGateWrite(&request, sizeof(USBRequest_t));
XLinkPlatformGateWrite((void*)sessionId.c_str(), sessionId.size());

XLinkPlatformGateRead(&request, sizeof(request));
if(request.RequestNum == RESPONSE_ERROR) {
spdlog::error("DeviceGate destroySession not successful - got no response");
return false;
}
spdlog::debug("DeviceGate destroySession successful");
return true;
}
return false;
}
Expand All @@ -234,7 +398,19 @@ bool DeviceGate::deleteSession() {
spdlog::debug("DeviceGate deleteSession successful");
return true;
} else {
spdlog::error("DeviceGate deleteSession not successful - got no response");
USBRequest_t request;
request.RequestNum = DELETE_SESSION;
request.RequestSize = sessionId.size();
XLinkPlatformGateWrite(&request, sizeof(USBRequest_t));
XLinkPlatformGateWrite((void*)sessionId.c_str(), sessionId.size());

XLinkPlatformGateRead(&request, sizeof(request));
if(request.RequestNum == RESPONSE_ERROR) {
spdlog::error("DeviceGate deleteSession not successful - got no response");
return false;
}
spdlog::debug("DeviceGate deleteSession successful");
return true;
}
return false;
}
Expand Down Expand Up @@ -273,7 +449,43 @@ DeviceGate::SessionState DeviceGate::getState() {
}
return sessionState;
} else {
spdlog::warn("DeviceGate getState not successful - got no response");
USBRequest_t request;
request.RequestNum = GET_STATE;
request.RequestSize = sessionId.size();
XLinkPlatformGateWrite(&request, sizeof(USBRequest_t));
XLinkPlatformGateWrite((void*)sessionId.c_str(), sessionId.size());

XLinkPlatformGateRead(&request, sizeof(request));
if(request.RequestNum == RESPONSE_ERROR) {
spdlog::warn("DeviceGate getState not successful - got no response");
return SessionState::ERROR_STATE;
}

char *respBuffer = new char[request.RequestSize + 1];
XLinkPlatformGateRead(respBuffer, request.RequestSize);
respBuffer[request.RequestSize]= '\0';
auto resp = nlohmann::json::parse(respBuffer);
delete[] respBuffer;
spdlog::trace("DeviceGate getState response: {}", resp.dump());

std::string sessionStateStr = resp["state"];
if(sessionStateStr == "CREATED") {
sessionState = SessionState::CREATED;
} else if(sessionStateStr == "RUNNING") {
sessionState = SessionState::RUNNING;
} else if(sessionStateStr == "STOPPED") {
sessionState = SessionState::STOPPED;
} else if(sessionStateStr == "STOPPING") {
sessionState = SessionState::STOPPING;
} else if(sessionStateStr == "CRASHED") {
sessionState = SessionState::CRASHED;
} else if(sessionStateStr == "DESTROYED") {
sessionState = SessionState::DESTROYED;
} else {
spdlog::warn("DeviceGate getState not successful - unknown session state: {}", sessionStateStr);
sessionState = SessionState::ERROR_STATE;
}
return sessionState;
}
return SessionState::ERROR_STATE;
}
Expand All @@ -293,8 +505,29 @@ std::optional<std::vector<uint8_t>> DeviceGate::getFile(const std::string& fileU
return std::nullopt;
}
} else {
spdlog::warn("File download not successful - got no response");
return std::nullopt;
USBRequest_t request;
request.RequestNum = GET_FILE;
request.RequestSize = fileUrl.size();
XLinkPlatformGateWrite(&request, sizeof(USBRequest_t));
XLinkPlatformGateWrite((void*)fileUrl.c_str(), fileUrl.size());

XLinkPlatformGateRead(&request, sizeof(request));
if(request.RequestNum == RESPONSE_ERROR) {
spdlog::warn("File download not successful - got no response");
return std::nullopt;
}

char *respBuffer = new char[request.RequestSize + 1];
XLinkPlatformGateRead(respBuffer, request.RequestSize);
respBuffer[request.RequestSize]= '\0';
auto resp = nlohmann::json::parse(respBuffer);
delete[] respBuffer;

filename = resp["filename"].get<std::string>();
std::vector<uint8_t> fileData(resp["data"].get<std::vector<uint8_t>>());

spdlog::debug("File download successful. Filename: {}", filename);
return fileData;
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/utility/LogCollection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ std::string protocolToString(XLinkProtocol_t protocol) {
return "X_LINK_LOCAL_SHDMEM";
case X_LINK_TCP_IP_OR_LOCAL_SHDMEM:
return "X_LINK_TCP_IP_OR_LOCAL_SHDMEM";
case X_LINK_USB_EP:
return "X_LINK_USB_EP";
case X_LINK_NMB_OF_PROTOCOLS:
return "X_LINK_NMB_OF_PROTOCOLS";
case X_LINK_ANY_PROTOCOL:
Expand Down
Loading