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