sane-project-backends/backend/genesys/device.cpp

278 wiersze
10 KiB
C++

/* sane - Scanner Access Now Easy.
Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt>
This file is part of the SANE package.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#define DEBUG_DECLARE_ONLY
#include "device.h"
#include "command_set.h"
#include "low.h"
#include "utilities.h"
namespace genesys {
std::vector<unsigned> MethodResolutions::get_resolutions() const
{
std::vector<unsigned> ret;
std::copy(resolutions_x.begin(), resolutions_x.end(), std::back_inserter(ret));
std::copy(resolutions_y.begin(), resolutions_y.end(), std::back_inserter(ret));
// sort in decreasing order
std::sort(ret.begin(), ret.end(), std::greater<unsigned>());
ret.erase(std::unique(ret.begin(), ret.end()), ret.end());
return ret;
}
const MethodResolutions* Genesys_Model::get_resolution_settings_ptr(ScanMethod method) const
{
for (const auto& res_for_method : resolutions) {
for (auto res_method : res_for_method.methods) {
if (res_method == method) {
return &res_for_method;
}
}
}
return nullptr;
}
const MethodResolutions& Genesys_Model::get_resolution_settings(ScanMethod method) const
{
const auto* ptr = get_resolution_settings_ptr(method);
if (ptr)
return *ptr;
throw SaneException("Could not find resolution settings for method %d",
static_cast<unsigned>(method));
}
std::vector<unsigned> Genesys_Model::get_resolutions(ScanMethod method) const
{
return get_resolution_settings(method).get_resolutions();
}
bool Genesys_Model::has_method(ScanMethod method) const
{
return get_resolution_settings_ptr(method) != nullptr;
}
Genesys_Device::~Genesys_Device()
{
clear();
}
void Genesys_Device::clear()
{
calib_file.clear();
calibration_cache.clear();
white_average_data.clear();
dark_average_data.clear();
}
ImagePipelineNodeBufferedCallableSource& Genesys_Device::get_pipeline_source()
{
return static_cast<ImagePipelineNodeBufferedCallableSource&>(pipeline.front());
}
bool Genesys_Device::is_head_pos_known(ScanHeadId scan_head) const
{
switch (scan_head) {
case ScanHeadId::PRIMARY: return is_head_pos_primary_known_;
case ScanHeadId::SECONDARY: return is_head_pos_secondary_known_;
case ScanHeadId::ALL: return is_head_pos_primary_known_ && is_head_pos_secondary_known_;
default:
throw SaneException("Unknown scan head ID");
}
}
unsigned Genesys_Device::head_pos(ScanHeadId scan_head) const
{
switch (scan_head) {
case ScanHeadId::PRIMARY: return head_pos_primary_;
case ScanHeadId::SECONDARY: return head_pos_secondary_;
default:
throw SaneException("Unknown scan head ID");
}
}
void Genesys_Device::set_head_pos_unknown(ScanHeadId scan_head)
{
if ((scan_head & ScanHeadId::PRIMARY) != ScanHeadId::NONE) {
is_head_pos_primary_known_ = false;
}
if ((scan_head & ScanHeadId::SECONDARY) != ScanHeadId::NONE) {
is_head_pos_secondary_known_ = false;
}
}
void Genesys_Device::set_head_pos_zero(ScanHeadId scan_head)
{
if ((scan_head & ScanHeadId::PRIMARY) != ScanHeadId::NONE) {
head_pos_primary_ = 0;
is_head_pos_primary_known_ = true;
}
if ((scan_head & ScanHeadId::SECONDARY) != ScanHeadId::NONE) {
head_pos_secondary_ = 0;
is_head_pos_secondary_known_ = true;
}
}
void Genesys_Device::advance_head_pos_by_session(ScanHeadId scan_head)
{
int motor_steps = session.params.starty +
(session.params.lines * motor.base_ydpi) / session.params.yres;
auto direction = has_flag(session.params.flags, ScanFlag::REVERSE) ? Direction::BACKWARD
: Direction::FORWARD;
advance_head_pos_by_steps(scan_head, direction, motor_steps);
}
static void advance_pos(unsigned& pos, Direction direction, unsigned offset)
{
if (direction == Direction::FORWARD) {
pos += offset;
} else {
if (pos < offset) {
throw SaneException("Trying to advance head behind the home sensor");
}
pos -= offset;
}
}
void Genesys_Device::advance_head_pos_by_steps(ScanHeadId scan_head, Direction direction,
unsigned steps)
{
if ((scan_head & ScanHeadId::PRIMARY) != ScanHeadId::NONE) {
if (!is_head_pos_primary_known_) {
throw SaneException("Trying to advance head while scanhead position is not known");
}
advance_pos(head_pos_primary_, direction, steps);
}
if ((scan_head & ScanHeadId::SECONDARY) != ScanHeadId::NONE) {
if (!is_head_pos_secondary_known_) {
throw SaneException("Trying to advance head while scanhead position is not known");
}
advance_pos(head_pos_secondary_, direction, steps);
}
}
void print_scan_position(std::ostream& out, const Genesys_Device& dev, ScanHeadId scan_head)
{
if (dev.is_head_pos_known(scan_head)) {
out << dev.head_pos(scan_head);
} else {
out <<"(unknown)";
}
}
std::ostream& operator<<(std::ostream& out, const Genesys_Device& dev)
{
StreamStateSaver state_saver{out};
out << "Genesys_Device{\n"
<< std::hex
<< " vendorId: 0x" << dev.vendorId << '\n'
<< " productId: 0x" << dev.productId << '\n'
<< std::dec
<< " usb_mode: " << dev.usb_mode << '\n'
<< " file_name: " << dev.file_name << '\n'
<< " calib_file: " << dev.calib_file << '\n'
<< " force_calibration: " << dev.force_calibration << '\n'
<< " ignore_offsets: " << dev.ignore_offsets << '\n'
<< " model: (not printed)\n"
<< " reg: " << format_indent_braced_list(4, dev.reg) << '\n'
<< " initial_regs: " << format_indent_braced_list(4, dev.initial_regs) << '\n'
<< " settings: " << format_indent_braced_list(4, dev.settings) << '\n'
<< " frontend: " << format_indent_braced_list(4, dev.frontend) << '\n'
<< " frontend_initial: " << format_indent_braced_list(4, dev.frontend_initial) << '\n';
if (!dev.memory_layout.regs.empty()) {
out << " memory_layout.regs: "
<< format_indent_braced_list(4, dev.memory_layout.regs) << '\n';
}
out << " gpo.regs: " << format_indent_braced_list(4, dev.gpo.regs) << '\n'
<< " motor: " << format_indent_braced_list(4, dev.motor) << '\n'
<< " control[0..6]: " << std::hex
<< static_cast<unsigned>(dev.control[0]) << ' '
<< static_cast<unsigned>(dev.control[1]) << ' '
<< static_cast<unsigned>(dev.control[2]) << ' '
<< static_cast<unsigned>(dev.control[3]) << ' '
<< static_cast<unsigned>(dev.control[4]) << ' '
<< static_cast<unsigned>(dev.control[5]) << '\n' << std::dec
<< " average_size: " << dev.average_size << '\n'
<< " calib_session: " << format_indent_braced_list(4, dev.calib_session) << '\n'
<< " gamma_override_tables[0].size(): " << dev.gamma_override_tables[0].size() << '\n'
<< " gamma_override_tables[1].size(): " << dev.gamma_override_tables[1].size() << '\n'
<< " gamma_override_tables[2].size(): " << dev.gamma_override_tables[2].size() << '\n'
<< " white_average_data.size(): " << dev.white_average_data.size() << '\n'
<< " dark_average_data.size(): " << dev.dark_average_data.size() << '\n'
<< " already_initialized: " << dev.already_initialized << '\n'
<< " scanhead_position[PRIMARY]: ";
print_scan_position(out, dev, ScanHeadId::PRIMARY);
out << '\n'
<< " scanhead_position[SECONDARY]: ";
print_scan_position(out, dev, ScanHeadId::SECONDARY);
out << '\n'
<< " read_active: " << dev.read_active << '\n'
<< " parking: " << dev.parking << '\n'
<< " document: " << dev.document << '\n'
<< " total_bytes_read: " << dev.total_bytes_read << '\n'
<< " total_bytes_to_read: " << dev.total_bytes_to_read << '\n'
<< " session: " << format_indent_braced_list(4, dev.session) << '\n'
<< " calibration_cache: (not printed)\n"
<< " line_count: " << dev.line_count << '\n'
<< " segment_order: "
<< format_indent_braced_list(4, format_vector_unsigned(4, dev.segment_order)) << '\n'
<< '}';
return out;
}
void apply_reg_settings_to_device_write_only(Genesys_Device& dev,
const GenesysRegisterSettingSet& regs)
{
GenesysRegisterSettingSet backup;
for (const auto& reg : regs) {
dev.interface->write_register(reg.address, reg.value);
}
}
void apply_reg_settings_to_device(Genesys_Device& dev, const GenesysRegisterSettingSet& regs)
{
apply_reg_settings_to_device_with_backup(dev, regs);
}
GenesysRegisterSettingSet
apply_reg_settings_to_device_with_backup(Genesys_Device& dev,
const GenesysRegisterSettingSet& regs)
{
GenesysRegisterSettingSet backup;
for (const auto& reg : regs) {
std::uint8_t old_val = dev.interface->read_register(reg.address);
std::uint8_t new_val = (old_val & ~reg.mask) | (reg.value & reg.mask);
dev.interface->write_register(reg.address, new_val);
using SettingType = GenesysRegisterSettingSet::SettingType;
backup.push_back(SettingType{reg.address,
static_cast<std::uint8_t>(old_val & reg.mask),
reg.mask});
}
return backup;
}
} // namespace genesys