1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
|
/* 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
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#define DEBUG_DECLARE_ONLY
#include "low.h"
#include "motor.h"
#include "utilities.h"
#include <cmath>
#include <numeric>
namespace genesys {
unsigned MotorSlope::get_table_step_shifted(unsigned step, StepType step_type) const
{
// first two steps are always equal to the initial speed
if (step < 2) {
return initial_speed_w >> static_cast<unsigned>(step_type);
}
step--;
float initial_speed_v = 1.0f / initial_speed_w;
float speed_v = std::sqrt(initial_speed_v * initial_speed_v + 2 * acceleration * step);
return static_cast<unsigned>(1.0f / speed_v) >> static_cast<unsigned>(step_type);
}
float compute_acceleration_for_steps(unsigned initial_w, unsigned max_w, unsigned steps)
{
float initial_speed_v = 1.0f / static_cast<float>(initial_w);
float max_speed_v = 1.0f / static_cast<float>(max_w);
return (max_speed_v * max_speed_v - initial_speed_v * initial_speed_v) / (2 * steps);
}
MotorSlope MotorSlope::create_from_steps(unsigned initial_w, unsigned max_w,
unsigned steps)
{
MotorSlope slope;
slope.initial_speed_w = initial_w;
slope.max_speed_w = max_w;
slope.acceleration = compute_acceleration_for_steps(initial_w, max_w, steps);
return slope;
}
void MotorSlopeTable::slice_steps(unsigned count, unsigned step_multiplier)
{
if (count > table.size() || count < step_multiplier) {
throw SaneException("Invalid steps count");
}
count = align_multiple_floor(count, step_multiplier);
table.resize(count);
generate_pixeltime_sum();
}
void MotorSlopeTable::expand_table(unsigned count, unsigned step_multiplier)
{
if (table.empty()) {
throw SaneException("Can't expand empty table");
}
count = align_multiple_ceil(count, step_multiplier);
table.resize(table.size() + count, table.back());
generate_pixeltime_sum();
}
void MotorSlopeTable::generate_pixeltime_sum()
{
pixeltime_sum_ = std::accumulate(table.begin(), table.end(),
std::size_t{0}, std::plus<std::size_t>());
}
unsigned get_slope_table_max_size(AsicType asic_type)
{
switch (asic_type) {
case AsicType::GL646:
case AsicType::GL841:
case AsicType::GL842: return 255;
case AsicType::GL843:
case AsicType::GL845:
case AsicType::GL846:
case AsicType::GL847:
case AsicType::GL124: return 1024;
default:
throw SaneException("Unknown asic type");
}
}
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)
{
DBG_HELPER_ARGS(dbg, "target_speed_w: %d, step_type: %d, steps_alignment: %d, min_size: %d",
target_speed_w, static_cast<unsigned>(step_type), steps_alignment, min_size);
MotorSlopeTable table;
unsigned step_shift = static_cast<unsigned>(step_type);
unsigned target_speed_shifted_w = target_speed_w >> step_shift;
unsigned max_speed_shifted_w = slope.max_speed_w >> step_shift;
if (target_speed_shifted_w < max_speed_shifted_w) {
dbg.vlog(DBG_warn, "failed to reach target speed %d %d", target_speed_w,
slope.max_speed_w);
}
if (target_speed_shifted_w >= std::numeric_limits<std::uint16_t>::max()) {
throw SaneException("Target motor speed is too low");
}
unsigned final_speed = std::max(target_speed_shifted_w, max_speed_shifted_w);
table.table.reserve(max_size);
while (table.table.size() < max_size - 1) {
unsigned current = slope.get_table_step_shifted(table.table.size(), step_type);
if (current <= final_speed) {
break;
}
table.table.push_back(current);
}
// make sure the target speed (or the max speed if target speed is too high) is present in
// the table
table.table.push_back(final_speed);
// fill the table up to the specified size
while (table.table.size() < max_size - 1 &&
(table.table.size() % steps_alignment != 0 || table.table.size() < min_size))
{
table.table.push_back(table.table.back());
}
table.generate_pixeltime_sum();
return table;
}
std::ostream& operator<<(std::ostream& out, const MotorSlope& slope)
{
out << "MotorSlope{\n"
<< " initial_speed_w: " << slope.initial_speed_w << '\n'
<< " max_speed_w: " << slope.max_speed_w << '\n'
<< " a: " << slope.acceleration << '\n'
<< '}';
return out;
}
std::ostream& operator<<(std::ostream& out, const MotorProfile& profile)
{
out << "MotorProfile{\n"
<< " max_exposure: " << profile.max_exposure << '\n'
<< " step_type: " << profile.step_type << '\n'
<< " motor_vref: " << profile.motor_vref << '\n'
<< " resolutions: " << format_indent_braced_list(4, profile.resolutions) << '\n'
<< " scan_methods: " << format_indent_braced_list(4, profile.scan_methods) << '\n'
<< " slope: " << format_indent_braced_list(4, profile.slope) << '\n'
<< '}';
return out;
}
std::ostream& operator<<(std::ostream& out, const Genesys_Motor& motor)
{
out << "Genesys_Motor{\n"
<< " id: " << motor.id << '\n'
<< " base_ydpi: " << motor.base_ydpi << '\n'
<< " profiles: "
<< format_indent_braced_list(4, format_vector_indent_braced(4, "MotorProfile",
motor.profiles)) << '\n'
<< " fast_profiles: "
<< format_indent_braced_list(4, format_vector_indent_braced(4, "MotorProfile",
motor.fast_profiles)) << '\n'
<< '}';
return out;
}
} // namespace genesys
|