1 /* sane - Scanner Access Now Easy.
2 
3    Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt>
4 
5    This file is part of the SANE package.
6 
7    This program is free software; you can redistribute it and/or
8    modify it under the terms of the GNU General Public License as
9    published by the Free Software Foundation; either version 2 of the
10    License, or (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <https://www.gnu.org/licenses/>.
19 */
20 
21 #define DEBUG_DECLARE_ONLY
22 
23 #include "device.h"
24 #include "command_set.h"
25 #include "low.h"
26 #include "utilities.h"
27 
28 namespace genesys {
29 
get_resolutions() const30 std::vector<unsigned> MethodResolutions::get_resolutions() const
31 {
32     std::vector<unsigned> ret;
33     std::copy(resolutions_x.begin(), resolutions_x.end(), std::back_inserter(ret));
34     std::copy(resolutions_y.begin(), resolutions_y.end(), std::back_inserter(ret));
35     // sort in decreasing order
36 
37     std::sort(ret.begin(), ret.end(), std::greater<unsigned>());
38     ret.erase(std::unique(ret.begin(), ret.end()), ret.end());
39     return ret;
40 }
41 
get_resolution_settings_ptr(ScanMethod method) const42 const MethodResolutions* Genesys_Model::get_resolution_settings_ptr(ScanMethod method) const
43 {
44     for (const auto& res_for_method : resolutions) {
45         for (auto res_method : res_for_method.methods) {
46             if (res_method == method) {
47                 return &res_for_method;
48             }
49         }
50     }
51     return nullptr;
52 
53 }
get_resolution_settings(ScanMethod method) const54 const MethodResolutions& Genesys_Model::get_resolution_settings(ScanMethod method) const
55 {
56     const auto* ptr = get_resolution_settings_ptr(method);
57     if (ptr)
58         return *ptr;
59 
60     throw SaneException("Could not find resolution settings for method %d",
61                         static_cast<unsigned>(method));
62 }
63 
get_resolutions(ScanMethod method) const64 std::vector<unsigned> Genesys_Model::get_resolutions(ScanMethod method) const
65 {
66     return get_resolution_settings(method).get_resolutions();
67 }
68 
has_method(ScanMethod method) const69 bool Genesys_Model::has_method(ScanMethod method) const
70 {
71     return get_resolution_settings_ptr(method) != nullptr;
72 }
73 
74 
~Genesys_Device()75 Genesys_Device::~Genesys_Device()
76 {
77     clear();
78 }
79 
clear()80 void Genesys_Device::clear()
81 {
82     calib_file.clear();
83 
84     calibration_cache.clear();
85 
86     white_average_data.clear();
87     dark_average_data.clear();
88 }
89 
get_pipeline_source()90 ImagePipelineNodeBufferedCallableSource& Genesys_Device::get_pipeline_source()
91 {
92     return static_cast<ImagePipelineNodeBufferedCallableSource&>(pipeline.front());
93 }
94 
is_head_pos_known(ScanHeadId scan_head) const95 bool Genesys_Device::is_head_pos_known(ScanHeadId scan_head) const
96 {
97     switch (scan_head) {
98         case ScanHeadId::PRIMARY: return is_head_pos_primary_known_;
99         case ScanHeadId::SECONDARY: return is_head_pos_secondary_known_;
100         case ScanHeadId::ALL: return is_head_pos_primary_known_ && is_head_pos_secondary_known_;
101         default:
102             throw SaneException("Unknown scan head ID");
103     }
104 }
head_pos(ScanHeadId scan_head) const105 unsigned Genesys_Device::head_pos(ScanHeadId scan_head) const
106 {
107     switch (scan_head) {
108         case ScanHeadId::PRIMARY: return head_pos_primary_;
109         case ScanHeadId::SECONDARY: return head_pos_secondary_;
110         default:
111             throw SaneException("Unknown scan head ID");
112     }
113 }
114 
set_head_pos_unknown(ScanHeadId scan_head)115 void Genesys_Device::set_head_pos_unknown(ScanHeadId scan_head)
116 {
117     if ((scan_head & ScanHeadId::PRIMARY) != ScanHeadId::NONE) {
118         is_head_pos_primary_known_ = false;
119     }
120     if ((scan_head & ScanHeadId::SECONDARY) != ScanHeadId::NONE) {
121         is_head_pos_secondary_known_ = false;
122     }
123 }
124 
set_head_pos_zero(ScanHeadId scan_head)125 void Genesys_Device::set_head_pos_zero(ScanHeadId scan_head)
126 {
127     if ((scan_head & ScanHeadId::PRIMARY) != ScanHeadId::NONE) {
128         head_pos_primary_ = 0;
129         is_head_pos_primary_known_ = true;
130     }
131     if ((scan_head & ScanHeadId::SECONDARY) != ScanHeadId::NONE) {
132         head_pos_secondary_ = 0;
133         is_head_pos_secondary_known_ = true;
134     }
135 }
136 
advance_head_pos_by_session(ScanHeadId scan_head)137 void Genesys_Device::advance_head_pos_by_session(ScanHeadId scan_head)
138 {
139     int motor_steps = session.params.starty +
140                       (session.params.lines * motor.base_ydpi) / session.params.yres;
141     auto direction = has_flag(session.params.flags, ScanFlag::REVERSE) ? Direction::BACKWARD
142                                                                        : Direction::FORWARD;
143     advance_head_pos_by_steps(scan_head, direction, motor_steps);
144 }
145 
advance_pos(unsigned& pos, Direction direction, unsigned offset)146 static void advance_pos(unsigned& pos, Direction direction, unsigned offset)
147 {
148     if (direction == Direction::FORWARD) {
149         pos += offset;
150     } else {
151         if (pos < offset) {
152             throw SaneException("Trying to advance head behind the home sensor");
153         }
154         pos -= offset;
155     }
156 }
157 
advance_head_pos_by_steps(ScanHeadId scan_head, Direction direction, unsigned steps)158 void Genesys_Device::advance_head_pos_by_steps(ScanHeadId scan_head, Direction direction,
159                                                unsigned steps)
160 {
161     if ((scan_head & ScanHeadId::PRIMARY) != ScanHeadId::NONE) {
162         if (!is_head_pos_primary_known_) {
163             throw SaneException("Trying to advance head while scanhead position is not known");
164         }
165         advance_pos(head_pos_primary_, direction, steps);
166     }
167     if ((scan_head & ScanHeadId::SECONDARY) != ScanHeadId::NONE) {
168         if (!is_head_pos_secondary_known_) {
169             throw SaneException("Trying to advance head while scanhead position is not known");
170         }
171         advance_pos(head_pos_secondary_, direction, steps);
172     }
173 }
174 
print_scan_position(std::ostream& out, const Genesys_Device& dev, ScanHeadId scan_head)175 void print_scan_position(std::ostream& out, const Genesys_Device& dev, ScanHeadId scan_head)
176 {
177     if (dev.is_head_pos_known(scan_head)) {
178         out << dev.head_pos(scan_head);
179     } else {
180         out <<"(unknown)";
181     }
182 }
183 
operator <<(std::ostream& out, const Genesys_Device& dev)184 std::ostream& operator<<(std::ostream& out, const Genesys_Device& dev)
185 {
186     StreamStateSaver state_saver{out};
187 
188     out << "Genesys_Device{\n"
189         << std::hex
190         << "    vendorId: 0x" << dev.vendorId << '\n'
191         << "    productId: 0x" << dev.productId << '\n'
192         << std::dec
193         << "    usb_mode: " << dev.usb_mode << '\n'
194         << "    file_name: " << dev.file_name << '\n'
195         << "    calib_file: " << dev.calib_file << '\n'
196         << "    force_calibration: " << dev.force_calibration << '\n'
197         << "    ignore_offsets: " << dev.ignore_offsets << '\n'
198         << "    model: (not printed)\n"
199         << "    reg: " << format_indent_braced_list(4, dev.reg) << '\n'
200         << "    initial_regs: " << format_indent_braced_list(4, dev.initial_regs) << '\n'
201         << "    settings: " << format_indent_braced_list(4, dev.settings) << '\n'
202         << "    frontend: " << format_indent_braced_list(4, dev.frontend) << '\n'
203         << "    frontend_initial: " << format_indent_braced_list(4, dev.frontend_initial) << '\n';
204     if (!dev.memory_layout.regs.empty()) {
205         out << "    memory_layout.regs: "
206             << format_indent_braced_list(4, dev.memory_layout.regs) << '\n';
207     }
208     out << "    gpo.regs: " << format_indent_braced_list(4, dev.gpo.regs) << '\n'
209         << "    motor: " << format_indent_braced_list(4, dev.motor) << '\n'
210         << "    control[0..6]: " << std::hex
211         << static_cast<unsigned>(dev.control[0]) << ' '
212         << static_cast<unsigned>(dev.control[1]) << ' '
213         << static_cast<unsigned>(dev.control[2]) << ' '
214         << static_cast<unsigned>(dev.control[3]) << ' '
215         << static_cast<unsigned>(dev.control[4]) << ' '
216         << static_cast<unsigned>(dev.control[5]) << '\n' << std::dec
217         << "    average_size: " << dev.average_size << '\n'
218         << "    calib_session: " << format_indent_braced_list(4, dev.calib_session) << '\n'
219         << "    gamma_override_tables[0].size(): " << dev.gamma_override_tables[0].size() << '\n'
220         << "    gamma_override_tables[1].size(): " << dev.gamma_override_tables[1].size() << '\n'
221         << "    gamma_override_tables[2].size(): " << dev.gamma_override_tables[2].size() << '\n'
222         << "    white_average_data.size(): " << dev.white_average_data.size() << '\n'
223         << "    dark_average_data.size(): " << dev.dark_average_data.size() << '\n'
224         << "    already_initialized: " << dev.already_initialized << '\n'
225         << "    scanhead_position[PRIMARY]: ";
226     print_scan_position(out, dev, ScanHeadId::PRIMARY);
227     out << '\n'
228         << "    scanhead_position[SECONDARY]: ";
229     print_scan_position(out, dev, ScanHeadId::SECONDARY);
230     out << '\n'
231         << "    read_active: " << dev.read_active << '\n'
232         << "    parking: " << dev.parking << '\n'
233         << "    document: " << dev.document << '\n'
234         << "    total_bytes_read: " << dev.total_bytes_read << '\n'
235         << "    total_bytes_to_read: " << dev.total_bytes_to_read << '\n'
236         << "    session: " << format_indent_braced_list(4, dev.session) << '\n'
237         << "    calibration_cache: (not printed)\n"
238         << "    line_count: " << dev.line_count << '\n'
239         << "    segment_order: "
240         << format_indent_braced_list(4, format_vector_unsigned(4, dev.segment_order)) << '\n'
241         << '}';
242     return out;
243 }
244 
apply_reg_settings_to_device_write_only(Genesys_Device& dev, const GenesysRegisterSettingSet& regs)245 void apply_reg_settings_to_device_write_only(Genesys_Device& dev,
246                                              const GenesysRegisterSettingSet& regs)
247 {
248     GenesysRegisterSettingSet backup;
249     for (const auto& reg : regs) {
250         dev.interface->write_register(reg.address, reg.value);
251     }
252 }
253 
apply_reg_settings_to_device(Genesys_Device& dev, const GenesysRegisterSettingSet& regs)254 void apply_reg_settings_to_device(Genesys_Device& dev, const GenesysRegisterSettingSet& regs)
255 {
256     apply_reg_settings_to_device_with_backup(dev, regs);
257 }
258 
259 GenesysRegisterSettingSet
apply_reg_settings_to_device_with_backup(Genesys_Device& dev, const GenesysRegisterSettingSet& regs)260     apply_reg_settings_to_device_with_backup(Genesys_Device& dev,
261                                              const GenesysRegisterSettingSet& regs)
262 {
263     GenesysRegisterSettingSet backup;
264     for (const auto& reg : regs) {
265         std::uint8_t old_val = dev.interface->read_register(reg.address);
266         std::uint8_t new_val = (old_val & ~reg.mask) | (reg.value & reg.mask);
267         dev.interface->write_register(reg.address, new_val);
268 
269         using SettingType = GenesysRegisterSettingSet::SettingType;
270         backup.push_back(SettingType{reg.address,
271                                      static_cast<std::uint8_t>(old_val & reg.mask),
272                                      reg.mask});
273     }
274     return backup;
275 }
276 
277 } // namespace genesys
278