18 #include <XLink/XLink.h>
20 #include <XLink/XLinkLog.h>
23 #include "spdlog/details/os.h"
24 #include "spdlog/fmt/chrono.h"
25 #include "spdlog/spdlog.h"
31 name = std::string(desc.name);
32 mxid = std::string(desc.mxid);
45 if(mxidOrName.find(
".") != std::string::npos) {
47 name = std::move(mxidOrName);
52 mxid = std::move(mxidOrName);
58 deviceDesc_t desc = {};
61 desc.mxid[
sizeof(desc.mxid) - 1] = 0;
62 strncpy(desc.mxid,
mxid.c_str(),
sizeof(desc.mxid) - 1);
63 desc.name[
sizeof(desc.name) - 1] = 0;
64 strncpy(desc.name,
name.c_str(),
sizeof(desc.name) - 1);
80 return fmt::format(
"DeviceInfo(name={}, mxid={}, {}, {}, {}, {})",
83 XLinkDeviceStateToStr(
state),
90 XLinkProtocol_t defaultProtocol = X_LINK_ANY_PROTOCOL;
94 std::transform(protocolStr.begin(), protocolStr.end(), protocolStr.begin(), ::tolower);
95 if(protocolStr.empty() || protocolStr ==
"any") {
96 defaultProtocol = X_LINK_ANY_PROTOCOL;
97 }
else if(protocolStr ==
"usb") {
98 defaultProtocol = X_LINK_USB_VSC;
99 }
else if(protocolStr ==
"tcpip") {
100 defaultProtocol = X_LINK_TCP_IP;
105 return defaultProtocol;
116 std::vector<DeviceInfo> devices;
118 unsigned int numdev = 0;
119 std::array<deviceDesc_t, 64> deviceDescAll = {};
120 deviceDesc_t suitableDevice = {};
122 suitableDevice.platform = platform;
123 suitableDevice.state = state;
129 auto status = XLinkFindAllSuitableDevices(suitableDevice, deviceDescAll.data(),
static_cast<unsigned int>(deviceDescAll.size()), &numdev);
130 if(
status != X_LINK_SUCCESS &&
status != X_LINK_DEVICE_NOT_FOUND)
throw std::runtime_error(
"Couldn't retrieve all connected devices");
132 for(
unsigned i = 0; i < numdev; i++) {
135 if(skipInvalidDevices) {
136 if(
info.status == X_LINK_SUCCESS) {
138 }
else if(
info.status == X_LINK_INSUFFICIENT_PERMISSIONS) {
139 logger::warn(
"Insufficient permissions to communicate with {} device having name \"{}\". Make sure udev rules are set",
140 XLinkDeviceStateToStr(
info.state),
144 logger::warn(
"skipping {} device having name \"{}\"", XLinkDeviceStateToStr(
info.state),
info.name);
149 bool allowedMxId = allowedDeviceMxIds.find(
info.getMxId()) != std::string::npos || allowedDeviceMxIds.empty();
150 bool allowedId = allowedDeviceIds.find(
info.getMxId()) != std::string::npos || allowedDeviceIds.empty();
151 bool allowedName = allowedDeviceNames.find(
info.name) != std::string::npos || allowedDeviceNames.empty();
152 if(allowedMxId && allowedId && allowedName) {
153 devices.push_back(
info);
164 devReq.
protocol = X_LINK_ANY_PROTOCOL;
168 devReq.
state = state;
170 deviceDesc_t desc = {};
172 if(res == X_LINK_SUCCESS) {
173 if(skipInvalidDevice) {
174 if(desc.status == X_LINK_SUCCESS) {
176 }
else if(desc.status == X_LINK_INSUFFICIENT_PERMISSIONS) {
177 logger::warn(
"Insufficient permissions to communicate with {} device having name \"{}\". Make sure udev rules are set",
178 XLinkDeviceStateToStr(desc.state),
182 logger::warn(
"skipping {} device having name \"{}\"", XLinkDeviceStateToStr(desc.state), desc.name);
200 deviceDesc_t desc = {};
202 if(res == X_LINK_SUCCESS) {
203 if(skipInvalidDevices) {
204 if(desc.status == X_LINK_SUCCESS) {
206 }
else if(desc.status == X_LINK_INSUFFICIENT_PERMISSIONS) {
207 logger::warn(
"Insufficient permissions to communicate with {} device having name \"{}\". Make sure udev rules are set",
208 XLinkDeviceStateToStr(desc.state),
212 logger::warn(
"skipping {} device having name \"{}\"", XLinkDeviceStateToStr(desc.state), desc.name);
224 using namespace std::chrono;
230 XLinkError_t bootBootloaderError = XLinkBootBootloader(&deviceDesc);
231 if(bootBootloaderError != X_LINK_SUCCESS) {
232 throw std::runtime_error(fmt::format(
"Couldn't boot device to bootloader - {}", XLinkErrorToStr(bootBootloaderError)));
237 deviceToWait.
state = X_LINK_BOOTLOADER;
242 descToWait.nameHintOnly =
true;
245 deviceDesc_t foundDeviceDesc = {};
252 const std::vector<std::pair<std::string, std::chrono::milliseconds*>> evars = {
253 {
"DEPTHAI_BOOTUP_TIMEOUT", &bootupTimeout},
256 for(
auto ev : evars) {
257 auto name = ev.first;
259 if(!valstr.empty()) {
261 std::chrono::milliseconds value{std::stoi(valstr)};
265 }
catch(
const std::invalid_argument& e) {
271 auto tstart = steady_clock::now();
273 rc = XLinkFindFirstSuitableDevice(descToWait, &foundDeviceDesc);
274 if(rc == X_LINK_SUCCESS)
break;
276 }
while(steady_clock::now() - tstart < bootupTimeout);
279 if(rc != X_LINK_SUCCESS) {
296 if(!testStream.good())
throw std::runtime_error(
"Error path doesn't exist. Note: Environment variables in path are not expanded. (E.g. '~', '$PATH').");
311 std::lock_guard<std::mutex> lock(
closedMtx);
316 std::lock_guard<std::mutex> lock(
closedMtx);
319 using namespace std::chrono;
320 constexpr
auto RESET_TIMEOUT = seconds(2);
321 constexpr
auto BOOTUP_SEARCH = seconds(5);
326 auto ret = XLinkResetRemoteTimeout(
deviceLinkId, duration_cast<milliseconds>(RESET_TIMEOUT).count());
327 if(ret != X_LINK_SUCCESS) {
328 logger::debug(
"XLinkResetRemoteTimeout returned: {}", XLinkErrorToStr(ret));
338 auto t1 = steady_clock::now();
344 if(rebootingDeviceInfo.
state == X_LINK_UNBOOTED || rebootingDeviceInfo.
state == X_LINK_BOOTLOADER) {
348 }
while(!found && steady_clock::now() - t1 < BOOTUP_SEARCH);
351 logger::debug(
"XLinkResetRemote of linkId: ({})", previousLinkId);
370 std::ifstream fwStream(
pathToMvcmd, std::ios::binary);
371 if(!fwStream.is_open())
throw std::runtime_error(fmt::format(
"Cannot boot firmware, binary at path: {} doesn't exist",
pathToMvcmd));
372 std::vector<uint8_t>
package = std::vector<std::uint8_t>(std::istreambuf_iterator<char>(fwStream), {});
377 auto status = XLinkBootMemory(&deviceToBoot,
mvcmd.data(),
static_cast<unsigned long>(
mvcmd.size()));
378 return status == X_LINK_SUCCESS;
384 XLinkError_t rc = X_LINK_ERROR;
386 using namespace std::chrono;
397 const std::vector<std::pair<std::string, std::chrono::milliseconds*>> evars = {
398 {
"DEPTHAI_CONNECT_TIMEOUT", &connectTimeout},
399 {
"DEPTHAI_BOOTUP_TIMEOUT", &bootupTimeout},
402 for(
auto ev : evars) {
403 auto name = ev.first;
405 if(!valstr.empty()) {
407 std::chrono::milliseconds value{std::stoi(valstr)};
410 }
catch(
const std::invalid_argument& e) {
419 deviceToBoot.
state = X_LINK_UNBOOTED;
421 deviceDesc_t foundDeviceDesc = {};
424 auto tstart = steady_clock::now();
426 rc = XLinkFindFirstSuitableDevice(deviceToBoot.
getXLinkDeviceDesc(), &foundDeviceDesc);
427 if(rc == X_LINK_SUCCESS)
break;
429 }
while(steady_clock::now() - tstart < bootupTimeout);
432 if(rc != X_LINK_SUCCESS) {
445 throw std::runtime_error(
"Failed to boot device!");
454 bootedDeviceInfo.
state = expectedState;
459 bootedDescInfo.nameHintOnly =
true;
461 logger::debug(
"Searching for booted device: {}, name used as hint only", bootedDeviceInfo.
toString());
464 deviceDesc_t foundDeviceDesc = {};
465 auto tstart = steady_clock::now();
467 rc = XLinkFindFirstSuitableDevice(bootedDescInfo, &foundDeviceDesc);
468 if(rc == X_LINK_SUCCESS)
break;
470 }
while(steady_clock::now() - tstart < bootupTimeout);
472 if(rc != X_LINK_SUCCESS) {
481 XLinkHandler_t connectionHandler = {};
483 connectionHandler.devicePath = desc.name;
484 connectionHandler.protocol = lastDeviceInfo.
protocol;
486 auto tstart = steady_clock::now();
488 if((rc = XLinkConnect(&connectionHandler)) == X_LINK_SUCCESS)
break;
490 }
while(steady_clock::now() - tstart < connectTimeout);
492 if(rc != X_LINK_SUCCESS)
throw std::runtime_error(
"Failed to connect to device, error message: " +
convertErrorCodeToString(rc));
505 return XLinkErrorToStr(errorCode);
511 if(XLinkGetGlobalProfilingData(&prof) != X_LINK_SUCCESS) {
512 throw std::runtime_error(
"Couldn't retrieve profiling data");
514 data.numBytesRead = prof.totalReadBytes;
515 data.numBytesWritten = prof.totalWriteBytes;
522 if(XLinkGetProfilingData(
deviceLinkId, &prof) != X_LINK_SUCCESS) {
523 throw std::runtime_error(
"Couldn't retrieve profiling data");
525 data.numBytesRead = prof.totalReadBytes;
526 data.numBytesWritten = prof.totalWriteBytes;