2018-05-10 14:46:34 +08:00
|
|
|
// Copyright 2018 Slightech Co., Ltd. All rights reserved.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
2018-10-27 21:24:04 +08:00
|
|
|
#include "mynteye/device/channels.h"
|
2018-04-09 15:54:14 +08:00
|
|
|
|
2018-04-13 16:08:47 +08:00
|
|
|
#include <bitset>
|
2018-04-10 20:20:42 +08:00
|
|
|
#include <chrono>
|
|
|
|
#include <iomanip>
|
2018-04-14 20:21:40 +08:00
|
|
|
#include <iterator>
|
|
|
|
#include <sstream>
|
2018-04-10 00:26:22 +08:00
|
|
|
#include <stdexcept>
|
|
|
|
|
2018-09-04 15:12:04 +08:00
|
|
|
#include "mynteye/logger.h"
|
2018-10-27 21:24:04 +08:00
|
|
|
#include "mynteye/util/strings.h"
|
|
|
|
#include "mynteye/util/times.h"
|
2018-05-15 14:54:22 +08:00
|
|
|
|
|
|
|
#define IMU_TRACK_PERIOD 25 // ms
|
2018-04-19 17:23:02 +08:00
|
|
|
|
2018-04-09 15:54:14 +08:00
|
|
|
MYNTEYE_BEGIN_NAMESPACE
|
|
|
|
|
2018-04-10 00:26:22 +08:00
|
|
|
namespace {
|
|
|
|
|
2018-06-07 11:19:58 +08:00
|
|
|
const uvc::xu mynteye_xu = {3,
|
|
|
|
2,
|
|
|
|
{0x947a6d9f,
|
|
|
|
0x8a2f,
|
|
|
|
0x418d,
|
|
|
|
{0x85, 0x9e, 0x6c, 0x9a, 0xa0, 0x38, 0x10, 0x14}}};
|
2018-05-07 15:03:52 +08:00
|
|
|
|
2018-04-10 00:26:22 +08:00
|
|
|
int XuCamCtrlId(Option option) {
|
|
|
|
switch (option) {
|
|
|
|
case Option::EXPOSURE_MODE:
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case Option::MAX_GAIN:
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
case Option::MAX_EXPOSURE_TIME:
|
|
|
|
return 2;
|
|
|
|
break;
|
|
|
|
case Option::DESIRED_BRIGHTNESS:
|
|
|
|
return 3;
|
|
|
|
break;
|
|
|
|
case Option::IMU_FREQUENCY:
|
|
|
|
return 4;
|
|
|
|
break;
|
|
|
|
case Option::IR_CONTROL:
|
|
|
|
return 5;
|
|
|
|
break;
|
|
|
|
case Option::HDR_MODE:
|
|
|
|
return 6;
|
|
|
|
break;
|
|
|
|
case Option::FRAME_RATE:
|
|
|
|
return 7;
|
|
|
|
break;
|
2018-11-20 15:23:07 +08:00
|
|
|
case Option::ACCELEROMETER_RANGE:
|
|
|
|
return 9;
|
|
|
|
break;
|
|
|
|
case Option::GYROSCOPE_RANGE:
|
|
|
|
return 10;
|
|
|
|
break;
|
2018-04-10 00:26:22 +08:00
|
|
|
default:
|
|
|
|
LOG(FATAL) << "No cam ctrl id for " << option;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-10 16:00:38 +08:00
|
|
|
int XuHalfDuplexId(Option option) {
|
|
|
|
switch (option) {
|
|
|
|
case Option::ZERO_DRIFT_CALIBRATION:
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case Option::ERASE_CHIP:
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
LOG(FATAL) << "No half duplex id for " << option;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-19 17:23:02 +08:00
|
|
|
void CheckSpecVersion(const Version *spec_version) {
|
|
|
|
if (spec_version == nullptr) {
|
|
|
|
LOG(FATAL) << "Spec version must be specified";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string> spec_versions{"1.0"};
|
|
|
|
for (auto &&spec_ver : spec_versions) {
|
|
|
|
if (*spec_version == Version(spec_ver)) {
|
|
|
|
return; // supported
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::ostringstream ss;
|
|
|
|
std::copy(
|
|
|
|
spec_versions.begin(), spec_versions.end(),
|
|
|
|
std::ostream_iterator<std::string>(ss, ","));
|
|
|
|
LOG(FATAL) << "Spec version " << spec_version->to_string()
|
2018-04-19 22:47:12 +08:00
|
|
|
<< " not supported, must in [" << ss.str() << "]";
|
2018-04-19 17:23:02 +08:00
|
|
|
}
|
|
|
|
|
2018-04-10 00:26:22 +08:00
|
|
|
} // namespace
|
|
|
|
|
2018-04-10 20:20:42 +08:00
|
|
|
Channels::Channels(std::shared_ptr<uvc::device> device)
|
|
|
|
: device_(device),
|
|
|
|
is_imu_tracking_(false),
|
|
|
|
imu_track_stop_(false),
|
|
|
|
imu_sn_(0),
|
|
|
|
imu_callback_(nullptr) {
|
2018-04-09 15:54:14 +08:00
|
|
|
VLOG(2) << __func__;
|
2018-04-10 13:58:37 +08:00
|
|
|
UpdateControlInfos();
|
|
|
|
}
|
|
|
|
|
|
|
|
Channels::~Channels() {
|
|
|
|
VLOG(2) << __func__;
|
2018-04-10 20:20:42 +08:00
|
|
|
StopImuTracking();
|
2018-04-10 13:58:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Channels::LogControlInfos() const {
|
|
|
|
for (auto &&it = control_infos_.begin(); it != control_infos_.end(); it++) {
|
|
|
|
LOG(INFO) << it->first << ": min=" << it->second.min
|
|
|
|
<< ", max=" << it->second.max << ", def=" << it->second.def
|
|
|
|
<< ", cur=" << GetControlValue(it->first);
|
|
|
|
}
|
|
|
|
}
|
2018-04-10 00:26:22 +08:00
|
|
|
|
2018-04-10 13:58:37 +08:00
|
|
|
void Channels::UpdateControlInfos() {
|
2018-04-10 00:26:22 +08:00
|
|
|
for (auto &&option : std::vector<Option>{Option::GAIN, Option::BRIGHTNESS,
|
|
|
|
Option::CONTRAST}) {
|
|
|
|
control_infos_[option] = PuControlInfo(option);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto &&option : std::vector<Option>{
|
|
|
|
Option::FRAME_RATE, Option::IMU_FREQUENCY, Option::EXPOSURE_MODE,
|
|
|
|
Option::MAX_GAIN, Option::MAX_EXPOSURE_TIME,
|
2018-11-20 15:23:07 +08:00
|
|
|
Option::DESIRED_BRIGHTNESS, Option::IR_CONTROL, Option::HDR_MODE,
|
|
|
|
Option::ACCELEROMETER_RANGE, Option::GYROSCOPE_RANGE}) {
|
2018-04-10 00:26:22 +08:00
|
|
|
control_infos_[option] = XuControlInfo(option);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VLOG_IS_ON(2)) {
|
|
|
|
for (auto &&it = control_infos_.begin(); it != control_infos_.end(); it++) {
|
|
|
|
VLOG(2) << it->first << ": min=" << it->second.min
|
|
|
|
<< ", max=" << it->second.max << ", def=" << it->second.def
|
|
|
|
<< ", cur=" << GetControlValue(it->first);
|
|
|
|
}
|
|
|
|
}
|
2018-04-09 15:54:14 +08:00
|
|
|
}
|
|
|
|
|
2018-04-10 00:26:22 +08:00
|
|
|
Channels::control_info_t Channels::GetControlInfo(const Option &option) const {
|
|
|
|
try {
|
|
|
|
return control_infos_.at(option);
|
|
|
|
} catch (const std::out_of_range &e) {
|
2018-04-10 13:58:37 +08:00
|
|
|
LOG(WARNING) << "Get control info of " << option << " failed";
|
2018-04-10 00:26:22 +08:00
|
|
|
return {0, 0, 0};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::int32_t Channels::GetControlValue(const Option &option) const {
|
|
|
|
switch (option) {
|
|
|
|
case Option::GAIN:
|
|
|
|
case Option::BRIGHTNESS:
|
|
|
|
case Option::CONTRAST:
|
|
|
|
std::int32_t value;
|
2018-04-10 17:48:27 +08:00
|
|
|
if (PuControlQuery(option, uvc::PU_QUERY_GET, &value)) {
|
|
|
|
return value;
|
|
|
|
} else {
|
2018-04-10 00:26:22 +08:00
|
|
|
LOG(WARNING) << option << " get value failed";
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
case Option::FRAME_RATE:
|
|
|
|
case Option::IMU_FREQUENCY:
|
|
|
|
case Option::EXPOSURE_MODE:
|
|
|
|
case Option::MAX_GAIN:
|
|
|
|
case Option::MAX_EXPOSURE_TIME:
|
|
|
|
case Option::DESIRED_BRIGHTNESS:
|
|
|
|
case Option::IR_CONTROL:
|
|
|
|
case Option::HDR_MODE:
|
2018-11-20 15:23:07 +08:00
|
|
|
case Option::ACCELEROMETER_RANGE:
|
|
|
|
case Option::GYROSCOPE_RANGE:
|
2018-04-10 00:26:22 +08:00
|
|
|
return XuCamCtrlGet(option);
|
|
|
|
case Option::ZERO_DRIFT_CALIBRATION:
|
|
|
|
case Option::ERASE_CHIP:
|
|
|
|
LOG(WARNING) << option << " get value useless";
|
|
|
|
return -1;
|
|
|
|
default:
|
2018-05-30 12:31:54 +08:00
|
|
|
LOG(ERROR) << "Unsupported option " << option;
|
2018-04-10 00:26:22 +08:00
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Channels::SetControlValue(const Option &option, std::int32_t value) {
|
2018-04-10 13:58:37 +08:00
|
|
|
auto in_range = [this, &option, &value]() {
|
|
|
|
auto &&info = GetControlInfo(option);
|
|
|
|
if (value < info.min || value > info.max) {
|
|
|
|
LOG(WARNING) << option << " set value out of range, " << value
|
|
|
|
<< " not in [" << info.min << "," << info.max << "]";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
2018-04-14 20:21:40 +08:00
|
|
|
auto in_values = [&option, &value](std::vector<std::int32_t> values) {
|
|
|
|
if (std::find(values.begin(), values.end(), value) != values.end()) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
std::ostringstream ss;
|
|
|
|
std::copy(
|
|
|
|
values.begin(), values.end(),
|
|
|
|
std::ostream_iterator<std::int32_t>(ss, ","));
|
2018-04-19 22:47:12 +08:00
|
|
|
LOG(WARNING) << option << " set value invalid, must in [" << ss.str()
|
|
|
|
<< "]";
|
2018-04-14 20:21:40 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
2018-04-10 13:58:37 +08:00
|
|
|
switch (option) {
|
|
|
|
case Option::GAIN:
|
|
|
|
case Option::BRIGHTNESS:
|
|
|
|
case Option::CONTRAST: {
|
|
|
|
if (!in_range())
|
|
|
|
break;
|
|
|
|
if (!PuControlQuery(option, uvc::PU_QUERY_SET, &value)) {
|
|
|
|
LOG(WARNING) << option << " set value failed";
|
|
|
|
}
|
|
|
|
} break;
|
2018-04-14 20:21:40 +08:00
|
|
|
case Option::FRAME_RATE: {
|
|
|
|
if (!in_range() ||
|
2018-10-17 11:12:40 +08:00
|
|
|
!in_values({10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60}))
|
2018-04-14 20:21:40 +08:00
|
|
|
break;
|
|
|
|
XuCamCtrlSet(option, value);
|
|
|
|
} break;
|
|
|
|
case Option::IMU_FREQUENCY: {
|
|
|
|
if (!in_range() || !in_values({100, 200, 250, 333, 500}))
|
|
|
|
break;
|
|
|
|
XuCamCtrlSet(option, value);
|
|
|
|
} break;
|
2018-11-20 15:23:07 +08:00
|
|
|
case Option::ACCELEROMETER_RANGE: {
|
|
|
|
if (!in_range() || !in_values({4, 8, 16, 32}))
|
|
|
|
break;
|
|
|
|
XuCamCtrlSet(option, value);
|
|
|
|
} break;
|
|
|
|
case Option::GYROSCOPE_RANGE: {
|
|
|
|
if (!in_range() || !in_values({500, 1000, 2000, 4000}))
|
|
|
|
break;
|
|
|
|
XuCamCtrlSet(option, value);
|
|
|
|
} break;
|
2018-04-10 13:58:37 +08:00
|
|
|
case Option::EXPOSURE_MODE:
|
|
|
|
case Option::MAX_GAIN:
|
|
|
|
case Option::MAX_EXPOSURE_TIME:
|
|
|
|
case Option::DESIRED_BRIGHTNESS:
|
|
|
|
case Option::IR_CONTROL:
|
|
|
|
case Option::HDR_MODE: {
|
|
|
|
if (!in_range())
|
|
|
|
break;
|
|
|
|
XuCamCtrlSet(option, value);
|
|
|
|
} break;
|
|
|
|
case Option::ZERO_DRIFT_CALIBRATION:
|
|
|
|
case Option::ERASE_CHIP:
|
|
|
|
LOG(WARNING) << option << " set value useless";
|
|
|
|
break;
|
|
|
|
default:
|
2018-05-30 12:31:54 +08:00
|
|
|
LOG(ERROR) << "Unsupported option " << option;
|
2018-04-10 13:58:37 +08:00
|
|
|
}
|
2018-04-10 00:26:22 +08:00
|
|
|
}
|
|
|
|
|
2018-04-10 16:00:38 +08:00
|
|
|
bool Channels::RunControlAction(const Option &option) const {
|
|
|
|
switch (option) {
|
|
|
|
case Option::ZERO_DRIFT_CALIBRATION:
|
|
|
|
return XuHalfDuplexSet(option, XU_CMD_ZDC);
|
|
|
|
case Option::ERASE_CHIP:
|
|
|
|
return XuHalfDuplexSet(option, XU_CMD_ERASE);
|
|
|
|
case Option::GAIN:
|
|
|
|
case Option::BRIGHTNESS:
|
|
|
|
case Option::CONTRAST:
|
|
|
|
case Option::FRAME_RATE:
|
|
|
|
case Option::IMU_FREQUENCY:
|
|
|
|
case Option::EXPOSURE_MODE:
|
|
|
|
case Option::MAX_GAIN:
|
|
|
|
case Option::MAX_EXPOSURE_TIME:
|
|
|
|
case Option::DESIRED_BRIGHTNESS:
|
|
|
|
case Option::IR_CONTROL:
|
|
|
|
case Option::HDR_MODE:
|
2018-11-20 15:23:07 +08:00
|
|
|
case Option::ACCELEROMETER_RANGE:
|
|
|
|
case Option::GYROSCOPE_RANGE:
|
2018-04-10 16:00:38 +08:00
|
|
|
LOG(WARNING) << option << " run action useless";
|
|
|
|
return false;
|
|
|
|
default:
|
2018-05-30 12:31:54 +08:00
|
|
|
LOG(ERROR) << "Unsupported option " << option;
|
|
|
|
return false;
|
2018-04-10 16:00:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-10 20:20:42 +08:00
|
|
|
void Channels::SetImuCallback(imu_callback_t callback) {
|
|
|
|
imu_callback_ = callback;
|
|
|
|
}
|
|
|
|
|
2018-06-07 11:19:58 +08:00
|
|
|
void Channels::DoImuTrack() {
|
|
|
|
static ImuReqPacket req_packet{0};
|
|
|
|
static ImuResPacket res_packet;
|
|
|
|
|
|
|
|
req_packet.serial_number = imu_sn_;
|
|
|
|
if (!XuImuWrite(req_packet)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!XuImuRead(&res_packet)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (res_packet.packets.size() == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
VLOG(2) << "Imu req sn: " << imu_sn_ << ", res count: " << []() {
|
|
|
|
std::size_t n = 0;
|
|
|
|
for (auto &&packet : res_packet.packets) {
|
|
|
|
n += packet.count;
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}();
|
|
|
|
|
|
|
|
auto &&sn = res_packet.packets.back().serial_number;
|
|
|
|
if (imu_sn_ == sn) {
|
|
|
|
VLOG(2) << "New imu not ready, dropped";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
imu_sn_ = sn;
|
|
|
|
|
|
|
|
if (imu_callback_) {
|
|
|
|
for (auto &&packet : res_packet.packets) {
|
|
|
|
imu_callback_(packet);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
res_packet.packets.clear();
|
|
|
|
}
|
|
|
|
|
2018-04-10 20:20:42 +08:00
|
|
|
void Channels::StartImuTracking(imu_callback_t callback) {
|
|
|
|
if (is_imu_tracking_) {
|
2018-04-12 11:18:56 +08:00
|
|
|
LOG(WARNING) << "Start imu tracking failed, is tracking already";
|
2018-04-10 20:20:42 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (callback) {
|
|
|
|
imu_callback_ = callback;
|
|
|
|
}
|
|
|
|
is_imu_tracking_ = true;
|
|
|
|
imu_track_thread_ = std::thread([this]() {
|
|
|
|
imu_sn_ = 0;
|
2018-05-16 16:37:12 +08:00
|
|
|
auto sleep = [](const times::system_clock::time_point &time_beg) {
|
|
|
|
auto &&time_elapsed_ms =
|
|
|
|
times::count<times::milliseconds>(times::now() - time_beg);
|
|
|
|
if (time_elapsed_ms < IMU_TRACK_PERIOD) {
|
|
|
|
std::this_thread::sleep_for(
|
|
|
|
std::chrono::milliseconds(IMU_TRACK_PERIOD - time_elapsed_ms));
|
|
|
|
VLOG(2) << "Imu track cost " << time_elapsed_ms << " ms"
|
|
|
|
<< ", sleep " << (IMU_TRACK_PERIOD - time_elapsed_ms) << " ms";
|
|
|
|
}
|
2018-05-15 14:54:22 +08:00
|
|
|
};
|
2018-04-10 20:20:42 +08:00
|
|
|
while (!imu_track_stop_) {
|
2018-05-15 14:54:22 +08:00
|
|
|
auto &&time_beg = times::now();
|
2018-06-07 11:19:58 +08:00
|
|
|
DoImuTrack();
|
2018-05-16 16:37:12 +08:00
|
|
|
sleep(time_beg);
|
2018-04-10 20:20:42 +08:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void Channels::StopImuTracking() {
|
|
|
|
if (!is_imu_tracking_) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (imu_track_thread_.joinable()) {
|
|
|
|
imu_track_stop_ = true;
|
|
|
|
imu_track_thread_.join();
|
|
|
|
imu_track_stop_ = false;
|
|
|
|
is_imu_tracking_ = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-13 16:08:47 +08:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
T _from_data(const std::uint8_t *data) {
|
|
|
|
std::size_t size = sizeof(T) / sizeof(std::uint8_t);
|
|
|
|
T value = 0;
|
|
|
|
for (std::size_t i = 0; i < size; i++) {
|
|
|
|
value |= data[i] << (8 * (size - i - 1));
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
double _from_data(const std::uint8_t *data) {
|
|
|
|
return *(reinterpret_cast<const double *>(data));
|
|
|
|
}
|
|
|
|
|
2018-04-19 17:23:02 +08:00
|
|
|
std::string _from_data(const std::uint8_t *data, std::size_t count) {
|
|
|
|
std::string s(reinterpret_cast<const char *>(data), count);
|
|
|
|
strings::trim(s);
|
|
|
|
return s;
|
|
|
|
}
|
2018-04-13 16:08:47 +08:00
|
|
|
|
|
|
|
std::size_t from_data(Channels::device_info_t *info, const std::uint8_t *data) {
|
2018-04-19 17:23:02 +08:00
|
|
|
std::size_t i = 4; // skip vid, pid
|
2018-04-13 16:08:47 +08:00
|
|
|
// name, 16
|
2018-04-19 17:23:02 +08:00
|
|
|
info->name = _from_data(data + i, 16);
|
2018-04-13 16:08:47 +08:00
|
|
|
i += 16;
|
|
|
|
// serial_number, 16
|
2018-04-19 17:23:02 +08:00
|
|
|
info->serial_number = _from_data(data + i, 16);
|
2018-04-13 16:08:47 +08:00
|
|
|
i += 16;
|
|
|
|
// firmware_version, 2
|
|
|
|
info->firmware_version.set_major(data[i]);
|
|
|
|
info->firmware_version.set_minor(data[i + 1]);
|
|
|
|
i += 2;
|
|
|
|
// hardware_version, 3
|
|
|
|
info->hardware_version.set_major(data[i]);
|
|
|
|
info->hardware_version.set_minor(data[i + 1]);
|
|
|
|
info->hardware_version.set_flag(std::bitset<8>(data[i + 2]));
|
|
|
|
i += 3;
|
|
|
|
// spec_version, 2
|
|
|
|
info->spec_version.set_major(data[i]);
|
|
|
|
info->spec_version.set_minor(data[i + 1]);
|
|
|
|
i += 2;
|
|
|
|
// lens_type, 4
|
|
|
|
info->lens_type.set_vendor(_from_data<std::uint16_t>(data + i));
|
|
|
|
info->lens_type.set_product(_from_data<std::uint16_t>(data + i + 2));
|
|
|
|
i += 4;
|
|
|
|
// imu_type, 4
|
|
|
|
info->imu_type.set_vendor(_from_data<std::uint16_t>(data + i));
|
|
|
|
info->imu_type.set_product(_from_data<std::uint16_t>(data + i + 2));
|
|
|
|
i += 4;
|
|
|
|
// nominal_baseline, 2
|
|
|
|
info->nominal_baseline = _from_data<std::uint16_t>(data + i);
|
|
|
|
i += 2;
|
2018-04-19 17:23:02 +08:00
|
|
|
|
2018-04-13 16:08:47 +08:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::size_t from_data(
|
2018-04-19 22:44:40 +08:00
|
|
|
Intrinsics *in, const std::uint8_t *data, const Version *spec_version) {
|
2018-04-13 16:08:47 +08:00
|
|
|
std::size_t i = 0;
|
|
|
|
|
|
|
|
// width, 2
|
2018-04-19 22:44:40 +08:00
|
|
|
in->width = _from_data<std::uint16_t>(data + i);
|
2018-04-13 16:08:47 +08:00
|
|
|
i += 2;
|
|
|
|
// height, 2
|
2018-04-19 22:44:40 +08:00
|
|
|
in->height = _from_data<std::uint16_t>(data + i);
|
2018-04-13 16:08:47 +08:00
|
|
|
i += 2;
|
|
|
|
// fx, 8
|
2018-04-19 22:44:40 +08:00
|
|
|
in->fx = _from_data<double>(data + i);
|
2018-04-13 16:08:47 +08:00
|
|
|
i += 8;
|
|
|
|
// fy, 8
|
2018-04-19 22:44:40 +08:00
|
|
|
in->fy = _from_data<double>(data + i);
|
2018-04-13 16:08:47 +08:00
|
|
|
i += 8;
|
|
|
|
// cx, 8
|
2018-04-19 22:44:40 +08:00
|
|
|
in->cx = _from_data<double>(data + i);
|
2018-04-13 16:08:47 +08:00
|
|
|
i += 8;
|
|
|
|
// cy, 8
|
2018-04-19 22:44:40 +08:00
|
|
|
in->cy = _from_data<double>(data + i);
|
2018-04-13 16:08:47 +08:00
|
|
|
i += 8;
|
|
|
|
// model, 1
|
2018-04-19 22:44:40 +08:00
|
|
|
in->model = data[i];
|
2018-04-13 16:08:47 +08:00
|
|
|
i += 1;
|
|
|
|
// coeffs, 40
|
|
|
|
for (std::size_t j = 0; j < 5; j++) {
|
2018-04-19 22:44:40 +08:00
|
|
|
in->coeffs[j] = _from_data<double>(data + i + j * 8);
|
2018-04-13 16:08:47 +08:00
|
|
|
}
|
|
|
|
i += 40;
|
|
|
|
|
2018-09-11 10:19:25 +08:00
|
|
|
MYNTEYE_UNUSED(spec_version)
|
2018-04-13 16:08:47 +08:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::size_t from_data(
|
2018-04-19 22:44:40 +08:00
|
|
|
ImuIntrinsics *in, const std::uint8_t *data, const Version *spec_version) {
|
2018-04-13 16:08:47 +08:00
|
|
|
std::size_t i = 0;
|
|
|
|
|
2018-04-19 22:44:40 +08:00
|
|
|
// scale
|
2018-04-13 16:08:47 +08:00
|
|
|
for (std::size_t j = 0; j < 3; j++) {
|
|
|
|
for (std::size_t k = 0; k < 3; k++) {
|
2018-04-19 22:44:40 +08:00
|
|
|
in->scale[j][k] = _from_data<double>(data + i + (j * 3 + k) * 8);
|
2018-04-13 16:08:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
i += 72;
|
2018-04-19 22:44:40 +08:00
|
|
|
// drift
|
2018-04-13 16:08:47 +08:00
|
|
|
for (std::size_t j = 0; j < 3; j++) {
|
2018-04-19 22:44:40 +08:00
|
|
|
in->drift[j] = _from_data<double>(data + i + j * 8);
|
2018-04-13 16:08:47 +08:00
|
|
|
}
|
|
|
|
i += 24;
|
2018-04-19 22:44:40 +08:00
|
|
|
// noise
|
2018-04-13 16:08:47 +08:00
|
|
|
for (std::size_t j = 0; j < 3; j++) {
|
2018-04-19 22:44:40 +08:00
|
|
|
in->noise[j] = _from_data<double>(data + i + j * 8);
|
2018-04-13 16:08:47 +08:00
|
|
|
}
|
|
|
|
i += 24;
|
2018-04-19 22:44:40 +08:00
|
|
|
// bias
|
2018-04-13 16:08:47 +08:00
|
|
|
for (std::size_t j = 0; j < 3; j++) {
|
2018-04-19 22:44:40 +08:00
|
|
|
in->bias[j] = _from_data<double>(data + i + j * 8);
|
2018-04-13 16:08:47 +08:00
|
|
|
}
|
|
|
|
i += 24;
|
|
|
|
|
2018-09-11 10:19:25 +08:00
|
|
|
MYNTEYE_UNUSED(spec_version)
|
2018-04-19 22:44:40 +08:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::size_t from_data(
|
|
|
|
Extrinsics *ex, const std::uint8_t *data, const Version *spec_version) {
|
|
|
|
std::size_t i = 0;
|
|
|
|
|
2018-04-13 16:08:47 +08:00
|
|
|
// rotation
|
|
|
|
for (std::size_t j = 0; j < 3; j++) {
|
|
|
|
for (std::size_t k = 0; k < 3; k++) {
|
2018-04-19 22:44:40 +08:00
|
|
|
ex->rotation[j][k] = _from_data<double>(data + i + (j * 3 + k) * 8);
|
2018-04-13 16:08:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
i += 72;
|
|
|
|
// translation
|
|
|
|
for (std::size_t j = 0; j < 3; j++) {
|
2018-04-19 22:44:40 +08:00
|
|
|
ex->translation[j] = _from_data<double>(data + i + j * 8);
|
2018-04-13 16:08:47 +08:00
|
|
|
}
|
|
|
|
i += 24;
|
|
|
|
|
2018-09-11 10:19:25 +08:00
|
|
|
MYNTEYE_UNUSED(spec_version)
|
2018-04-13 16:08:47 +08:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2018-04-19 22:44:40 +08:00
|
|
|
std::size_t from_data(
|
|
|
|
Channels::img_params_t *img_params, const std::uint8_t *data,
|
|
|
|
const Version *spec_version) {
|
|
|
|
std::size_t i = 0;
|
|
|
|
i += from_data(&img_params->in_left, data + i, spec_version);
|
|
|
|
i += from_data(&img_params->in_right, data + i, spec_version);
|
2018-07-22 10:42:15 +08:00
|
|
|
i += from_data(&img_params->ex_right_to_left, data + i, spec_version);
|
2018-04-19 22:44:40 +08:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::size_t from_data(
|
|
|
|
Channels::imu_params_t *imu_params, const std::uint8_t *data,
|
|
|
|
const Version *spec_version) {
|
|
|
|
std::size_t i = 0;
|
|
|
|
i += from_data(&imu_params->in_accel, data + i, spec_version);
|
|
|
|
i += from_data(&imu_params->in_gyro, data + i, spec_version);
|
|
|
|
i += from_data(&imu_params->ex_left_to_imu, data + i, spec_version);
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2018-04-13 16:08:47 +08:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
bool Channels::GetFiles(
|
2018-04-19 17:23:02 +08:00
|
|
|
device_info_t *info, img_params_t *img_params, imu_params_t *imu_params,
|
|
|
|
Version *spec_version) const {
|
2018-04-13 16:08:47 +08:00
|
|
|
if (info == nullptr && img_params == nullptr && imu_params == nullptr) {
|
|
|
|
LOG(WARNING) << "Files are not provided to get";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::uint8_t data[2000]{};
|
|
|
|
|
|
|
|
std::bitset<8> header;
|
2018-04-13 21:24:07 +08:00
|
|
|
header[7] = 0; // get
|
2018-04-13 16:08:47 +08:00
|
|
|
|
2018-04-13 21:24:07 +08:00
|
|
|
header[0] = (info != nullptr);
|
|
|
|
header[1] = (img_params != nullptr);
|
|
|
|
header[2] = (imu_params != nullptr);
|
2018-04-13 16:08:47 +08:00
|
|
|
|
|
|
|
data[0] = static_cast<std::uint8_t>(header.to_ulong());
|
2018-04-19 17:23:02 +08:00
|
|
|
VLOG(2) << "GetFiles header: 0x" << std::hex << std::uppercase << std::setw(2)
|
|
|
|
<< std::setfill('0') << static_cast<int>(data[0]);
|
2018-04-13 16:08:47 +08:00
|
|
|
if (!XuFileQuery(uvc::XU_QUERY_SET, 2000, data)) {
|
|
|
|
LOG(WARNING) << "GetFiles failed";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (XuFileQuery(uvc::XU_QUERY_GET, 2000, data)) {
|
|
|
|
// header = std::bitset<8>(data[0]);
|
|
|
|
std::uint16_t size = _from_data<std::uint16_t>(data + 1);
|
|
|
|
std::uint8_t checksum = data[3 + size];
|
2018-04-19 17:23:02 +08:00
|
|
|
VLOG(2) << "GetFiles data size: " << size << ", checksum: 0x" << std::hex
|
|
|
|
<< std::setw(2) << std::setfill('0') << static_cast<int>(checksum);
|
2018-04-13 16:08:47 +08:00
|
|
|
|
2018-04-17 14:46:11 +08:00
|
|
|
std::uint8_t checksum_now = 0;
|
2018-04-19 17:23:02 +08:00
|
|
|
for (std::size_t i = 3, n = 3 + size; i < n; i++) {
|
2018-04-17 14:46:11 +08:00
|
|
|
checksum_now = (checksum_now ^ data[i]);
|
2018-04-13 16:08:47 +08:00
|
|
|
}
|
2018-04-17 14:46:11 +08:00
|
|
|
if (checksum != checksum_now) {
|
2018-04-13 16:08:47 +08:00
|
|
|
LOG(WARNING) << "Files checksum should be 0x" << std::hex
|
|
|
|
<< std::uppercase << std::setw(2) << std::setfill('0')
|
2018-04-17 14:46:11 +08:00
|
|
|
<< static_cast<int>(checksum) << ", but 0x" << std::setw(2)
|
|
|
|
<< std::setfill('0') << static_cast<int>(checksum_now)
|
|
|
|
<< " now";
|
2018-04-13 16:08:47 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-04-19 17:23:02 +08:00
|
|
|
Version *spec_ver = spec_version;
|
2018-04-13 16:08:47 +08:00
|
|
|
std::size_t i = 3;
|
|
|
|
std::size_t end = 3 + size;
|
|
|
|
while (i < end) {
|
|
|
|
std::uint8_t file_id = *(data + i);
|
|
|
|
std::uint16_t file_size = _from_data<std::uint16_t>(data + i + 1);
|
2018-04-19 17:23:02 +08:00
|
|
|
VLOG(2) << "GetFiles id: " << static_cast<int>(file_id)
|
|
|
|
<< ", size: " << file_size;
|
2018-04-13 16:08:47 +08:00
|
|
|
i += 3;
|
|
|
|
switch (file_id) {
|
|
|
|
case FID_DEVICE_INFO: {
|
2018-04-20 12:45:40 +08:00
|
|
|
CHECK_EQ(from_data(info, data + i), file_size)
|
|
|
|
<< "The firmware not support getting device info, you could "
|
|
|
|
"upgrade to latest";
|
2018-04-19 17:23:02 +08:00
|
|
|
spec_ver = &info->spec_version;
|
|
|
|
CheckSpecVersion(spec_ver);
|
2018-04-13 16:08:47 +08:00
|
|
|
} break;
|
|
|
|
case FID_IMG_PARAMS: {
|
2018-04-19 17:23:02 +08:00
|
|
|
img_params->ok = file_size > 0;
|
|
|
|
if (img_params->ok) {
|
|
|
|
CheckSpecVersion(spec_ver);
|
|
|
|
CHECK_EQ(from_data(img_params, data + i, spec_ver), file_size);
|
|
|
|
}
|
2018-04-13 16:08:47 +08:00
|
|
|
} break;
|
|
|
|
case FID_IMU_PARAMS: {
|
2018-04-19 17:23:02 +08:00
|
|
|
imu_params->ok = file_size > 0;
|
|
|
|
if (imu_params->ok) {
|
|
|
|
CheckSpecVersion(spec_ver);
|
|
|
|
CHECK_EQ(from_data(imu_params, data + i, spec_ver), file_size);
|
|
|
|
}
|
2018-04-13 16:08:47 +08:00
|
|
|
} break;
|
|
|
|
default:
|
|
|
|
LOG(FATAL) << "Unsupported file id: " << file_id;
|
|
|
|
}
|
|
|
|
i += file_size;
|
|
|
|
}
|
|
|
|
|
2018-04-19 17:23:02 +08:00
|
|
|
VLOG(2) << "GetFiles success";
|
2018-04-13 16:08:47 +08:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
LOG(WARNING) << "GetFiles failed";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
std::size_t _to_data(T value, std::uint8_t *data) {
|
|
|
|
std::size_t size = sizeof(T) / sizeof(std::uint8_t);
|
|
|
|
for (std::size_t i = 0; i < size; i++) {
|
2018-04-19 17:23:02 +08:00
|
|
|
data[i] = static_cast<std::uint8_t>((value >> (8 * (size - i - 1))) & 0xFF);
|
2018-04-13 16:08:47 +08:00
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
std::size_t _to_data(double value, std::uint8_t *data) {
|
2018-04-19 17:23:02 +08:00
|
|
|
std::uint8_t *val = reinterpret_cast<std::uint8_t *>(&value);
|
|
|
|
std::copy(val, val + 8, data);
|
2018-04-13 16:08:47 +08:00
|
|
|
return 8;
|
|
|
|
}
|
|
|
|
|
2018-04-19 17:23:02 +08:00
|
|
|
std::size_t _to_data(std::string value, std::uint8_t *data, std::size_t count) {
|
2018-04-13 16:08:47 +08:00
|
|
|
std::copy(value.begin(), value.end(), data);
|
2018-04-19 17:23:02 +08:00
|
|
|
for (std::size_t i = value.size(); i < count; i++) {
|
|
|
|
data[i] = ' ';
|
|
|
|
}
|
|
|
|
return count;
|
2018-04-13 16:08:47 +08:00
|
|
|
}
|
|
|
|
|
2018-04-19 17:23:02 +08:00
|
|
|
std::size_t to_data(
|
|
|
|
const Channels::device_info_t *info, std::uint8_t *data,
|
|
|
|
const Version *spec_version) {
|
|
|
|
std::size_t i = 3; // skip id, size
|
|
|
|
i += 4; // skip vid, pid
|
2018-04-13 16:08:47 +08:00
|
|
|
// name, 16
|
2018-04-19 17:23:02 +08:00
|
|
|
_to_data(info->name, data + i, 16);
|
2018-04-13 16:08:47 +08:00
|
|
|
i += 16;
|
|
|
|
// serial_number, 16
|
2018-04-19 17:23:02 +08:00
|
|
|
_to_data(info->serial_number, data + i, 16);
|
2018-04-13 16:08:47 +08:00
|
|
|
i += 16;
|
|
|
|
// firmware_version, 2
|
|
|
|
data[i] = info->firmware_version.major();
|
|
|
|
data[i + 1] = info->firmware_version.minor();
|
|
|
|
i += 2;
|
|
|
|
// hardware_version, 3
|
|
|
|
data[i] = info->hardware_version.major();
|
|
|
|
data[i + 1] = info->hardware_version.minor();
|
|
|
|
data[i + 2] =
|
|
|
|
static_cast<std::uint8_t>(info->hardware_version.flag().to_ulong());
|
|
|
|
i += 3;
|
|
|
|
// spec_version, 2
|
|
|
|
data[i] = info->spec_version.major();
|
|
|
|
data[i + 1] = info->spec_version.minor();
|
|
|
|
i += 2;
|
|
|
|
// lens_type, 4
|
|
|
|
_to_data(info->lens_type.vendor(), data + i);
|
|
|
|
_to_data(info->lens_type.product(), data + i + 2);
|
|
|
|
i += 4;
|
|
|
|
// imu_type, 4
|
|
|
|
_to_data(info->imu_type.vendor(), data + i);
|
|
|
|
_to_data(info->imu_type.product(), data + i + 2);
|
|
|
|
i += 4;
|
|
|
|
// nominal_baseline, 2
|
|
|
|
_to_data(info->nominal_baseline, data + i);
|
|
|
|
i += 2;
|
2018-04-19 17:23:02 +08:00
|
|
|
|
2018-09-11 10:19:25 +08:00
|
|
|
MYNTEYE_UNUSED(spec_version)
|
2018-04-19 17:23:02 +08:00
|
|
|
|
2018-04-13 16:08:47 +08:00
|
|
|
// others
|
|
|
|
std::size_t size = i - 3;
|
|
|
|
data[0] = Channels::FID_DEVICE_INFO;
|
|
|
|
data[1] = static_cast<std::uint8_t>((size >> 8) & 0xFF);
|
|
|
|
data[2] = static_cast<std::uint8_t>(size & 0xFF);
|
|
|
|
return size + 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::size_t to_data(
|
2018-04-19 22:44:40 +08:00
|
|
|
const Intrinsics *in, std::uint8_t *data, const Version *spec_version) {
|
|
|
|
std::size_t i = 0;
|
2018-04-13 16:08:47 +08:00
|
|
|
|
|
|
|
// width, 2
|
2018-04-19 22:44:40 +08:00
|
|
|
_to_data(in->width, data + i);
|
2018-04-13 16:08:47 +08:00
|
|
|
i += 2;
|
|
|
|
// height, 2
|
2018-04-19 22:44:40 +08:00
|
|
|
_to_data(in->height, data + i);
|
2018-04-13 16:08:47 +08:00
|
|
|
i += 2;
|
|
|
|
// fx, 8
|
2018-04-19 22:44:40 +08:00
|
|
|
_to_data(in->fx, data + i);
|
2018-04-13 16:08:47 +08:00
|
|
|
i += 8;
|
|
|
|
// fy, 8
|
2018-04-19 22:44:40 +08:00
|
|
|
_to_data(in->fy, data + i);
|
2018-04-13 16:08:47 +08:00
|
|
|
i += 8;
|
|
|
|
// cx, 8
|
2018-04-19 22:44:40 +08:00
|
|
|
_to_data(in->cx, data + i);
|
2018-04-13 16:08:47 +08:00
|
|
|
i += 8;
|
|
|
|
// cy, 8
|
2018-04-19 22:44:40 +08:00
|
|
|
_to_data(in->cy, data + i);
|
2018-04-13 16:08:47 +08:00
|
|
|
i += 8;
|
|
|
|
// model, 1
|
2018-04-19 22:44:40 +08:00
|
|
|
data[i] = in->model;
|
2018-04-13 16:08:47 +08:00
|
|
|
i += 1;
|
|
|
|
// coeffs, 40
|
|
|
|
for (std::size_t j = 0; j < 5; j++) {
|
2018-04-19 22:44:40 +08:00
|
|
|
_to_data(in->coeffs[j], data + i + j * 8);
|
2018-04-13 16:08:47 +08:00
|
|
|
}
|
|
|
|
i += 40;
|
|
|
|
|
2018-09-11 10:19:25 +08:00
|
|
|
MYNTEYE_UNUSED(spec_version)
|
2018-04-19 22:44:40 +08:00
|
|
|
return i;
|
2018-04-13 16:08:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::size_t to_data(
|
2018-04-19 22:44:40 +08:00
|
|
|
const ImuIntrinsics *in, std::uint8_t *data, const Version *spec_version) {
|
|
|
|
std::size_t i = 0;
|
2018-04-13 16:08:47 +08:00
|
|
|
|
2018-04-19 22:44:40 +08:00
|
|
|
// scale
|
2018-04-13 16:08:47 +08:00
|
|
|
for (std::size_t j = 0; j < 3; j++) {
|
|
|
|
for (std::size_t k = 0; k < 3; k++) {
|
2018-04-19 22:44:40 +08:00
|
|
|
_to_data(in->scale[j][k], data + i + (j * 3 + k) * 8);
|
2018-04-13 16:08:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
i += 72;
|
2018-04-19 22:44:40 +08:00
|
|
|
// drift
|
2018-04-13 16:08:47 +08:00
|
|
|
for (std::size_t j = 0; j < 3; j++) {
|
2018-04-19 22:44:40 +08:00
|
|
|
_to_data(in->drift[j], data + i + j * 8);
|
2018-04-13 16:08:47 +08:00
|
|
|
}
|
|
|
|
i += 24;
|
2018-04-19 22:44:40 +08:00
|
|
|
// noise
|
2018-04-13 16:08:47 +08:00
|
|
|
for (std::size_t j = 0; j < 3; j++) {
|
2018-04-19 22:44:40 +08:00
|
|
|
_to_data(in->noise[j], data + i + j * 8);
|
2018-04-13 16:08:47 +08:00
|
|
|
}
|
|
|
|
i += 24;
|
2018-04-19 22:44:40 +08:00
|
|
|
// bias
|
2018-04-13 16:08:47 +08:00
|
|
|
for (std::size_t j = 0; j < 3; j++) {
|
2018-04-19 22:44:40 +08:00
|
|
|
_to_data(in->bias[j], data + i + j * 8);
|
2018-04-13 16:08:47 +08:00
|
|
|
}
|
|
|
|
i += 24;
|
|
|
|
|
2018-09-11 10:19:25 +08:00
|
|
|
MYNTEYE_UNUSED(spec_version)
|
2018-04-19 22:44:40 +08:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::size_t to_data(
|
|
|
|
const Extrinsics *ex, std::uint8_t *data, const Version *spec_version) {
|
|
|
|
std::size_t i = 0;
|
|
|
|
|
2018-04-13 16:08:47 +08:00
|
|
|
// rotation
|
|
|
|
for (std::size_t j = 0; j < 3; j++) {
|
|
|
|
for (std::size_t k = 0; k < 3; k++) {
|
2018-04-19 22:44:40 +08:00
|
|
|
_to_data(ex->rotation[j][k], data + i + (j * 3 + k) * 8);
|
2018-04-13 16:08:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
i += 72;
|
|
|
|
// translation
|
|
|
|
for (std::size_t j = 0; j < 3; j++) {
|
2018-04-19 22:44:40 +08:00
|
|
|
_to_data(ex->translation[j], data + i + j * 8);
|
2018-04-13 16:08:47 +08:00
|
|
|
}
|
|
|
|
i += 24;
|
|
|
|
|
2018-09-11 10:19:25 +08:00
|
|
|
MYNTEYE_UNUSED(spec_version)
|
2018-04-19 22:44:40 +08:00
|
|
|
return i;
|
|
|
|
}
|
2018-04-19 17:23:02 +08:00
|
|
|
|
2018-04-19 22:44:40 +08:00
|
|
|
std::size_t to_data(
|
|
|
|
const Channels::img_params_t *img_params, std::uint8_t *data,
|
|
|
|
const Version *spec_version) {
|
|
|
|
std::size_t i = 3; // skip id, size
|
|
|
|
i += to_data(&img_params->in_left, data + i, spec_version);
|
|
|
|
i += to_data(&img_params->in_right, data + i, spec_version);
|
2018-07-22 10:42:15 +08:00
|
|
|
i += to_data(&img_params->ex_right_to_left, data + i, spec_version);
|
2018-04-19 22:44:40 +08:00
|
|
|
// others
|
|
|
|
std::size_t size = i - 3;
|
|
|
|
data[0] = Channels::FID_IMG_PARAMS;
|
|
|
|
data[1] = static_cast<std::uint8_t>((size >> 8) & 0xFF);
|
|
|
|
data[2] = static_cast<std::uint8_t>(size & 0xFF);
|
|
|
|
return size + 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::size_t to_data(
|
|
|
|
const Channels::imu_params_t *imu_params, std::uint8_t *data,
|
|
|
|
const Version *spec_version) {
|
|
|
|
std::size_t i = 3; // skip id, size
|
|
|
|
i += to_data(&imu_params->in_accel, data + i, spec_version);
|
|
|
|
i += to_data(&imu_params->in_gyro, data + i, spec_version);
|
|
|
|
i += to_data(&imu_params->ex_left_to_imu, data + i, spec_version);
|
2018-04-13 16:08:47 +08:00
|
|
|
// others
|
|
|
|
std::size_t size = i - 3;
|
|
|
|
data[0] = Channels::FID_IMU_PARAMS;
|
|
|
|
data[1] = static_cast<std::uint8_t>((size >> 8) & 0xFF);
|
|
|
|
data[2] = static_cast<std::uint8_t>(size & 0xFF);
|
|
|
|
return size + 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
bool Channels::SetFiles(
|
2018-04-19 17:23:02 +08:00
|
|
|
device_info_t *info, img_params_t *img_params, imu_params_t *imu_params,
|
|
|
|
Version *spec_version) {
|
2018-04-13 16:08:47 +08:00
|
|
|
if (info == nullptr && img_params == nullptr && imu_params == nullptr) {
|
|
|
|
LOG(WARNING) << "Files are not provided to set";
|
|
|
|
return false;
|
|
|
|
}
|
2018-04-19 17:23:02 +08:00
|
|
|
Version *spec_ver = spec_version;
|
|
|
|
if (spec_ver == nullptr && info != nullptr) {
|
|
|
|
spec_ver = &info->spec_version;
|
|
|
|
}
|
|
|
|
CheckSpecVersion(spec_ver);
|
|
|
|
|
2018-04-13 16:08:47 +08:00
|
|
|
std::uint8_t data[2000]{};
|
|
|
|
|
|
|
|
std::bitset<8> header;
|
2018-04-13 21:24:07 +08:00
|
|
|
header[7] = 1; // set
|
2018-04-13 16:08:47 +08:00
|
|
|
|
|
|
|
std::uint16_t size = 0;
|
|
|
|
if (info != nullptr) {
|
2018-04-13 21:24:07 +08:00
|
|
|
header[0] = true;
|
2018-04-19 17:23:02 +08:00
|
|
|
size += to_data(info, data + 3 + size, spec_ver);
|
2018-04-13 16:08:47 +08:00
|
|
|
}
|
|
|
|
if (img_params != nullptr) {
|
2018-04-13 21:24:07 +08:00
|
|
|
header[1] = true;
|
2018-04-19 17:23:02 +08:00
|
|
|
size += to_data(img_params, data + 3 + size, spec_ver);
|
2018-04-13 16:08:47 +08:00
|
|
|
}
|
|
|
|
if (imu_params != nullptr) {
|
2018-04-13 21:24:07 +08:00
|
|
|
header[2] = true;
|
2018-04-19 17:23:02 +08:00
|
|
|
size += to_data(imu_params, data + 3 + size, spec_ver);
|
2018-04-13 16:08:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
data[0] = static_cast<std::uint8_t>(header.to_ulong());
|
|
|
|
data[1] = static_cast<std::uint8_t>((size >> 8) & 0xFF);
|
|
|
|
data[2] = static_cast<std::uint8_t>(size & 0xFF);
|
|
|
|
|
2018-04-19 17:23:02 +08:00
|
|
|
VLOG(2) << "SetFiles header: 0x" << std::hex << std::uppercase << std::setw(2)
|
|
|
|
<< std::setfill('0') << static_cast<int>(data[0]);
|
2018-04-13 16:08:47 +08:00
|
|
|
if (XuFileQuery(uvc::XU_QUERY_SET, 2000, data)) {
|
|
|
|
VLOG(2) << "SetFiles success";
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
LOG(WARNING) << "SetFiles failed";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-10 00:26:22 +08:00
|
|
|
bool Channels::PuControlRange(
|
|
|
|
Option option, int32_t *min, int32_t *max, int32_t *def) const {
|
|
|
|
CHECK_NOTNULL(device_);
|
|
|
|
return uvc::pu_control_range(*device_, option, min, max, def);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Channels::PuControlQuery(
|
|
|
|
Option option, uvc::pu_query query, int32_t *value) const {
|
|
|
|
CHECK_NOTNULL(device_);
|
|
|
|
return uvc::pu_control_query(*device_, option, query, value);
|
|
|
|
}
|
|
|
|
|
2018-05-25 12:32:58 +08:00
|
|
|
bool Channels::XuControlRange(
|
2018-06-07 11:19:58 +08:00
|
|
|
channel_t channel, uint8_t id, int32_t *min, int32_t *max,
|
|
|
|
int32_t *def) const {
|
2018-05-31 15:09:00 +08:00
|
|
|
return XuControlRange(mynteye_xu, channel, id, min, max, def);
|
2018-05-25 12:32:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Channels::XuControlRange(
|
2018-05-31 15:09:00 +08:00
|
|
|
const uvc::xu &xu, uint8_t selector, uint8_t id, int32_t *min, int32_t *max,
|
2018-05-25 12:32:58 +08:00
|
|
|
int32_t *def) const {
|
|
|
|
CHECK_NOTNULL(device_);
|
2018-05-31 15:09:00 +08:00
|
|
|
return uvc::xu_control_range(*device_, xu, selector, id, min, max, def);
|
2018-05-25 12:32:58 +08:00
|
|
|
}
|
|
|
|
|
2018-04-09 22:24:34 +08:00
|
|
|
bool Channels::XuControlQuery(
|
2018-04-10 16:00:38 +08:00
|
|
|
channel_t channel, uvc::xu_query query, uint16_t size,
|
|
|
|
uint8_t *data) const {
|
2018-05-29 12:21:30 +08:00
|
|
|
return XuControlQuery(mynteye_xu, channel, query, size, data);
|
2018-04-09 22:24:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Channels::XuControlQuery(
|
|
|
|
const uvc::xu &xu, uint8_t selector, uvc::xu_query query, uint16_t size,
|
2018-04-10 00:26:22 +08:00
|
|
|
uint8_t *data) const {
|
2018-04-09 15:54:14 +08:00
|
|
|
CHECK_NOTNULL(device_);
|
2018-04-09 22:24:34 +08:00
|
|
|
return uvc::xu_control_query(*device_, xu, selector, query, size, data);
|
2018-04-09 15:54:14 +08:00
|
|
|
}
|
|
|
|
|
2018-04-10 00:26:22 +08:00
|
|
|
bool Channels::XuCamCtrlQuery(
|
|
|
|
uvc::xu_query query, uint16_t size, uint8_t *data) const {
|
2018-04-10 16:00:38 +08:00
|
|
|
return XuControlQuery(CHANNEL_CAM_CTRL, query, size, data);
|
2018-04-10 00:26:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::int32_t Channels::XuCamCtrlGet(Option option) const {
|
|
|
|
int id = XuCamCtrlId(option);
|
|
|
|
|
|
|
|
std::uint8_t data[3] = {static_cast<std::uint8_t>((id | 0x80) & 0xFF), 0, 0};
|
|
|
|
if (!XuCamCtrlQuery(uvc::XU_QUERY_SET, 3, data)) {
|
2018-04-10 16:00:38 +08:00
|
|
|
LOG(WARNING) << "XuCamCtrlGet value of " << option << " failed";
|
2018-04-10 00:26:22 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
data[0] = id & 0xFF;
|
|
|
|
if (XuCamCtrlQuery(uvc::XU_QUERY_GET, 3, data)) {
|
2018-04-13 10:20:02 +08:00
|
|
|
return (data[1] << 8) | (data[2]);
|
2018-04-10 00:26:22 +08:00
|
|
|
} else {
|
2018-04-10 16:00:38 +08:00
|
|
|
LOG(WARNING) << "XuCamCtrlGet value of " << option << " failed";
|
2018-04-10 00:26:22 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-10 13:58:37 +08:00
|
|
|
void Channels::XuCamCtrlSet(Option option, std::int32_t value) const {
|
|
|
|
int id = XuCamCtrlId(option);
|
|
|
|
std::uint8_t data[3] = {static_cast<std::uint8_t>(id & 0xFF),
|
|
|
|
static_cast<std::uint8_t>((value >> 8) & 0xFF),
|
|
|
|
static_cast<std::uint8_t>(value & 0xFF)};
|
2018-04-10 17:48:27 +08:00
|
|
|
if (XuCamCtrlQuery(uvc::XU_QUERY_SET, 3, data)) {
|
2018-04-10 16:00:38 +08:00
|
|
|
VLOG(2) << "XuCamCtrlSet value (" << value << ") of " << option
|
|
|
|
<< " success";
|
2018-04-10 17:48:27 +08:00
|
|
|
} else {
|
|
|
|
LOG(WARNING) << "XuCamCtrlSet value (" << value << ") of " << option
|
|
|
|
<< " failed";
|
2018-04-10 16:00:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Channels::XuHalfDuplexSet(Option option, xu_cmd_t cmd) const {
|
|
|
|
int id = XuHalfDuplexId(option);
|
2018-04-12 20:50:40 +08:00
|
|
|
std::uint8_t data[20] = {static_cast<std::uint8_t>(id & 0xFF),
|
|
|
|
static_cast<std::uint8_t>(cmd)};
|
|
|
|
if (XuControlQuery(CHANNEL_HALF_DUPLEX, uvc::XU_QUERY_SET, 20, data)) {
|
2018-04-10 17:48:27 +08:00
|
|
|
VLOG(2) << "XuHalfDuplexSet value (0x" << std::hex << std::uppercase << cmd
|
|
|
|
<< ") of " << option << " success";
|
|
|
|
return true;
|
|
|
|
} else {
|
2018-04-10 16:00:38 +08:00
|
|
|
LOG(WARNING) << "XuHalfDuplexSet value (0x" << std::hex << std::uppercase
|
|
|
|
<< cmd << ") of " << option << " failed";
|
|
|
|
return false;
|
2018-04-10 17:48:27 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Channels::XuImuWrite(const ImuReqPacket &req) const {
|
|
|
|
auto &&data = req.to_data();
|
|
|
|
if (XuControlQuery(
|
|
|
|
CHANNEL_IMU_WRITE, uvc::XU_QUERY_SET, data.size(), data.data())) {
|
|
|
|
VLOG(2) << "XuImuWrite request success";
|
|
|
|
return true;
|
2018-04-10 16:00:38 +08:00
|
|
|
} else {
|
2018-04-10 17:48:27 +08:00
|
|
|
LOG(WARNING) << "XuImuWrite request failed";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Channels::XuImuRead(ImuResPacket *res) const {
|
|
|
|
static std::uint8_t data[2000]{};
|
|
|
|
// std::fill(data, data + 2000, 0); // reset
|
|
|
|
if (XuControlQuery(CHANNEL_IMU_READ, uvc::XU_QUERY_GET, 2000, data)) {
|
|
|
|
res->from_data(data);
|
2018-04-10 20:20:42 +08:00
|
|
|
|
|
|
|
if (res->header != 0x5B) {
|
|
|
|
LOG(WARNING) << "Imu response packet header must be 0x5B, but 0x"
|
|
|
|
<< std::hex << std::uppercase << std::setw(2)
|
|
|
|
<< std::setfill('0') << static_cast<int>(res->header)
|
|
|
|
<< " now";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (res->state != 0) {
|
|
|
|
LOG(WARNING) << "Imu response packet state must be 0, but " << res->state
|
|
|
|
<< " now";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::uint8_t checksum = 0;
|
|
|
|
for (std::size_t i = 4, n = 4 + res->size; i < n; i++) {
|
|
|
|
checksum = (checksum ^ data[i]);
|
|
|
|
}
|
2018-04-17 14:46:11 +08:00
|
|
|
if (res->checksum != checksum) {
|
2018-04-10 20:20:42 +08:00
|
|
|
LOG(WARNING) << "Imu response packet checksum should be 0x" << std::hex
|
|
|
|
<< std::uppercase << std::setw(2) << std::setfill('0')
|
2018-04-17 14:46:11 +08:00
|
|
|
<< static_cast<int>(res->checksum) << ", but 0x"
|
|
|
|
<< std::setw(2) << std::setfill('0')
|
|
|
|
<< static_cast<int>(checksum) << " now";
|
2018-04-10 20:20:42 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
VLOG(2) << "XuImuRead response success";
|
2018-04-10 16:00:38 +08:00
|
|
|
return true;
|
2018-04-10 17:48:27 +08:00
|
|
|
} else {
|
|
|
|
LOG(WARNING) << "XuImuRead response failed";
|
|
|
|
return false;
|
2018-04-10 13:58:37 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-13 16:08:47 +08:00
|
|
|
bool Channels::XuFileQuery(
|
|
|
|
uvc::xu_query query, uint16_t size, uint8_t *data) const {
|
|
|
|
return XuControlQuery(CHANNEL_FILE, query, size, data);
|
|
|
|
}
|
|
|
|
|
2018-04-10 00:26:22 +08:00
|
|
|
Channels::control_info_t Channels::PuControlInfo(Option option) const {
|
|
|
|
int32_t min = 0, max = 0, def = 0;
|
|
|
|
if (!PuControlRange(option, &min, &max, &def)) {
|
2018-04-10 16:00:38 +08:00
|
|
|
LOG(WARNING) << "Get PuControlInfo of " << option << " failed";
|
2018-04-10 00:26:22 +08:00
|
|
|
}
|
|
|
|
return {min, max, def};
|
|
|
|
}
|
|
|
|
|
|
|
|
Channels::control_info_t Channels::XuControlInfo(Option option) const {
|
|
|
|
int id = XuCamCtrlId(option);
|
|
|
|
|
2018-05-25 12:32:58 +08:00
|
|
|
int32_t min = 0, max = 0, def = 0;
|
2018-06-07 11:19:58 +08:00
|
|
|
if (!XuControlRange(
|
|
|
|
CHANNEL_CAM_CTRL, static_cast<std::uint8_t>(id), &min, &max, &def)) {
|
2018-04-10 16:00:38 +08:00
|
|
|
LOG(WARNING) << "Get XuControlInfo of " << option << " failed";
|
2018-04-10 00:26:22 +08:00
|
|
|
}
|
2018-05-25 12:32:58 +08:00
|
|
|
return {min, max, def};
|
2018-04-10 00:26:22 +08:00
|
|
|
}
|
|
|
|
|
2018-04-09 15:54:14 +08:00
|
|
|
MYNTEYE_END_NAMESPACE
|