5 #include <condition_variable>
12 #include "archive_entry.h"
15 #include "spdlog/details/os.h"
16 #include "spdlog/fmt/chrono.h"
17 #include "spdlog/spdlog.h"
34 #ifdef DEPTHAI_RESOURCE_COMPILED_BINARIES
35 #include "cmrc/cmrc.hpp"
36 CMRC_DECLARE(depthai);
41 static std::vector<std::uint8_t>
createPrebootHeader(
const std::vector<uint8_t>& payload, uint32_t magic1, uint32_t magic2);
57 template <
typename V,
typename... T>
58 static constexpr
auto array_of(T&&... t) -> std::array<V,
sizeof...(T)> {
59 return {{std::forward<T>(t)...}};
71 std::unique_lock<std::mutex> lock(
mtxDevice);
75 std::vector<std::uint8_t> finalFwBinary;
82 if(!pathToMvcmd.
empty()) {
83 finalFwBinaryPath = pathToMvcmd;
87 if(!fwBinaryPath.
empty()) {
88 finalFwBinaryPath = fwBinaryPath;
91 if(!finalFwBinaryPath.
empty()) {
93 std::ifstream stream(finalFwBinaryPath, std::ios::binary);
94 if(!stream.is_open()) {
97 throw std::runtime_error(
98 fmt::format(
"File at path {}{} doesn't exist.", finalFwBinaryPath, !fwBinaryPath.
empty() ?
" pointed to by DEPTHAI_DEVICE_BINARY" :
""));
100 logger::warn(
"Overriding firmware: {}", finalFwBinaryPath);
102 finalFwBinary = std::vector<std::uint8_t>(std::istreambuf_iterator<char>(stream), {});
105 #ifdef DEPTHAI_RESOURCE_COMPILED_BINARIES
107 std::unordered_set<OpenVINO::Version> deprecatedVersions(
110 if(deprecatedVersions.count(version)) {
115 std::vector<std::uint8_t> depthaiBinary;
117 std::vector<std::uint8_t> depthaiPatch;
148 if(!depthaiPatch.empty()) {
158 std::vector<std::uint8_t> tmpDepthaiBinary{};
159 tmpDepthaiBinary.resize(patchedSize);
162 int error =
bspatch_mem(depthaiBinary.data(), depthaiBinary.size(), depthaiPatch.data(), depthaiPatch.size(), tmpDepthaiBinary.data());
166 throw std::runtime_error(fmt::format(
171 depthaiBinary = std::move(tmpDepthaiBinary);
174 finalFwBinary = std::move(depthaiBinary);
186 finalFwBinary.insert(finalFwBinary.begin(), prebootHeader.begin(), prebootHeader.end());
189 return finalFwBinary;
209 std::string blEnvVar;
211 blEnvVar =
"DEPTHAI_BOOTLOADER_BINARY_USB";
213 blEnvVar =
"DEPTHAI_BOOTLOADER_BINARY_ETH";
216 if(!blBinaryPath.
empty()) {
218 std::ifstream stream(blBinaryPath, std::ios::binary);
219 if(!stream.is_open()) {
222 throw std::runtime_error(fmt::format(
"File at path {} pointed to by {} doesn't exist.", blBinaryPath, blEnvVar));
224 logger::warn(
"Overriding bootloader {}: {}", blEnvVar, blBinaryPath);
226 return std::vector<std::uint8_t>(std::istreambuf_iterator<char>(stream), {});
231 throw std::invalid_argument(
"DeviceBootloader::Type::AUTO not allowed, when getting bootloader firmware.");
243 throw std::invalid_argument(
"Invalid Bootloader Type specified.");
253 template <
typename CV,
typename BOOL,
typename MTX,
typename PATH,
typename LIST,
typename MAP>
254 std::function<void()>
getLazyTarXzFunction(MTX&
mtx, CV& cv, BOOL& ready, PATH cmrcPath, LIST& resourceList, MAP& resourceMap) {
255 return [&
mtx, &cv, &ready, cmrcPath, &resourceList, &resourceMap] {
256 using namespace std::chrono;
259 auto fs = cmrc::depthai::get_filesystem();
260 auto tarXz = fs.open(cmrcPath);
262 auto t1 = steady_clock::now();
265 struct archive* a = archive_read_new();
266 archive_read_support_filter_xz(a);
267 archive_read_support_format_tar(a);
268 int r = archive_read_open_memory(a, tarXz.begin(), tarXz.size());
269 assert(r == ARCHIVE_OK);
271 auto t2 = steady_clock::now();
273 struct archive_entry* entry;
274 while(archive_read_next_header(a, &entry) == ARCHIVE_OK) {
276 for(
const auto& cpath : resourceList) {
277 std::string resPath(cpath);
278 if(resPath == std::string(archive_entry_pathname(entry))) {
280 resourceMap[resPath] = std::vector<std::uint8_t>();
283 std::size_t readSize = 16 * 1024;
284 if(archive_entry_size_is_set(entry)) {
286 readSize = archive_entry_size(entry);
290 long long finalSize = 0;
294 auto currentSize = resourceMap[resPath].size();
297 resourceMap[resPath].resize(currentSize + readSize);
298 long long size = archive_read_data(a, &resourceMap[resPath][currentSize], readSize);
313 resourceMap[resPath].resize(finalSize);
320 r = archive_read_free(a);
321 assert(r == ARCHIVE_OK);
326 for(
const auto& cpath : resourceList) {
327 std::string resPath(cpath);
328 assert(resourceMap.count(resPath) > 0);
331 auto t3 = steady_clock::now();
335 "Resources - Archive '{}' open: {}, archive read: {}", cmrcPath, duration_cast<milliseconds>(t2 - t1), duration_cast<milliseconds>(t3 - t2));
339 std::unique_lock<std::mutex> l(
mtx);
348 struct archive* a = archive_read_new();
349 auto r = archive_read_free(a);
350 assert(r == ARCHIVE_OK);
383 std::vector<std::uint8_t>
createPrebootHeader(
const std::vector<uint8_t>& payload, uint32_t magic1, uint32_t magic2) {
385 const std::uint8_t HEADER[] = {77, 65, 50, 120,
388 0x9A, 0xA8, 0x00, 0x32, 0x20, 0xAD, 0xDE, 0xD0, 0xF1,
389 0x9A, 0x9C, 0x00, 0x32, 0x20, 0xFF, 0xFF, 0xFF, 0xFF,
390 0x9A, 0xA8, 0x00, 0x32, 0x20, 0xAD, 0xDE, 0xD0, 0xF1,
391 0x9A, 0xA4, 0x00, 0x32, 0x20, 0x01, 0x00, 0x00, 0x00,
393 static_cast<uint8_t
>((magic1 >> 0) & 0xFF),
394 static_cast<uint8_t
>((magic1 >> 8) & 0xFF),
395 static_cast<uint8_t
>((magic1 >> 16) & 0xFF),
396 static_cast<uint8_t
>((magic1 >> 24) & 0xFF)};
400 std::vector<std::uint8_t> prebootHeader;
403 prebootHeader.insert(prebootHeader.begin(), std::begin(HEADER), std::end(HEADER));
406 std::size_t totalPayloadSize = payload.size() +
sizeof(magic2) +
sizeof(uint32_t) +
sizeof(uint32_t);
407 std::size_t toAddBytes = 0;
408 if(totalPayloadSize % 4 != 0) {
409 toAddBytes = 4 - (totalPayloadSize % 4);
411 std::size_t totalSize = totalPayloadSize + toAddBytes;
412 std::size_t totalSizeWord = totalSize / 4;
415 prebootHeader.push_back((totalSizeWord >> 0) & 0xFF);
416 prebootHeader.push_back((totalSizeWord >> 8) & 0xFF);
422 for(
const auto& field : {magic2,
checksum,
static_cast<uint32_t
>(payload.size())}) {
423 for(
int i = 0; i < 4; i++) {
424 prebootHeader.push_back((field >> (i * 8)) & 0xFF);
429 prebootHeader.insert(prebootHeader.end(), payload.begin(), payload.end());
431 for(std::size_t i = 0; i < toAddBytes; i++) {
432 prebootHeader.push_back(0x00);
435 return prebootHeader;