| 
									
										
										
										
											2019-08-02 19:35:16 +00:00
										 |  |  | /* 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 | 
					
						
							| 
									
										
										
										
											2021-02-12 08:41:38 +00:00
										 |  |  |    along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2019-08-02 19:35:16 +00:00
										 |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef BACKEND_GENESYS_MOTOR_H
 | 
					
						
							|  |  |  | #define BACKEND_GENESYS_MOTOR_H
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-31 18:13:13 +00:00
										 |  |  | #include <algorithm>
 | 
					
						
							| 
									
										
										
										
											2019-08-02 19:35:16 +00:00
										 |  |  | #include <cstdint>
 | 
					
						
							|  |  |  | #include <vector>
 | 
					
						
							| 
									
										
										
										
											2019-10-01 05:42:08 +00:00
										 |  |  | #include "enums.h"
 | 
					
						
							| 
									
										
										
										
											2020-01-31 18:13:16 +00:00
										 |  |  | #include "sensor.h"
 | 
					
						
							| 
									
										
										
										
											2020-03-14 21:19:34 +00:00
										 |  |  | #include "value_filter.h"
 | 
					
						
							| 
									
										
										
										
											2019-08-02 19:35:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-02 09:01:28 +00:00
										 |  |  | namespace genesys { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-23 10:38:44 +00:00
										 |  |  | /*  Describes a motor acceleration curve.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Definitions: | 
					
						
							|  |  |  |         v - speed in steps per pixeltime | 
					
						
							|  |  |  |         w - speed in pixel times per step. w = 1 / v | 
					
						
							|  |  |  |         a - acceleration in steps per pixeltime squared | 
					
						
							|  |  |  |         s - distance travelled in steps | 
					
						
							|  |  |  |         t - time in pixeltime | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-28 16:17:08 +00:00
										 |  |  |     The physical mode defines the curve in physical quantities. We assume that the scanner head | 
					
						
							| 
									
										
										
										
											2019-11-23 10:38:44 +00:00
										 |  |  |     accelerates from standstill to the target speed uniformly. Then: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     v(t) = v(0) + a * t                                                                         (2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Where `a` is acceleration, `t` is time. Also we can calculate the travelled distance `s`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s(t) = v(0) * t + a * t^2 / 2                                                               (3) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The actual motor slope is defined as the duration of each motor step. That means we need to | 
					
						
							|  |  |  |     define speed in terms of travelled distance. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Solving (3) for `t` gives: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            sqrt( v(0)^2 + 2 * a * s ) - v(0) | 
					
						
							|  |  |  |     t(s) = ---------------------------------                                                    (4) | 
					
						
							|  |  |  |                           a | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Combining (4) and (2) will yield: | 
					
						
							| 
									
										
										
										
											2019-08-02 19:35:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-23 10:38:44 +00:00
										 |  |  |     v(s) = sqrt( v(0)^2 + 2 * a * s )                                                           (5) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The data in the slope struct MotorSlope corresponds to the above in the following way: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     maximum_start_speed is `w(0) = 1/v(0)` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     maximum_speed is defines maximum speed which should not be exceeded | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     minimum_steps is not used | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     g is `a` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Given the start and target speeds on a known motor curve, `a` can be computed as follows: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         v(t1)^2 - v(t0)^2 | 
					
						
							|  |  |  |     a = -----------------                                                                       (6) | 
					
						
							|  |  |  |                2 * s | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Here `v(t0)` and `v(t1)` are the start and target speeds and `s` is the number of step required | 
					
						
							|  |  |  |     to reach the target speeds. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | struct MotorSlope | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // initial speed in pixeltime per step
 | 
					
						
							|  |  |  |     unsigned initial_speed_w = 0; | 
					
						
							| 
									
										
										
										
											2019-08-04 09:01:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-23 10:38:44 +00:00
										 |  |  |     // max speed in pixeltime per step
 | 
					
						
							|  |  |  |     unsigned max_speed_w = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-14 08:20:09 +00:00
										 |  |  |     // maximum number of steps in the table
 | 
					
						
							|  |  |  |     unsigned max_step_count; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-23 10:38:44 +00:00
										 |  |  |     // acceleration in steps per pixeltime squared.
 | 
					
						
							|  |  |  |     float acceleration = 0; | 
					
						
							| 
									
										
										
										
											2019-11-23 10:38:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     unsigned get_table_step_shifted(unsigned step, StepType step_type) const; | 
					
						
							| 
									
										
										
										
											2019-12-14 08:20:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     static MotorSlope create_from_steps(unsigned initial_w, unsigned max_w, | 
					
						
							|  |  |  |                                         unsigned steps); | 
					
						
							| 
									
										
										
										
											2019-11-23 10:38:46 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct MotorSlopeTable | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     std::vector<std::uint16_t> table; | 
					
						
							| 
									
										
										
										
											2019-12-14 08:20:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-18 00:53:14 +00:00
										 |  |  |     void slice_steps(unsigned count, unsigned step_multiplier); | 
					
						
							| 
									
										
										
										
											2020-05-18 00:53:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // expands the table by the given number of steps
 | 
					
						
							| 
									
										
										
										
											2020-05-18 00:53:14 +00:00
										 |  |  |     void expand_table(unsigned count, unsigned step_multiplier); | 
					
						
							| 
									
										
										
										
											2020-05-18 00:53:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     std::uint64_t pixeltime_sum() const { return pixeltime_sum_; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void generate_pixeltime_sum(); | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     std::uint64_t pixeltime_sum_ = 0; | 
					
						
							| 
									
										
										
										
											2019-11-23 10:38:44 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-14 08:20:09 +00:00
										 |  |  | unsigned get_slope_table_max_size(AsicType asic_type); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-09 07:34:40 +00:00
										 |  |  | MotorSlopeTable create_slope_table_for_speed(const MotorSlope& slope, unsigned target_speed_w, | 
					
						
							|  |  |  |                                              StepType step_type, unsigned steps_alignment, | 
					
						
							|  |  |  |                                              unsigned min_size, unsigned max_size); | 
					
						
							| 
									
										
										
										
											2019-11-23 10:38:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-14 08:20:13 +00:00
										 |  |  | std::ostream& operator<<(std::ostream& out, const MotorSlope& slope); | 
					
						
							| 
									
										
										
										
											2019-10-26 10:42:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-31 18:13:13 +00:00
										 |  |  | struct MotorProfile | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     MotorProfile() = default; | 
					
						
							|  |  |  |     MotorProfile(const MotorSlope& a_slope, StepType a_step_type, unsigned a_max_exposure) : | 
					
						
							|  |  |  |         slope{a_slope}, step_type{a_step_type}, max_exposure{a_max_exposure} | 
					
						
							|  |  |  |     {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     MotorSlope slope; | 
					
						
							|  |  |  |     StepType step_type = StepType::FULL; | 
					
						
							| 
									
										
										
										
											2020-01-31 18:13:15 +00:00
										 |  |  |     int motor_vref = -1; | 
					
						
							| 
									
										
										
										
											2020-01-31 18:13:16 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // the resolutions this profile is good for
 | 
					
						
							| 
									
										
										
										
											2020-03-14 21:19:34 +00:00
										 |  |  |     ValueFilterAny<unsigned> resolutions = VALUE_FILTER_ANY; | 
					
						
							| 
									
										
										
										
											2020-01-31 18:13:16 +00:00
										 |  |  |     // the scan method this profile is good for. If the list is empty, good for any method.
 | 
					
						
							| 
									
										
										
										
											2020-03-14 21:19:35 +00:00
										 |  |  |     ValueFilterAny<ScanMethod> scan_methods = VALUE_FILTER_ANY; | 
					
						
							| 
									
										
										
										
											2020-01-31 18:13:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-31 18:13:13 +00:00
										 |  |  |     unsigned max_exposure = 0; // 0 - any exposure
 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | std::ostream& operator<<(std::ostream& out, const MotorProfile& profile); | 
					
						
							| 
									
										
										
										
											2019-08-02 19:35:16 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | struct Genesys_Motor | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Genesys_Motor() = default; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // id of the motor description
 | 
					
						
							| 
									
										
										
										
											2019-09-30 10:52:03 +00:00
										 |  |  |     MotorId id = MotorId::UNKNOWN; | 
					
						
							| 
									
										
										
										
											2019-08-02 19:35:16 +00:00
										 |  |  |     // motor base steps. Unit: 1/inch
 | 
					
						
							|  |  |  |     int base_ydpi = 0; | 
					
						
							|  |  |  |     // slopes to derive individual slopes from
 | 
					
						
							| 
									
										
										
										
											2020-01-31 18:13:13 +00:00
										 |  |  |     std::vector<MotorProfile> profiles; | 
					
						
							| 
									
										
										
										
											2020-01-31 18:13:18 +00:00
										 |  |  |     // slopes to derive individual slopes from for fast moving
 | 
					
						
							|  |  |  |     std::vector<MotorProfile> fast_profiles; | 
					
						
							| 
									
										
										
										
											2019-11-23 10:38:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-31 18:13:12 +00:00
										 |  |  |     MotorSlope& get_slope_with_step_type(StepType step_type) | 
					
						
							| 
									
										
										
										
											2019-11-23 10:38:42 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-01-31 18:13:13 +00:00
										 |  |  |         for (auto& p : profiles) { | 
					
						
							|  |  |  |             if (p.step_type == step_type) | 
					
						
							|  |  |  |                 return p.slope; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         throw SaneException("No motor profile with step type"); | 
					
						
							| 
									
										
										
										
											2019-11-23 10:38:42 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-31 18:13:12 +00:00
										 |  |  |     const MotorSlope& get_slope_with_step_type(StepType step_type) const | 
					
						
							| 
									
										
										
										
											2019-11-23 10:38:42 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-01-31 18:13:13 +00:00
										 |  |  |         for (const auto& p : profiles) { | 
					
						
							|  |  |  |             if (p.step_type == step_type) | 
					
						
							|  |  |  |                 return p.slope; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         throw SaneException("No motor profile with step type"); | 
					
						
							| 
									
										
										
										
											2019-11-23 10:38:42 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     StepType max_step_type() const | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-01-31 18:13:13 +00:00
										 |  |  |         if (profiles.empty()) { | 
					
						
							|  |  |  |             throw std::runtime_error("Profiles table is empty"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         StepType step_type = StepType::FULL; | 
					
						
							|  |  |  |         for (const auto& p : profiles) { | 
					
						
							|  |  |  |             step_type = static_cast<StepType>( | 
					
						
							|  |  |  |                     std::max(static_cast<unsigned>(step_type), | 
					
						
							|  |  |  |                              static_cast<unsigned>(p.step_type))); | 
					
						
							| 
									
										
										
										
											2019-11-23 10:38:42 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-01-31 18:13:13 +00:00
										 |  |  |         return step_type; | 
					
						
							| 
									
										
										
										
											2019-11-23 10:38:42 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-08-10 12:10:31 +00:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2019-08-02 19:35:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-26 10:42:46 +00:00
										 |  |  | std::ostream& operator<<(std::ostream& out, const Genesys_Motor& motor); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-02 09:01:28 +00:00
										 |  |  | } // namespace genesys
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-02 19:35:16 +00:00
										 |  |  | #endif // BACKEND_GENESYS_MOTOR_H
 |