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#ifndef BACKEND_GENESYS_MOTOR_H 22141cc406Sopenharmony_ci#define BACKEND_GENESYS_MOTOR_H 23141cc406Sopenharmony_ci 24141cc406Sopenharmony_ci#include <algorithm> 25141cc406Sopenharmony_ci#include <cstdint> 26141cc406Sopenharmony_ci#include <vector> 27141cc406Sopenharmony_ci#include "enums.h" 28141cc406Sopenharmony_ci#include "sensor.h" 29141cc406Sopenharmony_ci#include "value_filter.h" 30141cc406Sopenharmony_ci 31141cc406Sopenharmony_cinamespace genesys { 32141cc406Sopenharmony_ci 33141cc406Sopenharmony_ci/* Describes a motor acceleration curve. 34141cc406Sopenharmony_ci 35141cc406Sopenharmony_ci Definitions: 36141cc406Sopenharmony_ci v - speed in steps per pixeltime 37141cc406Sopenharmony_ci w - speed in pixel times per step. w = 1 / v 38141cc406Sopenharmony_ci a - acceleration in steps per pixeltime squared 39141cc406Sopenharmony_ci s - distance travelled in steps 40141cc406Sopenharmony_ci t - time in pixeltime 41141cc406Sopenharmony_ci 42141cc406Sopenharmony_ci The physical mode defines the curve in physical quantities. We assume that the scanner head 43141cc406Sopenharmony_ci accelerates from standstill to the target speed uniformly. Then: 44141cc406Sopenharmony_ci 45141cc406Sopenharmony_ci v(t) = v(0) + a * t (2) 46141cc406Sopenharmony_ci 47141cc406Sopenharmony_ci Where `a` is acceleration, `t` is time. Also we can calculate the travelled distance `s`: 48141cc406Sopenharmony_ci 49141cc406Sopenharmony_ci s(t) = v(0) * t + a * t^2 / 2 (3) 50141cc406Sopenharmony_ci 51141cc406Sopenharmony_ci The actual motor slope is defined as the duration of each motor step. That means we need to 52141cc406Sopenharmony_ci define speed in terms of travelled distance. 53141cc406Sopenharmony_ci 54141cc406Sopenharmony_ci Solving (3) for `t` gives: 55141cc406Sopenharmony_ci 56141cc406Sopenharmony_ci sqrt( v(0)^2 + 2 * a * s ) - v(0) 57141cc406Sopenharmony_ci t(s) = --------------------------------- (4) 58141cc406Sopenharmony_ci a 59141cc406Sopenharmony_ci 60141cc406Sopenharmony_ci Combining (4) and (2) will yield: 61141cc406Sopenharmony_ci 62141cc406Sopenharmony_ci v(s) = sqrt( v(0)^2 + 2 * a * s ) (5) 63141cc406Sopenharmony_ci 64141cc406Sopenharmony_ci The data in the slope struct MotorSlope corresponds to the above in the following way: 65141cc406Sopenharmony_ci 66141cc406Sopenharmony_ci maximum_start_speed is `w(0) = 1/v(0)` 67141cc406Sopenharmony_ci 68141cc406Sopenharmony_ci maximum_speed is defines maximum speed which should not be exceeded 69141cc406Sopenharmony_ci 70141cc406Sopenharmony_ci minimum_steps is not used 71141cc406Sopenharmony_ci 72141cc406Sopenharmony_ci g is `a` 73141cc406Sopenharmony_ci 74141cc406Sopenharmony_ci Given the start and target speeds on a known motor curve, `a` can be computed as follows: 75141cc406Sopenharmony_ci 76141cc406Sopenharmony_ci v(t1)^2 - v(t0)^2 77141cc406Sopenharmony_ci a = ----------------- (6) 78141cc406Sopenharmony_ci 2 * s 79141cc406Sopenharmony_ci 80141cc406Sopenharmony_ci Here `v(t0)` and `v(t1)` are the start and target speeds and `s` is the number of step required 81141cc406Sopenharmony_ci to reach the target speeds. 82141cc406Sopenharmony_ci*/ 83141cc406Sopenharmony_cistruct MotorSlope 84141cc406Sopenharmony_ci{ 85141cc406Sopenharmony_ci // initial speed in pixeltime per step 86141cc406Sopenharmony_ci unsigned initial_speed_w = 0; 87141cc406Sopenharmony_ci 88141cc406Sopenharmony_ci // max speed in pixeltime per step 89141cc406Sopenharmony_ci unsigned max_speed_w = 0; 90141cc406Sopenharmony_ci 91141cc406Sopenharmony_ci // maximum number of steps in the table 92141cc406Sopenharmony_ci unsigned max_step_count; 93141cc406Sopenharmony_ci 94141cc406Sopenharmony_ci // acceleration in steps per pixeltime squared. 95141cc406Sopenharmony_ci float acceleration = 0; 96141cc406Sopenharmony_ci 97141cc406Sopenharmony_ci unsigned get_table_step_shifted(unsigned step, StepType step_type) const; 98141cc406Sopenharmony_ci 99141cc406Sopenharmony_ci static MotorSlope create_from_steps(unsigned initial_w, unsigned max_w, 100141cc406Sopenharmony_ci unsigned steps); 101141cc406Sopenharmony_ci}; 102141cc406Sopenharmony_ci 103141cc406Sopenharmony_cistruct MotorSlopeTable 104141cc406Sopenharmony_ci{ 105141cc406Sopenharmony_ci std::vector<std::uint16_t> table; 106141cc406Sopenharmony_ci 107141cc406Sopenharmony_ci void slice_steps(unsigned count, unsigned step_multiplier); 108141cc406Sopenharmony_ci 109141cc406Sopenharmony_ci // expands the table by the given number of steps 110141cc406Sopenharmony_ci void expand_table(unsigned count, unsigned step_multiplier); 111141cc406Sopenharmony_ci 112141cc406Sopenharmony_ci std::uint64_t pixeltime_sum() const { return pixeltime_sum_; } 113141cc406Sopenharmony_ci 114141cc406Sopenharmony_ci void generate_pixeltime_sum(); 115141cc406Sopenharmony_ciprivate: 116141cc406Sopenharmony_ci std::uint64_t pixeltime_sum_ = 0; 117141cc406Sopenharmony_ci}; 118141cc406Sopenharmony_ci 119141cc406Sopenharmony_ciunsigned get_slope_table_max_size(AsicType asic_type); 120141cc406Sopenharmony_ci 121141cc406Sopenharmony_ciMotorSlopeTable create_slope_table_for_speed(const MotorSlope& slope, unsigned target_speed_w, 122141cc406Sopenharmony_ci StepType step_type, unsigned steps_alignment, 123141cc406Sopenharmony_ci unsigned min_size, unsigned max_size); 124141cc406Sopenharmony_ci 125141cc406Sopenharmony_cistd::ostream& operator<<(std::ostream& out, const MotorSlope& slope); 126141cc406Sopenharmony_ci 127141cc406Sopenharmony_cistruct MotorProfile 128141cc406Sopenharmony_ci{ 129141cc406Sopenharmony_ci MotorProfile() = default; 130141cc406Sopenharmony_ci MotorProfile(const MotorSlope& a_slope, StepType a_step_type, unsigned a_max_exposure) : 131141cc406Sopenharmony_ci slope{a_slope}, step_type{a_step_type}, max_exposure{a_max_exposure} 132141cc406Sopenharmony_ci {} 133141cc406Sopenharmony_ci 134141cc406Sopenharmony_ci MotorSlope slope; 135141cc406Sopenharmony_ci StepType step_type = StepType::FULL; 136141cc406Sopenharmony_ci int motor_vref = -1; 137141cc406Sopenharmony_ci 138141cc406Sopenharmony_ci // the resolutions this profile is good for 139141cc406Sopenharmony_ci ValueFilterAny<unsigned> resolutions = VALUE_FILTER_ANY; 140141cc406Sopenharmony_ci // the scan method this profile is good for. If the list is empty, good for any method. 141141cc406Sopenharmony_ci ValueFilterAny<ScanMethod> scan_methods = VALUE_FILTER_ANY; 142141cc406Sopenharmony_ci 143141cc406Sopenharmony_ci unsigned max_exposure = 0; // 0 - any exposure 144141cc406Sopenharmony_ci}; 145141cc406Sopenharmony_ci 146141cc406Sopenharmony_cistd::ostream& operator<<(std::ostream& out, const MotorProfile& profile); 147141cc406Sopenharmony_ci 148141cc406Sopenharmony_cistruct Genesys_Motor 149141cc406Sopenharmony_ci{ 150141cc406Sopenharmony_ci Genesys_Motor() = default; 151141cc406Sopenharmony_ci 152141cc406Sopenharmony_ci // id of the motor description 153141cc406Sopenharmony_ci MotorId id = MotorId::UNKNOWN; 154141cc406Sopenharmony_ci // motor base steps. Unit: 1/inch 155141cc406Sopenharmony_ci int base_ydpi = 0; 156141cc406Sopenharmony_ci // slopes to derive individual slopes from 157141cc406Sopenharmony_ci std::vector<MotorProfile> profiles; 158141cc406Sopenharmony_ci // slopes to derive individual slopes from for fast moving 159141cc406Sopenharmony_ci std::vector<MotorProfile> fast_profiles; 160141cc406Sopenharmony_ci 161141cc406Sopenharmony_ci MotorSlope& get_slope_with_step_type(StepType step_type) 162141cc406Sopenharmony_ci { 163141cc406Sopenharmony_ci for (auto& p : profiles) { 164141cc406Sopenharmony_ci if (p.step_type == step_type) 165141cc406Sopenharmony_ci return p.slope; 166141cc406Sopenharmony_ci } 167141cc406Sopenharmony_ci throw SaneException("No motor profile with step type"); 168141cc406Sopenharmony_ci } 169141cc406Sopenharmony_ci 170141cc406Sopenharmony_ci const MotorSlope& get_slope_with_step_type(StepType step_type) const 171141cc406Sopenharmony_ci { 172141cc406Sopenharmony_ci for (const auto& p : profiles) { 173141cc406Sopenharmony_ci if (p.step_type == step_type) 174141cc406Sopenharmony_ci return p.slope; 175141cc406Sopenharmony_ci } 176141cc406Sopenharmony_ci throw SaneException("No motor profile with step type"); 177141cc406Sopenharmony_ci } 178141cc406Sopenharmony_ci 179141cc406Sopenharmony_ci StepType max_step_type() const 180141cc406Sopenharmony_ci { 181141cc406Sopenharmony_ci if (profiles.empty()) { 182141cc406Sopenharmony_ci throw std::runtime_error("Profiles table is empty"); 183141cc406Sopenharmony_ci } 184141cc406Sopenharmony_ci StepType step_type = StepType::FULL; 185141cc406Sopenharmony_ci for (const auto& p : profiles) { 186141cc406Sopenharmony_ci step_type = static_cast<StepType>( 187141cc406Sopenharmony_ci std::max(static_cast<unsigned>(step_type), 188141cc406Sopenharmony_ci static_cast<unsigned>(p.step_type))); 189141cc406Sopenharmony_ci } 190141cc406Sopenharmony_ci return step_type; 191141cc406Sopenharmony_ci } 192141cc406Sopenharmony_ci}; 193141cc406Sopenharmony_ci 194141cc406Sopenharmony_cistd::ostream& operator<<(std::ostream& out, const Genesys_Motor& motor); 195141cc406Sopenharmony_ci 196141cc406Sopenharmony_ci} // namespace genesys 197141cc406Sopenharmony_ci 198141cc406Sopenharmony_ci#endif // BACKEND_GENESYS_MOTOR_H 199