brother_mfp: Added basic test framework and moved source into brother_mfp directory

brother_mfp_backend
Ralph Little 2022-09-24 11:38:34 -07:00
rodzic 8280db1eef
commit 6eb9e1cc43
15 zmienionych plików z 421 dodań i 54 usunięć

Wyświetl plik

@ -382,12 +382,13 @@ libsane_bh_la_LIBADD = $(COMMON_LIBS) libbh.la \
EXTRA_DIST += bh.conf.in
libbrother_mfp_la_SOURCES = brother_mfp-driver.cpp \
brother_mfp-driver.h \
brother_mfp-common.h \
brother_mfp-encoder.cpp \
brother_mfp-encoder.h \
brother_mfp.cpp
libbrother_mfp_la_SOURCES = \
brother_mfp/brother_mfp-driver.cpp \
brother_mfp/brother_mfp-driver.h \
brother_mfp/brother_mfp-common.h \
brother_mfp/brother_mfp-encoder.cpp \
brother_mfp/brother_mfp-encoder.h \
brother_mfp/brother_mfp.cpp
libbrother_mfp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=brother_mfp
nodist_libsane_brother_mfp_la_SOURCES = brother_mfp-s.cpp
@ -399,7 +400,7 @@ libsane_brother_mfp_la_LIBADD = $(COMMON_LIBS) libbrother_mfp.la \
../sanei/sanei_usb.lo \
../sanei/sanei_config.lo \
sane_strstatus.lo \
$(USB_LIBS)
$(USB_LIBS) $(JPEG_LIBS)
EXTRA_DIST += brother_mfp.conf.in

Wyświetl plik

@ -1,11 +0,0 @@
# Options for the canon_lide70 backend
# Autodetect the Canon CanoScan LiDE 70
usb 0x04a9 0x2225
# Autodetect the Canon CanoScan LiDE 600
usb 0x04a9 0x2224
# device list for non-linux-systems (enable if autodetect fails):
#/dev/scanner
#/dev/usb/scanner0

Wyświetl plik

@ -1,7 +1,10 @@
# Options for the brother_mfp backend
# Options for the canon_lide70 backend
# Brother MFC-J4320DW
usb 0x04f9 0x033a
# Autodetect the Canon CanoScan LiDE 70
usb 0x04a9 0x2225
# Autodetect the Canon CanoScan LiDE 600
usb 0x04a9 0x2224
# device list for non-linux-systems (enable if autodetect fails):
#/dev/scanner

Wyświetl plik

@ -883,7 +883,7 @@ SANE_Status BrotherUSBDriver::StartScan ()
* Reset the encoder/decoder.
*
*/
encoder->Reset();
encoder->NewPage();
return SANE_STATUS_GOOD;
}

Wyświetl plik

@ -389,8 +389,10 @@ SANE_Status BrotherEncoderFamily4::DecodeScanData (const SANE_Byte *src_data, si
break;
}
DBG (DBG_IMPORTANT, "BrotherEncoderFamily4::DecodeScanData: decoded new block header: 0x%2.2x\n",
current_header.block_type);
DBG (DBG_IMPORTANT,
"BrotherEncoderFamily4::DecodeScanData: decoded new block header: 0x%2.2x, length=%zu\n",
current_header.block_type,
current_header.block_len);
src_data += header_consumed;
src_data_len -= header_consumed;
@ -413,7 +415,7 @@ SANE_Status BrotherEncoderFamily4::DecodeScanData (const SANE_Byte *src_data, si
{
if (new_block)
{
jfif_decoder.Reset ();
jfif_decoder.NewBlock ();
}
res = jfif_decoder.DecodeScanData (src_data,
@ -427,7 +429,7 @@ SANE_Status BrotherEncoderFamily4::DecodeScanData (const SANE_Byte *src_data, si
{
if (new_block)
{
gray_decoder.Reset ();
gray_decoder.NewBlock ();
}
res = gray_decoder.DecodeScanData (src_data,
@ -441,7 +443,7 @@ SANE_Status BrotherEncoderFamily4::DecodeScanData (const SANE_Byte *src_data, si
{
if (new_block)
{
gray_raw_decoder.Reset ();
gray_raw_decoder.NewBlock ();
}
res = gray_raw_decoder.DecodeScanData (src_data,
@ -464,6 +466,10 @@ SANE_Status BrotherEncoderFamily4::DecodeScanData (const SANE_Byte *src_data, si
src_data_len -= bytes_consumed;
current_header.block_len -= bytes_consumed;
DBG (DBG_IMPORTANT,
"BrotherEncoderFamily4::DecodeScanData: bytes remaining after decode=%zu\n",
current_header.block_len);
dest_data += bytes_written;
dest_data_len -= bytes_written;
@ -563,13 +569,18 @@ DecodeStatus BrotherEncoderFamily4::DecodeScanDataHeader (const SANE_Byte *src_d
return DECODE_STATUS_GOOD;
}
void BrotherGrayRLengthDecoder::Reset ()
void BrotherGrayRLengthDecoder::NewBlock ()
{
decode_state = BROTHER_DECODE_RLEN_INIT;
decode_expand_char = 0;
block_bytes_left = 0;
}
void BrotherGrayRLengthDecoder::NewPage ()
{
NewBlock();
}
/*
* Returns:
*
@ -695,28 +706,226 @@ DecodeStatus BrotherGrayRLengthDecoder::DecodeScanData (const SANE_Byte *in_buff
return DECODE_STATUS_GOOD;
}
void BrotherJFIFDecoder::Reset ()
#include <jpeglib.h>
#include <jerror.h>
void BrotherJFIFDecoder::NewBlock()
{
// Nothing to do.
}
void BrotherJFIFDecoder::NewPage ()
{
/*
* Aborting a non-running state should be OK.
*
*/
jpeg_abort_decompress(&state.cinfo);
state.have_read_header = false;
}
void BrotherJFIFDecoder::InitSource (j_decompress_ptr cinfo)
{
DBG (DBG_EVENT, "BrotherJFIFDecoder::InitSource.\n");
(void)cinfo;
/*
* We will have already setup all the available data.
*
*/
return;
}
boolean BrotherJFIFDecoder::FillInputBuffer(j_decompress_ptr cinfo)
{
(void)cinfo;
/*
* We can not supply more data.
* We setup the data buffer already with everything we have.
*
*/
DBG (DBG_EVENT, "BrotherJFIFDecoder::FillInputBuffer.\n");
return FALSE;
}
void BrotherJFIFDecoder::SkipInputData(j_decompress_ptr cinfo, long num_bytes)
{
(void)cinfo;
(void)num_bytes;
/*
* TODO: Note the special attention required here.
* num_bytes might exceed the number of bytes in the src_data so we must remember
* the excess so that we can discard it when we add more data later!!!!!!!
*
*/
DBG (DBG_EVENT, "BrotherJFIFDecoder::SkipInputData.\n");
}
void BrotherJFIFDecoder::TermSource(j_decompress_ptr cinfo)
{
(void)cinfo;
DBG (DBG_EVENT, "BrotherJFIFDecoder::TermSource.\n");
}
jmp_buf BrotherJFIFDecoder::my_env;
DecodeStatus BrotherJFIFDecoder::DecodeScanData (const SANE_Byte *src_data, size_t src_data_len,
size_t *src_data_consumed, SANE_Byte *dest_data,
size_t dest_data_len, size_t *dest_data_written)
{
(void)src_data;
(void)src_data_len;
(void)src_data_consumed;
(void)dest_data;
(void)dest_data_len;
(void)dest_data_written;
DBG (DBG_EVENT, "BrotherJFIFDecoder::DecodeScanData\n");
// TODO: finish me.
return DECODE_STATUS_ERROR;
*src_data_consumed = 0;
*dest_data_written = 0;
/*
* Initialise read buffer.
*
*/
state.src_mgr.bytes_in_buffer = src_data_len;
state.src_mgr.next_input_byte = src_data;
if (setjmp(my_env) != 0)
{
DBG (DBG_EVENT, "BrotherJFIFDecoder::DecodeScanData: setjmp error return\n");
return DECODE_STATUS_ERROR;
}
/*
* Read header if we haven't yet.
*
*/
if (!state.have_read_header)
{
DBG (DBG_EVENT, "BrotherJFIFDecoder::DecodeScanData: Trying to read header.\n");
int read_status = jpeg_read_header(&state.cinfo, TRUE);
if (read_status == JPEG_SUSPENDED)
{
return DECODE_STATUS_GOOD;
}
else if (read_status != JPEG_HEADER_OK)
{
return DECODE_STATUS_ERROR;
}
state.have_read_header = true;
DBG (DBG_EVENT, "BrotherJFIFDecoder::DecodeScanData: Starting decompress.\n");
if (!jpeg_start_decompress(&state.cinfo))
{
/*
* Need more data.
*
*/
return DECODE_STATUS_GOOD;
}
/*
* Make sure that we will be getting the data that we expect.
* This is for colour only, so we expect 3 components.
*
*/
if (state.cinfo.out_color_components != 3)
{
return DECODE_STATUS_ERROR;
}
/*
* TODO: Perhaps also check the dimensions are what we are expecting.
* Depending on the issues related to width alignment, we might
* have to do some trimming on the scan lines if we had to round up the
* the width and/or round down the left margin.
*
*/
}
/*
* Let's try to decompress some JPEG!
*
*/
DBG (DBG_EVENT, "BrotherJFIFDecoder::DecodeScanData: Converting data.\n");
SANE_Byte *output_ptr = dest_data;
const size_t line_size = sizeof(JSAMPLE) * state.cinfo.output_width * state.cinfo.out_color_components;
size_t output_size = dest_data_len;
while (output_size >= line_size)
{
/*
* Estimate the number of lines we can generate from
* the available output space.
*
*/
// JDIMENSION max_lines = dest_data_len / (state.cinfo.output_width * 3);
JDIMENSION converted = jpeg_read_scanlines (&state.cinfo, &output_ptr, 1);
DBG (DBG_IMPORTANT,
"BrotherJFIFDecoder::DecodeScanData: Convert %u scanlines. Remaining scanlines: %u\n",
(unsigned int) converted, (unsigned int)(state.cinfo.output_height - state.cinfo.output_scanline));
output_size -= line_size;
output_ptr += converted * line_size;
if (converted == 0)
{
break;
}
}
/*
* Account for what we have processed.
*
* Note that libjpeg will have altered state.src_mgr.bytes_in_buffer
* to a backtracked position for it to restart again.
* This is why it is CRUCIAL that we do not try to guess.
*
*/
*dest_data_written = output_ptr - dest_data;
*src_data_consumed = src_data_len - state.src_mgr.bytes_in_buffer;
DBG (DBG_IMPORTANT,
"BrotherJFIFDecoder::DecodeScanData: Finished: consumed %zu bytes, written %zu bytes\n",
*src_data_consumed,
*dest_data_written);
/*
* If we have output all the scanlines, then we need to finish up.
*
*/
if (state.cinfo.output_scanline >= state.cinfo.output_height)
{
DBG (DBG_EVENT, "BrotherJFIFDecoder::DecodeScanData: Converted all scanlines. Finishing.\n");
if (!jpeg_finish_decompress(&state.cinfo))
{
return DECODE_STATUS_ERROR;
}
}
return DECODE_STATUS_GOOD;
}
void BrotherGrayRawDecoder::Reset ()
void BrotherGrayRawDecoder::NewPage ()
{
// Nothing to do.
}
void BrotherGrayRawDecoder::NewBlock()
{
// Nothing to do.
}

Wyświetl plik

@ -33,6 +33,9 @@
#include <fcntl.h>
#include <sys/ioctl.h>
#include <jpeglib.h>
#include <jerror.h>
#include "brother_mfp-common.h"
#include "../include/sane/sane.h"
@ -141,7 +144,6 @@ enum DecodeStatus
{
DECODE_STATUS_GOOD,
DECODE_STATUS_TRUNCATED,
DECODE_STATUS_MORE,
DECODE_STATUS_ENDOFDATA,
DECODE_STATUS_ENDOFFRAME,
DECODE_STATUS_ERROR
@ -169,7 +171,7 @@ public:
{
}
virtual void Reset() = 0;
virtual void NewPage() = 0;
SANE_Status SetScanMode (BrotherScanMode scan_mode);
SANE_Status SetRes (SANE_Int x, SANE_Int y);
@ -205,14 +207,79 @@ protected:
BrotherParameters scan_params;
};
#include <setjmp.h>
class BrotherJFIFDecoder
{
public:
void Reset();
BrotherJFIFDecoder():
is_running(false)
{
/*
* Not sure if this is a safe way to get the cinfo into
* a consistent state but at least all pointers will be NULL.
*
*/
(void)memset(&state.cinfo, 0, sizeof(state.cinfo));
// TODO: override error stuff to avoid exit on error.
// Also provide a mechanism to check for errors.
state.cinfo.err = jpeg_std_error(&state.jerr);
state.cinfo.err->error_exit = ErrorExitManager;
jpeg_create_decompress (&state.cinfo);
/*
* Set up source manager.
*
*/
state.src_mgr.init_source = InitSource;
state.src_mgr.fill_input_buffer = FillInputBuffer;
state.src_mgr.skip_input_data = SkipInputData;
state.src_mgr.resync_to_restart = jpeg_resync_to_restart;
state.src_mgr.term_source = TermSource;
state.cinfo.src = &state.src_mgr;
}
static void ErrorExitManager(j_common_ptr cinfo)
{
(void)cinfo;
longjmp(my_env, 1);
}
~BrotherJFIFDecoder()
{
jpeg_destroy_decompress(&state.cinfo);
}
void NewBlock();
void NewPage();
DecodeStatus DecodeScanData (const SANE_Byte *src_data, size_t src_data_len,
size_t *src_data_consumed, SANE_Byte *dst_data, size_t dest_data_len,
size_t *dest_data_written);
private:
static void InitSource (j_decompress_ptr cinfo);
static boolean FillInputBuffer(j_decompress_ptr cinfo);
static void SkipInputData(j_decompress_ptr cinfo, long num_bytes);
static void TermSource(j_decompress_ptr cinfo);
struct CompressionState
{
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
struct jpeg_source_mgr src_mgr;
bool have_read_header;
} state;
bool is_running;
// TODO: Move me to the state.
static jmp_buf my_env;
};
class BrotherGrayRLengthDecoder
@ -224,7 +291,8 @@ public:
block_bytes_left(0)
{
}
void Reset();
void NewBlock();
void NewPage();
DecodeStatus DecodeScanData (const SANE_Byte *src_data, size_t src_data_len,
size_t *src_data_consumed, SANE_Byte *dst_data, size_t dest_data_len,
@ -251,7 +319,8 @@ public:
BrotherGrayRawDecoder()
{
}
void Reset();
void NewBlock();
void NewPage();
DecodeStatus DecodeScanData (const SANE_Byte *src_data, size_t src_data_len,
size_t *src_data_consumed, SANE_Byte *dst_data, size_t dest_data_len,
@ -267,7 +336,7 @@ public:
{
}
void Reset() override
void NewPage() override
{
current_header.block_type = 0;
}

Wyświetl plik

@ -56,7 +56,7 @@
* TODO: I will remove this shortly anyway. For dev only.
*
*/
//#define BROTHER_ENABLE_SCAN_FILE 1
#define BROTHER_ENABLE_SCAN_FILE 1
/*-----------------------------------------------------------------*/
@ -180,7 +180,9 @@ struct BrotherDevice
SANE_Int x_res;
SANE_Int y_res;
#ifdef BROTHER_ENABLE_SCAN_FILE
FILE *scan_file;
#endif
BrotherDriver *driver;
@ -1060,7 +1062,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
*/
device->params = *params;
DBG (DBG_SERIOUS,
DBG (DBG_IMPORTANT,
"sane_get_parameters: params: format:%d last_frame:%d bytes_per_line:%d "
"pixels_per_line: %d lines:%d depth:%d\n",
params->format,
@ -1070,12 +1072,6 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
params->lines,
params->depth);
// SANE_Frame format;
// SANE_Bool last_frame;
// SANE_Int bytes_per_line;
// SANE_Int pixels_per_line;
// SANE_Int lines;
// SANE_Int depth;
return rc;
}
@ -1131,11 +1127,13 @@ sane_read (SANE_Handle handle, SANE_Byte * data,
*length = 0;
#ifdef BROTHER_ENABLE_SCAN_FILE
if (!device->scan_file)
{
DBG (DBG_SERIOUS, "sane_read: no scan data file.\n");
return SANE_STATUS_EOF;
}
#endif
size_t scan_len = 0;
SANE_Status res = device->driver->ReadScanData(data, (size_t)max_length, &scan_len);
@ -1147,14 +1145,17 @@ sane_read (SANE_Handle handle, SANE_Byte * data,
*/
#ifdef BROTHER_ENABLE_SCAN_FILE
fwrite(data, *length, 1, device->scan_file);
#endif
if (res == SANE_STATUS_EOF)
{
DBG (DBG_EVENT, "sane_read: read receives EOF.\n");
#ifdef BROTHER_ENABLE_SCAN_FILE
fclose(device->scan_file);
device->scan_file = NULL;
}
#endif
}
return res;
}

Wyświetl plik

@ -0,0 +1,8 @@
# Options for the brother_mfp backend
# Brother MFC-J4320DW
usb 0x04f9 0x033a
# device list for non-linux-systems (enable if autodetect fails):
#/dev/scanner
#/dev/usb/scanner0

Wyświetl plik

@ -723,6 +723,9 @@ for backend in ${BACKENDS} ; do
BACKEND_LIBS_ENABLED="${BACKEND_LIBS_ENABLED} libsane-${backend}.la"
BACKEND_CONFS_ENABLED="${BACKEND_CONFS_ENABLED} ${backend}.conf"
BACKEND_MANS_ENABLED="${BACKEND_MANS_ENABLED} sane-${backend}.5"
if test x$backend = xbrother_mfp; then
with_brother_mfp_tests=yes
fi
if test x$backend = xgenesys; then
with_genesys_tests=yes
fi
@ -732,6 +735,7 @@ for backend in ${BACKENDS} ; do
done
AC_SUBST(BACKEND_LIBS_ENABLED)
AM_CONDITIONAL(WITH_GENESYS_TESTS, test xyes = x$with_genesys_tests)
AM_CONDITIONAL(WITH_BROTHER_MFP_TESTS, test xyes = x$with_brother_mfp_tests)
AM_CONDITIONAL(INSTALL_UMAX_PP_TOOLS, test xyes = x$install_umax_pp_tools)
AC_ARG_VAR(PRELOADABLE_BACKENDS, [list of backends to preload into single DLL])
@ -824,6 +828,7 @@ AC_CONFIG_FILES([Makefile lib/Makefile sanei/Makefile frontend/Makefile \
po/Makefile.in testsuite/Makefile \
testsuite/backend/Makefile \
testsuite/backend/genesys/Makefile \
testsuite/backend/brother_mfp/Makefile \
testsuite/sanei/Makefile testsuite/tools/Makefile \
tools/Makefile doc/doxygen-sanei.conf doc/doxygen-genesys.conf])
AC_CONFIG_FILES([tools/sane-config], [chmod a+x tools/sane-config])

Wyświetl plik

@ -5,5 +5,11 @@
## included LICENSE file for license information.
if WITH_GENESYS_TESTS
SUBDIRS = genesys
SUBDIR_GENESYS = genesys
endif
if WITH_BROTHER_MFP_TESTS
SUBDIR_BROTHER_MFP = brother_mfp
endif
SUBDIRS = $(SUBDIR_GENESYS) $(SUBDIR_BROTHER_MFP)

Wyświetl plik

@ -0,0 +1,24 @@
## Makefile.am -- an automake template for Makefile.in file
## Copyright (C) 2022 Ralph Little <skelband@gmail.com>
##
## This file is part of the "Sane" build infra-structure. See
## included LICENSE file for license information.
TEST_LDADD = \
../../../sanei/libsanei.la \
../../../sanei/sanei_usb.lo \
../../../sanei/sanei_magic.lo \
../../../lib/liblib.la \
../../../backend/libbrother_mfp.la \
../../../backend/sane_strstatus.lo \
$(USB_LIBS) $(XML_LIBS) $(PTHREAD_LIBS)
check_PROGRAMS = brother_mfp_unit_tests
TESTS = brother_mfp_unit_tests
AM_CPPFLAGS += -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include $(USB_CFLAGS) \
-DBACKEND_NAME=brother_mfp -DTESTSUITE_BACKEND_BROTHER_MFP_SRCDIR=$(srcdir)
brother_mfp_unit_tests_SOURCES = brother_mfp_tests.cpp brother_mfp_tests.h
brother_mfp_unit_tests_LDADD = $(TEST_LDADD)

Wyświetl plik

@ -0,0 +1,31 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2022 Ralph Little <skelband@gmail.com>
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 <stdio.h>
#include "brother_mfp_tests.h"
int main()
{
printf("Brother MFP tests.\n");
return 0;
}

Wyświetl plik

@ -0,0 +1,21 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2022 Ralph Little <skelband@gmail.com>
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/>.
*/
#pragma once