1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt>
4141cc406Sopenharmony_ci
5141cc406Sopenharmony_ci   This file is part of the SANE package.
6141cc406Sopenharmony_ci
7141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
8141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
9141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
10141cc406Sopenharmony_ci   License, or (at your option) any later version.
11141cc406Sopenharmony_ci
12141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
13141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
14141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15141cc406Sopenharmony_ci   General Public License for more details.
16141cc406Sopenharmony_ci
17141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
18141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
19141cc406Sopenharmony_ci*/
20141cc406Sopenharmony_ci
21141cc406Sopenharmony_ci#define DEBUG_DECLARE_ONLY
22141cc406Sopenharmony_ci
23141cc406Sopenharmony_ci#include "device.h"
24141cc406Sopenharmony_ci#include "command_set.h"
25141cc406Sopenharmony_ci#include "low.h"
26141cc406Sopenharmony_ci#include "utilities.h"
27141cc406Sopenharmony_ci
28141cc406Sopenharmony_cinamespace genesys {
29141cc406Sopenharmony_ci
30141cc406Sopenharmony_cistd::vector<unsigned> MethodResolutions::get_resolutions() const
31141cc406Sopenharmony_ci{
32141cc406Sopenharmony_ci    std::vector<unsigned> ret;
33141cc406Sopenharmony_ci    std::copy(resolutions_x.begin(), resolutions_x.end(), std::back_inserter(ret));
34141cc406Sopenharmony_ci    std::copy(resolutions_y.begin(), resolutions_y.end(), std::back_inserter(ret));
35141cc406Sopenharmony_ci    // sort in decreasing order
36141cc406Sopenharmony_ci
37141cc406Sopenharmony_ci    std::sort(ret.begin(), ret.end(), std::greater<unsigned>());
38141cc406Sopenharmony_ci    ret.erase(std::unique(ret.begin(), ret.end()), ret.end());
39141cc406Sopenharmony_ci    return ret;
40141cc406Sopenharmony_ci}
41141cc406Sopenharmony_ci
42141cc406Sopenharmony_ciconst MethodResolutions* Genesys_Model::get_resolution_settings_ptr(ScanMethod method) const
43141cc406Sopenharmony_ci{
44141cc406Sopenharmony_ci    for (const auto& res_for_method : resolutions) {
45141cc406Sopenharmony_ci        for (auto res_method : res_for_method.methods) {
46141cc406Sopenharmony_ci            if (res_method == method) {
47141cc406Sopenharmony_ci                return &res_for_method;
48141cc406Sopenharmony_ci            }
49141cc406Sopenharmony_ci        }
50141cc406Sopenharmony_ci    }
51141cc406Sopenharmony_ci    return nullptr;
52141cc406Sopenharmony_ci
53141cc406Sopenharmony_ci}
54141cc406Sopenharmony_ciconst MethodResolutions& Genesys_Model::get_resolution_settings(ScanMethod method) const
55141cc406Sopenharmony_ci{
56141cc406Sopenharmony_ci    const auto* ptr = get_resolution_settings_ptr(method);
57141cc406Sopenharmony_ci    if (ptr)
58141cc406Sopenharmony_ci        return *ptr;
59141cc406Sopenharmony_ci
60141cc406Sopenharmony_ci    throw SaneException("Could not find resolution settings for method %d",
61141cc406Sopenharmony_ci                        static_cast<unsigned>(method));
62141cc406Sopenharmony_ci}
63141cc406Sopenharmony_ci
64141cc406Sopenharmony_cistd::vector<unsigned> Genesys_Model::get_resolutions(ScanMethod method) const
65141cc406Sopenharmony_ci{
66141cc406Sopenharmony_ci    return get_resolution_settings(method).get_resolutions();
67141cc406Sopenharmony_ci}
68141cc406Sopenharmony_ci
69141cc406Sopenharmony_cibool Genesys_Model::has_method(ScanMethod method) const
70141cc406Sopenharmony_ci{
71141cc406Sopenharmony_ci    return get_resolution_settings_ptr(method) != nullptr;
72141cc406Sopenharmony_ci}
73141cc406Sopenharmony_ci
74141cc406Sopenharmony_ci
75141cc406Sopenharmony_ciGenesys_Device::~Genesys_Device()
76141cc406Sopenharmony_ci{
77141cc406Sopenharmony_ci    clear();
78141cc406Sopenharmony_ci}
79141cc406Sopenharmony_ci
80141cc406Sopenharmony_civoid Genesys_Device::clear()
81141cc406Sopenharmony_ci{
82141cc406Sopenharmony_ci    calib_file.clear();
83141cc406Sopenharmony_ci
84141cc406Sopenharmony_ci    calibration_cache.clear();
85141cc406Sopenharmony_ci
86141cc406Sopenharmony_ci    white_average_data.clear();
87141cc406Sopenharmony_ci    dark_average_data.clear();
88141cc406Sopenharmony_ci}
89141cc406Sopenharmony_ci
90141cc406Sopenharmony_ciImagePipelineNodeBufferedCallableSource& Genesys_Device::get_pipeline_source()
91141cc406Sopenharmony_ci{
92141cc406Sopenharmony_ci    return static_cast<ImagePipelineNodeBufferedCallableSource&>(pipeline.front());
93141cc406Sopenharmony_ci}
94141cc406Sopenharmony_ci
95141cc406Sopenharmony_cibool Genesys_Device::is_head_pos_known(ScanHeadId scan_head) const
96141cc406Sopenharmony_ci{
97141cc406Sopenharmony_ci    switch (scan_head) {
98141cc406Sopenharmony_ci        case ScanHeadId::PRIMARY: return is_head_pos_primary_known_;
99141cc406Sopenharmony_ci        case ScanHeadId::SECONDARY: return is_head_pos_secondary_known_;
100141cc406Sopenharmony_ci        case ScanHeadId::ALL: return is_head_pos_primary_known_ && is_head_pos_secondary_known_;
101141cc406Sopenharmony_ci        default:
102141cc406Sopenharmony_ci            throw SaneException("Unknown scan head ID");
103141cc406Sopenharmony_ci    }
104141cc406Sopenharmony_ci}
105141cc406Sopenharmony_ciunsigned Genesys_Device::head_pos(ScanHeadId scan_head) const
106141cc406Sopenharmony_ci{
107141cc406Sopenharmony_ci    switch (scan_head) {
108141cc406Sopenharmony_ci        case ScanHeadId::PRIMARY: return head_pos_primary_;
109141cc406Sopenharmony_ci        case ScanHeadId::SECONDARY: return head_pos_secondary_;
110141cc406Sopenharmony_ci        default:
111141cc406Sopenharmony_ci            throw SaneException("Unknown scan head ID");
112141cc406Sopenharmony_ci    }
113141cc406Sopenharmony_ci}
114141cc406Sopenharmony_ci
115141cc406Sopenharmony_civoid Genesys_Device::set_head_pos_unknown(ScanHeadId scan_head)
116141cc406Sopenharmony_ci{
117141cc406Sopenharmony_ci    if ((scan_head & ScanHeadId::PRIMARY) != ScanHeadId::NONE) {
118141cc406Sopenharmony_ci        is_head_pos_primary_known_ = false;
119141cc406Sopenharmony_ci    }
120141cc406Sopenharmony_ci    if ((scan_head & ScanHeadId::SECONDARY) != ScanHeadId::NONE) {
121141cc406Sopenharmony_ci        is_head_pos_secondary_known_ = false;
122141cc406Sopenharmony_ci    }
123141cc406Sopenharmony_ci}
124141cc406Sopenharmony_ci
125141cc406Sopenharmony_civoid Genesys_Device::set_head_pos_zero(ScanHeadId scan_head)
126141cc406Sopenharmony_ci{
127141cc406Sopenharmony_ci    if ((scan_head & ScanHeadId::PRIMARY) != ScanHeadId::NONE) {
128141cc406Sopenharmony_ci        head_pos_primary_ = 0;
129141cc406Sopenharmony_ci        is_head_pos_primary_known_ = true;
130141cc406Sopenharmony_ci    }
131141cc406Sopenharmony_ci    if ((scan_head & ScanHeadId::SECONDARY) != ScanHeadId::NONE) {
132141cc406Sopenharmony_ci        head_pos_secondary_ = 0;
133141cc406Sopenharmony_ci        is_head_pos_secondary_known_ = true;
134141cc406Sopenharmony_ci    }
135141cc406Sopenharmony_ci}
136141cc406Sopenharmony_ci
137141cc406Sopenharmony_civoid Genesys_Device::advance_head_pos_by_session(ScanHeadId scan_head)
138141cc406Sopenharmony_ci{
139141cc406Sopenharmony_ci    int motor_steps = session.params.starty +
140141cc406Sopenharmony_ci                      (session.params.lines * motor.base_ydpi) / session.params.yres;
141141cc406Sopenharmony_ci    auto direction = has_flag(session.params.flags, ScanFlag::REVERSE) ? Direction::BACKWARD
142141cc406Sopenharmony_ci                                                                       : Direction::FORWARD;
143141cc406Sopenharmony_ci    advance_head_pos_by_steps(scan_head, direction, motor_steps);
144141cc406Sopenharmony_ci}
145141cc406Sopenharmony_ci
146141cc406Sopenharmony_cistatic void advance_pos(unsigned& pos, Direction direction, unsigned offset)
147141cc406Sopenharmony_ci{
148141cc406Sopenharmony_ci    if (direction == Direction::FORWARD) {
149141cc406Sopenharmony_ci        pos += offset;
150141cc406Sopenharmony_ci    } else {
151141cc406Sopenharmony_ci        if (pos < offset) {
152141cc406Sopenharmony_ci            throw SaneException("Trying to advance head behind the home sensor");
153141cc406Sopenharmony_ci        }
154141cc406Sopenharmony_ci        pos -= offset;
155141cc406Sopenharmony_ci    }
156141cc406Sopenharmony_ci}
157141cc406Sopenharmony_ci
158141cc406Sopenharmony_civoid Genesys_Device::advance_head_pos_by_steps(ScanHeadId scan_head, Direction direction,
159141cc406Sopenharmony_ci                                               unsigned steps)
160141cc406Sopenharmony_ci{
161141cc406Sopenharmony_ci    if ((scan_head & ScanHeadId::PRIMARY) != ScanHeadId::NONE) {
162141cc406Sopenharmony_ci        if (!is_head_pos_primary_known_) {
163141cc406Sopenharmony_ci            throw SaneException("Trying to advance head while scanhead position is not known");
164141cc406Sopenharmony_ci        }
165141cc406Sopenharmony_ci        advance_pos(head_pos_primary_, direction, steps);
166141cc406Sopenharmony_ci    }
167141cc406Sopenharmony_ci    if ((scan_head & ScanHeadId::SECONDARY) != ScanHeadId::NONE) {
168141cc406Sopenharmony_ci        if (!is_head_pos_secondary_known_) {
169141cc406Sopenharmony_ci            throw SaneException("Trying to advance head while scanhead position is not known");
170141cc406Sopenharmony_ci        }
171141cc406Sopenharmony_ci        advance_pos(head_pos_secondary_, direction, steps);
172141cc406Sopenharmony_ci    }
173141cc406Sopenharmony_ci}
174141cc406Sopenharmony_ci
175141cc406Sopenharmony_civoid print_scan_position(std::ostream& out, const Genesys_Device& dev, ScanHeadId scan_head)
176141cc406Sopenharmony_ci{
177141cc406Sopenharmony_ci    if (dev.is_head_pos_known(scan_head)) {
178141cc406Sopenharmony_ci        out << dev.head_pos(scan_head);
179141cc406Sopenharmony_ci    } else {
180141cc406Sopenharmony_ci        out <<"(unknown)";
181141cc406Sopenharmony_ci    }
182141cc406Sopenharmony_ci}
183141cc406Sopenharmony_ci
184141cc406Sopenharmony_cistd::ostream& operator<<(std::ostream& out, const Genesys_Device& dev)
185141cc406Sopenharmony_ci{
186141cc406Sopenharmony_ci    StreamStateSaver state_saver{out};
187141cc406Sopenharmony_ci
188141cc406Sopenharmony_ci    out << "Genesys_Device{\n"
189141cc406Sopenharmony_ci        << std::hex
190141cc406Sopenharmony_ci        << "    vendorId: 0x" << dev.vendorId << '\n'
191141cc406Sopenharmony_ci        << "    productId: 0x" << dev.productId << '\n'
192141cc406Sopenharmony_ci        << std::dec
193141cc406Sopenharmony_ci        << "    usb_mode: " << dev.usb_mode << '\n'
194141cc406Sopenharmony_ci        << "    file_name: " << dev.file_name << '\n'
195141cc406Sopenharmony_ci        << "    calib_file: " << dev.calib_file << '\n'
196141cc406Sopenharmony_ci        << "    force_calibration: " << dev.force_calibration << '\n'
197141cc406Sopenharmony_ci        << "    ignore_offsets: " << dev.ignore_offsets << '\n'
198141cc406Sopenharmony_ci        << "    model: (not printed)\n"
199141cc406Sopenharmony_ci        << "    reg: " << format_indent_braced_list(4, dev.reg) << '\n'
200141cc406Sopenharmony_ci        << "    initial_regs: " << format_indent_braced_list(4, dev.initial_regs) << '\n'
201141cc406Sopenharmony_ci        << "    settings: " << format_indent_braced_list(4, dev.settings) << '\n'
202141cc406Sopenharmony_ci        << "    frontend: " << format_indent_braced_list(4, dev.frontend) << '\n'
203141cc406Sopenharmony_ci        << "    frontend_initial: " << format_indent_braced_list(4, dev.frontend_initial) << '\n';
204141cc406Sopenharmony_ci    if (!dev.memory_layout.regs.empty()) {
205141cc406Sopenharmony_ci        out << "    memory_layout.regs: "
206141cc406Sopenharmony_ci            << format_indent_braced_list(4, dev.memory_layout.regs) << '\n';
207141cc406Sopenharmony_ci    }
208141cc406Sopenharmony_ci    out << "    gpo.regs: " << format_indent_braced_list(4, dev.gpo.regs) << '\n'
209141cc406Sopenharmony_ci        << "    motor: " << format_indent_braced_list(4, dev.motor) << '\n'
210141cc406Sopenharmony_ci        << "    control[0..6]: " << std::hex
211141cc406Sopenharmony_ci        << static_cast<unsigned>(dev.control[0]) << ' '
212141cc406Sopenharmony_ci        << static_cast<unsigned>(dev.control[1]) << ' '
213141cc406Sopenharmony_ci        << static_cast<unsigned>(dev.control[2]) << ' '
214141cc406Sopenharmony_ci        << static_cast<unsigned>(dev.control[3]) << ' '
215141cc406Sopenharmony_ci        << static_cast<unsigned>(dev.control[4]) << ' '
216141cc406Sopenharmony_ci        << static_cast<unsigned>(dev.control[5]) << '\n' << std::dec
217141cc406Sopenharmony_ci        << "    average_size: " << dev.average_size << '\n'
218141cc406Sopenharmony_ci        << "    calib_session: " << format_indent_braced_list(4, dev.calib_session) << '\n'
219141cc406Sopenharmony_ci        << "    gamma_override_tables[0].size(): " << dev.gamma_override_tables[0].size() << '\n'
220141cc406Sopenharmony_ci        << "    gamma_override_tables[1].size(): " << dev.gamma_override_tables[1].size() << '\n'
221141cc406Sopenharmony_ci        << "    gamma_override_tables[2].size(): " << dev.gamma_override_tables[2].size() << '\n'
222141cc406Sopenharmony_ci        << "    white_average_data.size(): " << dev.white_average_data.size() << '\n'
223141cc406Sopenharmony_ci        << "    dark_average_data.size(): " << dev.dark_average_data.size() << '\n'
224141cc406Sopenharmony_ci        << "    already_initialized: " << dev.already_initialized << '\n'
225141cc406Sopenharmony_ci        << "    scanhead_position[PRIMARY]: ";
226141cc406Sopenharmony_ci    print_scan_position(out, dev, ScanHeadId::PRIMARY);
227141cc406Sopenharmony_ci    out << '\n'
228141cc406Sopenharmony_ci        << "    scanhead_position[SECONDARY]: ";
229141cc406Sopenharmony_ci    print_scan_position(out, dev, ScanHeadId::SECONDARY);
230141cc406Sopenharmony_ci    out << '\n'
231141cc406Sopenharmony_ci        << "    read_active: " << dev.read_active << '\n'
232141cc406Sopenharmony_ci        << "    parking: " << dev.parking << '\n'
233141cc406Sopenharmony_ci        << "    document: " << dev.document << '\n'
234141cc406Sopenharmony_ci        << "    total_bytes_read: " << dev.total_bytes_read << '\n'
235141cc406Sopenharmony_ci        << "    total_bytes_to_read: " << dev.total_bytes_to_read << '\n'
236141cc406Sopenharmony_ci        << "    session: " << format_indent_braced_list(4, dev.session) << '\n'
237141cc406Sopenharmony_ci        << "    calibration_cache: (not printed)\n"
238141cc406Sopenharmony_ci        << "    line_count: " << dev.line_count << '\n'
239141cc406Sopenharmony_ci        << "    segment_order: "
240141cc406Sopenharmony_ci        << format_indent_braced_list(4, format_vector_unsigned(4, dev.segment_order)) << '\n'
241141cc406Sopenharmony_ci        << '}';
242141cc406Sopenharmony_ci    return out;
243141cc406Sopenharmony_ci}
244141cc406Sopenharmony_ci
245141cc406Sopenharmony_civoid apply_reg_settings_to_device_write_only(Genesys_Device& dev,
246141cc406Sopenharmony_ci                                             const GenesysRegisterSettingSet& regs)
247141cc406Sopenharmony_ci{
248141cc406Sopenharmony_ci    GenesysRegisterSettingSet backup;
249141cc406Sopenharmony_ci    for (const auto& reg : regs) {
250141cc406Sopenharmony_ci        dev.interface->write_register(reg.address, reg.value);
251141cc406Sopenharmony_ci    }
252141cc406Sopenharmony_ci}
253141cc406Sopenharmony_ci
254141cc406Sopenharmony_civoid apply_reg_settings_to_device(Genesys_Device& dev, const GenesysRegisterSettingSet& regs)
255141cc406Sopenharmony_ci{
256141cc406Sopenharmony_ci    apply_reg_settings_to_device_with_backup(dev, regs);
257141cc406Sopenharmony_ci}
258141cc406Sopenharmony_ci
259141cc406Sopenharmony_ciGenesysRegisterSettingSet
260141cc406Sopenharmony_ci    apply_reg_settings_to_device_with_backup(Genesys_Device& dev,
261141cc406Sopenharmony_ci                                             const GenesysRegisterSettingSet& regs)
262141cc406Sopenharmony_ci{
263141cc406Sopenharmony_ci    GenesysRegisterSettingSet backup;
264141cc406Sopenharmony_ci    for (const auto& reg : regs) {
265141cc406Sopenharmony_ci        std::uint8_t old_val = dev.interface->read_register(reg.address);
266141cc406Sopenharmony_ci        std::uint8_t new_val = (old_val & ~reg.mask) | (reg.value & reg.mask);
267141cc406Sopenharmony_ci        dev.interface->write_register(reg.address, new_val);
268141cc406Sopenharmony_ci
269141cc406Sopenharmony_ci        using SettingType = GenesysRegisterSettingSet::SettingType;
270141cc406Sopenharmony_ci        backup.push_back(SettingType{reg.address,
271141cc406Sopenharmony_ci                                     static_cast<std::uint8_t>(old_val & reg.mask),
272141cc406Sopenharmony_ci                                     reg.mask});
273141cc406Sopenharmony_ci    }
274141cc406Sopenharmony_ci    return backup;
275141cc406Sopenharmony_ci}
276141cc406Sopenharmony_ci
277141cc406Sopenharmony_ci} // namespace genesys
278