summaryrefslogtreecommitdiff
path: root/backend/genesys/image_buffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'backend/genesys/image_buffer.cpp')
-rw-r--r--backend/genesys/image_buffer.cpp203
1 files changed, 203 insertions, 0 deletions
diff --git a/backend/genesys/image_buffer.cpp b/backend/genesys/image_buffer.cpp
new file mode 100644
index 0000000..07c6987
--- /dev/null
+++ b/backend/genesys/image_buffer.cpp
@@ -0,0 +1,203 @@
+/* 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
+
+ As a special exception, the authors of SANE give permission for
+ additional uses of the libraries contained in this release of SANE.
+
+ The exception is that, if you link a SANE library with other files
+ to produce an executable, this does not by itself cause the
+ resulting executable to be covered by the GNU General Public
+ License. Your use of that executable is in no way restricted on
+ account of linking the SANE library code into it.
+
+ This exception does not, however, invalidate any other reasons why
+ the executable file might be covered by the GNU General Public
+ License.
+
+ If you submit changes to SANE to the maintainers to be included in
+ a subsequent release, you agree by submitting the changes that
+ those changes may be distributed with this exception intact.
+
+ If you write modifications of your own for SANE, it is your choice
+ whether to permit this exception to apply to your modifications.
+ If you do not wish that, delete this exception notice.
+*/
+
+#define DEBUG_DECLARE_ONLY
+
+#include "image_buffer.h"
+#include "image.h"
+
+namespace genesys {
+
+ImageBuffer::ImageBuffer(std::size_t size, ProducerCallback producer) :
+ producer_{producer},
+ size_{size},
+ buffer_offset_{size}
+{
+ buffer_.resize(size_);
+}
+
+bool ImageBuffer::get_data(std::size_t size, std::uint8_t* out_data)
+{
+ const std::uint8_t* out_data_end = out_data + size;
+
+ auto copy_buffer = [&]()
+ {
+ std::size_t bytes_copy = std::min<std::size_t>(out_data_end - out_data, available());
+ std::memcpy(out_data, buffer_.data() + buffer_offset_, bytes_copy);
+ out_data += bytes_copy;
+ buffer_offset_ += bytes_copy;
+ };
+
+ // first, read remaining data from buffer
+ if (available() > 0) {
+ copy_buffer();
+ }
+
+ if (out_data == out_data_end) {
+ return true;
+ }
+
+ // now the buffer is empty and there's more data to be read
+ bool got_data = true;
+ do {
+ buffer_offset_ = 0;
+ got_data &= producer_(size_, buffer_.data());
+
+ copy_buffer();
+ } while(out_data < out_data_end && got_data);
+
+ return got_data;
+}
+
+void FakeBufferModel::push_step(std::size_t buffer_size, std::size_t row_bytes)
+{
+ sizes_.push_back(buffer_size);
+ available_sizes_.push_back(0);
+ row_bytes_.push_back(row_bytes);
+}
+
+std::size_t FakeBufferModel::available_space() const
+{
+ if (sizes_.empty())
+ throw SaneException("Model has not been setup");
+ return sizes_.front() - available_sizes_.front();
+}
+
+void FakeBufferModel::simulate_read(std::size_t size)
+{
+ if (sizes_.empty()) {
+ throw SaneException("Model has not been setup");
+ }
+ if (available_space() < size) {
+ throw SaneException("Attempted to simulate read of too much memory");
+ }
+
+ available_sizes_.front() += size;
+
+ for (unsigned i = 1; i < sizes_.size(); ++i) {
+ auto avail_src = available_sizes_[i - 1];
+ auto avail_dst = sizes_[i] - available_sizes_[i];
+
+ auto avail = (std::min(avail_src, avail_dst) / row_bytes_[i]) * row_bytes_[i];
+ available_sizes_[i - 1] -= avail;
+ available_sizes_[i] += avail;
+ }
+ available_sizes_.back() = 0;
+}
+
+ImageBufferGenesysUsb::ImageBufferGenesysUsb(std::size_t total_size,
+ const FakeBufferModel& buffer_model,
+ ProducerCallback producer) :
+ remaining_size_{total_size},
+ buffer_model_{buffer_model},
+ producer_{producer}
+{}
+
+bool ImageBufferGenesysUsb::get_data(std::size_t size, std::uint8_t* out_data)
+{
+ const std::uint8_t* out_data_end = out_data + size;
+
+ auto copy_buffer = [&]()
+ {
+ std::size_t bytes_copy = std::min<std::size_t>(out_data_end - out_data, available());
+ std::memcpy(out_data, buffer_.data() + buffer_offset_, bytes_copy);
+ out_data += bytes_copy;
+ buffer_offset_ += bytes_copy;
+ };
+
+ // first, read remaining data from buffer
+ if (available() > 0) {
+ copy_buffer();
+ }
+
+ if (out_data == out_data_end) {
+ return true;
+ }
+
+ // now the buffer is empty and there's more data to be read
+ do {
+ if (remaining_size_ == 0)
+ return false;
+
+ auto bytes_to_read = get_read_size();
+ buffer_offset_ = 0;
+ buffer_end_ = bytes_to_read;
+ buffer_.resize(bytes_to_read);
+
+ producer_(bytes_to_read, buffer_.data());
+
+ if (remaining_size_ < bytes_to_read) {
+ remaining_size_ = 0;
+ } else {
+ remaining_size_ -= bytes_to_read;
+ }
+
+ copy_buffer();
+ } while(out_data < out_data_end);
+ return true;
+}
+
+std::size_t ImageBufferGenesysUsb::get_read_size()
+{
+ std::size_t size = buffer_model_.available_space();
+
+ // never read an odd number. exception: last read
+ // the chip internal counter does not count half words.
+ size &= ~1;
+
+ // Some setups need the reads to be multiples of 256 bytes
+ size &= ~0xff;
+
+ if (remaining_size_ < size) {
+ size = remaining_size_;
+ /*round up to a multiple of 256 bytes */
+ size += (size & 0xff) ? 0x100 : 0x00;
+ size &= ~0xff;
+ }
+
+ buffer_model_.simulate_read(size);
+
+ return size;
+}
+
+} // namespace genesys