MYNT-EYE-S-SDK/src/internal/channels.cc

966 lines
26 KiB
C++
Raw Normal View History

2018-04-09 10:54:14 +03:00
#include "internal/channels.h"
#include <glog/logging.h>
2018-04-13 11:08:47 +03:00
#include <bitset>
2018-04-10 15:20:42 +03:00
#include <chrono>
#include <iomanip>
#include <iterator>
#include <sstream>
2018-04-09 19:26:22 +03:00
#include <stdexcept>
2018-04-09 10:54:14 +03:00
MYNTEYE_BEGIN_NAMESPACE
2018-04-09 19:26:22 +03:00
namespace {
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;
default:
LOG(FATAL) << "No cam ctrl id for " << option;
}
}
2018-04-10 11:00:38 +03: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-09 19:26:22 +03:00
} // namespace
2018-04-10 15:20:42 +03: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 10:54:14 +03:00
VLOG(2) << __func__;
2018-04-10 08:58:37 +03:00
UpdateControlInfos();
}
Channels::~Channels() {
VLOG(2) << __func__;
2018-04-10 15:20:42 +03:00
StopImuTracking();
2018-04-10 08:58:37 +03: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-09 19:26:22 +03:00
2018-04-10 08:58:37 +03:00
void Channels::UpdateControlInfos() {
2018-04-09 19:26:22 +03: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,
Option::DESIRED_BRIGHTNESS, Option::IR_CONTROL, Option::HDR_MODE}) {
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 10:54:14 +03:00
}
2018-04-09 19:26:22 +03: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 08:58:37 +03:00
LOG(WARNING) << "Get control info of " << option << " failed";
2018-04-09 19:26:22 +03: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 12:48:27 +03:00
if (PuControlQuery(option, uvc::PU_QUERY_GET, &value)) {
return value;
} else {
2018-04-09 19:26:22 +03: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:
return XuCamCtrlGet(option);
case Option::ZERO_DRIFT_CALIBRATION:
case Option::ERASE_CHIP:
LOG(WARNING) << option << " get value useless";
return -1;
default:
LOG(FATAL) << "Unsupported option " << option;
}
return -1;
}
void Channels::SetControlValue(const Option &option, std::int32_t value) {
2018-04-10 08:58:37 +03: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;
};
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, ","));
LOG(WARNING) << option << " set value invalid, must be {" << ss.str()
<< "}";
return false;
}
};
2018-04-10 08:58:37 +03: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;
case Option::FRAME_RATE: {
if (!in_range() ||
!in_values({10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60}))
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-04-10 08:58:37 +03: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:
LOG(FATAL) << "Unsupported option " << option;
}
2018-04-09 19:26:22 +03:00
}
2018-04-10 11:00:38 +03: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:
LOG(WARNING) << option << " run action useless";
return false;
default:
LOG(FATAL) << "Unsupported option " << option;
}
}
2018-04-10 15:20:42 +03:00
void Channels::SetImuCallback(imu_callback_t callback) {
imu_callback_ = callback;
}
void Channels::StartImuTracking(imu_callback_t callback) {
if (is_imu_tracking_) {
2018-04-12 06:18:56 +03:00
LOG(WARNING) << "Start imu tracking failed, is tracking already";
2018-04-10 15:20:42 +03:00
return;
}
if (callback) {
imu_callback_ = callback;
}
is_imu_tracking_ = true;
imu_track_thread_ = std::thread([this]() {
imu_sn_ = 0;
ImuReqPacket req_packet{imu_sn_};
ImuResPacket res_packet;
2018-04-12 15:21:40 +03:00
// auto sleep_milli = [](std::intmax_t n) {
// std::this_thread::sleep_for(std::chrono::milliseconds(n));
// };
2018-04-10 15:20:42 +03:00
while (!imu_track_stop_) {
req_packet.serial_number = imu_sn_;
if (!XuImuWrite(req_packet)) {
continue;
}
if (!XuImuRead(&res_packet)) {
continue;
}
2018-04-12 15:21:40 +03:00
if (res_packet.packets.size() == 0) {
continue;
}
VLOG(2) << "Imu req sn: " << imu_sn_
<< ", res count: " << [&res_packet]() {
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";
continue;
}
imu_sn_ = sn;
2018-04-10 15:20:42 +03:00
if (imu_callback_) {
2018-04-12 15:21:40 +03:00
for (auto &&packet : res_packet.packets) {
imu_callback_(packet);
}
2018-04-10 15:20:42 +03:00
}
2018-04-12 15:21:40 +03:00
res_packet.packets.clear();
2018-04-10 15:20:42 +03: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 11:08:47 +03: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 <>
std::string _from_data(const std::uint8_t *data) {
return std::string(reinterpret_cast<const char *>(data));
}
template <>
double _from_data(const std::uint8_t *data) {
return *(reinterpret_cast<const double *>(data));
}
// std::string _from_data(const std::uint8_t *data, std::size_t n) {
// return std::string(reinterpret_cast<const char *>(data), n);
// }
std::size_t from_data(Channels::device_info_t *info, const std::uint8_t *data) {
std::size_t i = 0;
// name, 16
info->name = _from_data<std::string>(data + i);
i += 16;
// serial_number, 16
info->serial_number = _from_data<std::string>(data + i);
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;
return i;
}
std::size_t from_data(
Channels::img_params_t *img_params, const std::uint8_t *data) {
std::size_t i = 0;
auto &&in = img_params->in;
// width, 2
in.width = _from_data<std::uint16_t>(data + i);
i += 2;
// height, 2
in.height = _from_data<std::uint16_t>(data + i);
i += 2;
// fx, 8
in.fx = _from_data<double>(data + i);
i += 8;
// fy, 8
in.fy = _from_data<double>(data + i);
i += 8;
// cx, 8
in.cx = _from_data<double>(data + i);
i += 8;
// cy, 8
in.cy = _from_data<double>(data + i);
i += 8;
// model, 1
in.model = data[i];
i += 1;
// coeffs, 40
for (std::size_t j = 0; j < 5; j++) {
in.coeffs[j] = _from_data<double>(data + i + j * 8);
}
i += 40;
auto &&ex = img_params->ex.left_to_right;
// rotation
for (std::size_t j = 0; j < 3; j++) {
for (std::size_t k = 0; k < 3; k++) {
ex.rotation[j][k] = _from_data<double>(data + i + j * 3 + k);
}
}
i += 72;
// translation
for (std::size_t j = 0; j < 3; j++) {
ex.translation[j] = _from_data<double>(data + i + j * 8);
}
i += 24;
return i;
}
std::size_t from_data(
Channels::imu_params_t *imu_params, const std::uint8_t *data) {
std::size_t i = 0;
auto &&in = imu_params->in;
// acc_scale
for (std::size_t j = 0; j < 3; j++) {
for (std::size_t k = 0; k < 3; k++) {
in.accel.scale[j][k] = _from_data<double>(data + i + j * 3 + k);
}
}
i += 72;
// gyro_scale
for (std::size_t j = 0; j < 3; j++) {
for (std::size_t k = 0; k < 3; k++) {
in.gyro.scale[j][k] = _from_data<double>(data + i + j * 3 + k);
}
}
i += 72;
// acc_drift
for (std::size_t j = 0; j < 3; j++) {
in.accel.drift[j] = _from_data<double>(data + i + j * 8);
}
i += 24;
// gyro_drift
for (std::size_t j = 0; j < 3; j++) {
in.gyro.drift[j] = _from_data<double>(data + i + j * 8);
}
i += 24;
// acc_noise
for (std::size_t j = 0; j < 3; j++) {
in.accel.noise[j] = _from_data<double>(data + i + j * 8);
}
i += 24;
// gyro_noise
for (std::size_t j = 0; j < 3; j++) {
in.gyro.noise[j] = _from_data<double>(data + i + j * 8);
}
i += 24;
// acc_bias
for (std::size_t j = 0; j < 3; j++) {
in.accel.bias[j] = _from_data<double>(data + i + j * 8);
}
i += 24;
// gyro_bias
for (std::size_t j = 0; j < 3; j++) {
in.gyro.bias[j] = _from_data<double>(data + i + j * 8);
}
i += 24;
auto &&ex = imu_params->ex.left_to_imu;
// rotation
for (std::size_t j = 0; j < 3; j++) {
for (std::size_t k = 0; k < 3; k++) {
ex.rotation[j][k] = _from_data<double>(data + i + j * 3 + k);
}
}
i += 72;
// translation
for (std::size_t j = 0; j < 3; j++) {
ex.translation[j] = _from_data<double>(data + i + j * 8);
}
i += 24;
return i;
}
} // namespace
bool Channels::GetFiles(
device_info_t *info, img_params_t *img_params,
imu_params_t *imu_params) const {
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 16:24:07 +03:00
header[7] = 0; // get
2018-04-13 11:08:47 +03:00
2018-04-13 16:24:07 +03:00
header[0] = (info != nullptr);
header[1] = (img_params != nullptr);
header[2] = (imu_params != nullptr);
2018-04-13 11:08:47 +03:00
data[0] = static_cast<std::uint8_t>(header.to_ulong());
2018-04-13 16:24:07 +03:00
// VLOG(2) << "GetFiles header: 0x" << std::hex << std::uppercase
// << std::setw(2) << std::setfill('0') << static_cast<int>(data[0]);
2018-04-13 11:08:47 +03:00
if (!XuFileQuery(uvc::XU_QUERY_SET, 2000, data)) {
LOG(WARNING) << "GetFiles failed";
return false;
}
if (XuFileQuery(uvc::XU_QUERY_GET, 2000, data)) {
VLOG(2) << "GetFiles success";
// header = std::bitset<8>(data[0]);
std::uint16_t size = _from_data<std::uint16_t>(data + 1);
std::uint8_t checksum = data[3 + size];
std::uint8_t checksum_cal = 0;
for (std::size_t i = 4, n = 4 + size; i < n; i++) {
checksum_cal = (checksum_cal ^ data[i]);
}
if (checksum_cal != checksum) {
LOG(WARNING) << "Files checksum should be 0x" << std::hex
<< std::uppercase << std::setw(2) << std::setfill('0')
<< static_cast<int>(checksum_cal) << ", but 0x"
<< std::setw(2) << std::setfill('0')
<< static_cast<int>(checksum) << " now";
return false;
}
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);
i += 3;
switch (file_id) {
case FID_DEVICE_INFO: {
CHECK_EQ(from_data(info, data + i), file_size);
} break;
case FID_IMG_PARAMS: {
CHECK_EQ(from_data(img_params, data + i), file_size);
} break;
case FID_IMU_PARAMS: {
CHECK_EQ(from_data(imu_params, data + i), file_size);
} break;
default:
LOG(FATAL) << "Unsupported file id: " << file_id;
}
i += file_size;
}
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++) {
data[i] =
static_cast<std::uint8_t>((value >> (8 * (size - i - 1))) && 0xFF);
}
return size;
}
template <>
std::size_t _to_data(double value, std::uint8_t *data) {
std::copy(data, data + 8, reinterpret_cast<std::uint8_t *>(&value));
return 8;
}
template <>
std::size_t _to_data(std::string value, std::uint8_t *data) {
std::copy(value.begin(), value.end(), data);
data[value.size()] = '\0';
return value.size() + 1;
}
std::size_t to_data(const Channels::device_info_t *info, std::uint8_t *data) {
std::size_t i = 3;
// name, 16
_to_data(info->name, data + i);
i += 16;
// serial_number, 16
_to_data(info->serial_number, data + i);
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;
// 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(
const Channels::img_params_t *img_params, std::uint8_t *data) {
std::size_t i = 3;
auto &&in = img_params->in;
// width, 2
_to_data(in.width, data + i);
i += 2;
// height, 2
_to_data(in.height, data + i);
i += 2;
// fx, 8
_to_data(in.fx, data + i);
i += 8;
// fy, 8
_to_data(in.fy, data + i);
i += 8;
// cx, 8
_to_data(in.cx, data + i);
i += 8;
// cy, 8
_to_data(in.cy, data + i);
i += 8;
// model, 1
data[i] = in.model;
i += 1;
// coeffs, 40
for (std::size_t j = 0; j < 5; j++) {
_to_data(in.coeffs[j], data + i + j * 8);
}
i += 40;
auto &&ex = img_params->ex.left_to_right;
// rotation
for (std::size_t j = 0; j < 3; j++) {
for (std::size_t k = 0; k < 3; k++) {
_to_data(ex.rotation[j][k], data + i + j * 3 + k);
}
}
i += 72;
// translation
for (std::size_t j = 0; j < 3; j++) {
_to_data(ex.translation[j], data + i + j * 8);
}
i += 24;
// 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) {
std::size_t i = 3;
auto &&in = imu_params->in;
// acc_scale
for (std::size_t j = 0; j < 3; j++) {
for (std::size_t k = 0; k < 3; k++) {
_to_data(in.accel.scale[j][k], data + i + j * 3 + k);
}
}
i += 72;
// gyro_scale
for (std::size_t j = 0; j < 3; j++) {
for (std::size_t k = 0; k < 3; k++) {
_to_data(in.gyro.scale[j][k], data + i + j * 3 + k);
}
}
i += 72;
// acc_drift
for (std::size_t j = 0; j < 3; j++) {
_to_data(in.accel.drift[j], data + i + j * 8);
}
i += 24;
// gyro_drift
for (std::size_t j = 0; j < 3; j++) {
_to_data(in.gyro.drift[j], data + i + j * 8);
}
i += 24;
// acc_noise
for (std::size_t j = 0; j < 3; j++) {
_to_data(in.accel.noise[j], data + i + j * 8);
}
i += 24;
// gyro_noise
for (std::size_t j = 0; j < 3; j++) {
_to_data(in.gyro.noise[j], data + i + j * 8);
}
i += 24;
// acc_bias
for (std::size_t j = 0; j < 3; j++) {
_to_data(in.accel.bias[j], data + i + j * 8);
}
i += 24;
// gyro_bias
for (std::size_t j = 0; j < 3; j++) {
_to_data(in.gyro.bias[j], data + i + j * 8);
}
i += 24;
auto &&ex = imu_params->ex.left_to_imu;
// rotation
for (std::size_t j = 0; j < 3; j++) {
for (std::size_t k = 0; k < 3; k++) {
_to_data(ex.rotation[j][k], data + i + j * 3 + k);
}
}
i += 72;
// translation
for (std::size_t j = 0; j < 3; j++) {
_to_data(ex.translation[j], data + i + j * 8);
}
i += 24;
// 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(
device_info_t *info, img_params_t *img_params, imu_params_t *imu_params) {
if (info == nullptr && img_params == nullptr && imu_params == nullptr) {
LOG(WARNING) << "Files are not provided to set";
return false;
}
std::uint8_t data[2000]{};
std::bitset<8> header;
2018-04-13 16:24:07 +03:00
header[7] = 1; // set
2018-04-13 11:08:47 +03:00
std::uint16_t size = 0;
if (info != nullptr) {
2018-04-13 16:24:07 +03:00
header[0] = true;
2018-04-13 11:08:47 +03:00
size += to_data(info, data + 3 + size);
}
if (img_params != nullptr) {
2018-04-13 16:24:07 +03:00
header[1] = true;
2018-04-13 11:08:47 +03:00
size += to_data(img_params, data + 3 + size);
}
if (imu_params != nullptr) {
2018-04-13 16:24:07 +03:00
header[2] = true;
2018-04-13 11:08:47 +03:00
size += to_data(imu_params, data + 3 + size);
}
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);
if (XuFileQuery(uvc::XU_QUERY_SET, 2000, data)) {
VLOG(2) << "SetFiles success";
return true;
} else {
LOG(WARNING) << "SetFiles failed";
return false;
}
}
2018-04-09 19:26:22 +03: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-04-09 17:24:34 +03:00
bool Channels::XuControlQuery(
2018-04-10 11:00:38 +03:00
channel_t channel, uvc::xu_query query, uint16_t size,
uint8_t *data) const {
return XuControlQuery({3}, channel >> 8, query, size, data);
2018-04-09 17:24:34 +03:00
}
bool Channels::XuControlQuery(
const uvc::xu &xu, uint8_t selector, uvc::xu_query query, uint16_t size,
2018-04-09 19:26:22 +03:00
uint8_t *data) const {
2018-04-09 10:54:14 +03:00
CHECK_NOTNULL(device_);
2018-04-09 17:24:34 +03:00
return uvc::xu_control_query(*device_, xu, selector, query, size, data);
2018-04-09 10:54:14 +03:00
}
2018-04-09 19:26:22 +03:00
bool Channels::XuCamCtrlQuery(
uvc::xu_query query, uint16_t size, uint8_t *data) const {
2018-04-10 11:00:38 +03:00
return XuControlQuery(CHANNEL_CAM_CTRL, query, size, data);
2018-04-09 19:26:22 +03: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 11:00:38 +03:00
LOG(WARNING) << "XuCamCtrlGet value of " << option << " failed";
2018-04-09 19:26:22 +03:00
return -1;
}
data[0] = id & 0xFF;
if (XuCamCtrlQuery(uvc::XU_QUERY_GET, 3, data)) {
2018-04-13 05:20:02 +03:00
return (data[1] << 8) | (data[2]);
2018-04-09 19:26:22 +03:00
} else {
2018-04-10 11:00:38 +03:00
LOG(WARNING) << "XuCamCtrlGet value of " << option << " failed";
2018-04-09 19:26:22 +03:00
return -1;
}
}
2018-04-10 08:58:37 +03: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 12:48:27 +03:00
if (XuCamCtrlQuery(uvc::XU_QUERY_SET, 3, data)) {
2018-04-10 11:00:38 +03:00
VLOG(2) << "XuCamCtrlSet value (" << value << ") of " << option
<< " success";
2018-04-10 12:48:27 +03:00
} else {
LOG(WARNING) << "XuCamCtrlSet value (" << value << ") of " << option
<< " failed";
2018-04-10 11:00:38 +03:00
}
}
bool Channels::XuHalfDuplexSet(Option option, xu_cmd_t cmd) const {
int id = XuHalfDuplexId(option);
2018-04-12 15:50:40 +03: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 12:48:27 +03:00
VLOG(2) << "XuHalfDuplexSet value (0x" << std::hex << std::uppercase << cmd
<< ") of " << option << " success";
return true;
} else {
2018-04-10 11:00:38 +03:00
LOG(WARNING) << "XuHalfDuplexSet value (0x" << std::hex << std::uppercase
<< cmd << ") of " << option << " failed";
return false;
2018-04-10 12:48:27 +03: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 11:00:38 +03:00
} else {
2018-04-10 12:48:27 +03: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 15:20:42 +03: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]);
}
if (checksum != res->checksum) {
LOG(WARNING) << "Imu response packet checksum should be 0x" << std::hex
<< std::uppercase << std::setw(2) << std::setfill('0')
2018-04-10 15:32:31 +03:00
<< static_cast<int>(checksum) << ", but 0x" << std::setw(2)
<< std::setfill('0') << static_cast<int>(res->checksum)
<< " now";
2018-04-10 15:20:42 +03:00
return false;
}
VLOG(2) << "XuImuRead response success";
2018-04-10 11:00:38 +03:00
return true;
2018-04-10 12:48:27 +03:00
} else {
LOG(WARNING) << "XuImuRead response failed";
return false;
2018-04-10 08:58:37 +03:00
}
}
2018-04-13 11:08:47 +03:00
bool Channels::XuFileQuery(
uvc::xu_query query, uint16_t size, uint8_t *data) const {
return XuControlQuery(CHANNEL_FILE, query, size, data);
}
2018-04-09 19:26:22 +03: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 11:00:38 +03:00
LOG(WARNING) << "Get PuControlInfo of " << option << " failed";
2018-04-09 19:26:22 +03:00
}
return {min, max, def};
}
Channels::control_info_t Channels::XuControlInfo(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 11:00:38 +03:00
LOG(WARNING) << "Get XuControlInfo of " << option << " failed";
2018-04-09 19:26:22 +03:00
return {0, 0, 0};
}
control_info_t info{0, 0, 0};
data[0] = id & 0xFF;
if (XuCamCtrlQuery(uvc::XU_QUERY_MIN, 3, data)) {
2018-04-13 05:20:02 +03:00
info.min = (data[1] << 8) | (data[2]);
2018-04-09 19:26:22 +03:00
} else {
2018-04-10 11:00:38 +03:00
LOG(WARNING) << "Get XuControlInfo.min of " << option << " failed";
2018-04-09 19:26:22 +03:00
}
if (XuCamCtrlQuery(uvc::XU_QUERY_MAX, 3, data)) {
2018-04-13 05:20:02 +03:00
info.max = (data[1] << 8) | (data[2]);
2018-04-09 19:26:22 +03:00
} else {
2018-04-10 11:00:38 +03:00
LOG(WARNING) << "Get XuControlInfo.max of " << option << " failed";
2018-04-09 19:26:22 +03:00
}
if (XuCamCtrlQuery(uvc::XU_QUERY_DEF, 3, data)) {
2018-04-13 05:20:02 +03:00
info.def = (data[1] << 8) | (data[2]);
2018-04-09 19:26:22 +03:00
} else {
2018-04-10 11:00:38 +03:00
LOG(WARNING) << "Get XuControlInfo.def of " << option << " failed";
2018-04-09 19:26:22 +03:00
}
return info;
}
2018-04-09 10:54:14 +03:00
MYNTEYE_END_NAMESPACE