kopia lustrzana https://gitlab.com/sane-project/backends
Porównaj commity
31 Commity
5445182a37
...
b31b82c8bd
Autor | SHA1 | Data |
---|---|---|
Ralph Little | b31b82c8bd | |
Ralph Little | 0f472aa205 | |
Guillaume Girol | a6d63a72ec | |
Ralph Little | c6b0b1871c | |
Ralph Little | 32be74e1f6 | |
Ralph Little | 45416ffe03 | |
Ralph Little | 311a38c76f | |
Ralph Little | ceb7342877 | |
Ralph Little | cc4ad6be99 | |
Ralph Little | 4173926d3b | |
Ralph Little | b64b8c13bb | |
Ralph Little | ca760d54b3 | |
Ralph Little | a8a9e895b9 | |
Ralph Little | 9bbf24cf97 | |
Ralph Little | 40de9f87b8 | |
Ralph Little | d95166777f | |
Ralph Little | 76481920c3 | |
Ralph Little | a484c6ad93 | |
Ralph Little | a6f4f816b1 | |
Ralph Little | fbe872ae86 | |
Ralph Little | 0055214614 | |
Ralph Little | 437bfd27f3 | |
Ralph Little | 3fae2e561d | |
Ralph Little | 22d8ab2b49 | |
Ralph Little | 6eb9e1cc43 | |
Ralph Little | 8280db1eef | |
Ralph Little | 79a9b6ac44 | |
Ralph Little | 7f763c0763 | |
Ralph Little | 4f060d6cea | |
Ralph Little | a7d6a553ee | |
Ralph Little | a9853d1bb8 |
|
@ -6,7 +6,8 @@
|
|||
# Your editor may need a plugin for this configuration to take effect.
|
||||
# See http://editorconfig.org/#download for details.
|
||||
|
||||
root = true ; look no further
|
||||
; look no further
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
|
|
|
@ -577,6 +577,13 @@ for be in ${BACKENDS}; do
|
|||
fi
|
||||
;;
|
||||
|
||||
brother_mfp)
|
||||
if test "${HAVE_CXX11}" != "1"; then
|
||||
echo "*** $be backend requires C++11 support - $DISABLE_MSG"
|
||||
backend_supported="no"
|
||||
fi
|
||||
;;
|
||||
|
||||
mustek_pp)
|
||||
if test "${sane_cv_use_libieee1284}" != "yes" && test "${enable_parport_directio}" != "yes"; then
|
||||
echo "*** $be backend requires libieee1284 or parport-directio libraries - $DISABLE_MSG"
|
||||
|
|
|
@ -66,7 +66,7 @@ EXTRA_DIST += saned.conf.in
|
|||
# Backends are not required to have a config file. Any backend
|
||||
# that wants to install a config file should list it here.
|
||||
BACKEND_CONFS= abaton.conf agfafocus.conf apple.conf artec.conf \
|
||||
artec_eplus48u.conf avision.conf bh.conf \
|
||||
artec_eplus48u.conf avision.conf bh.conf brother_mfp.conf \
|
||||
canon630u.conf canon.conf canon_dr.conf \
|
||||
canon_lide70.conf \
|
||||
canon_pp.conf cardscan.conf coolscan2.conf coolscan3.conf \
|
||||
|
@ -160,7 +160,7 @@ clean-local:
|
|||
# example of working around that issue.
|
||||
be_convenience_libs = libabaton.la libagfafocus.la \
|
||||
libapple.la libartec.la libartec_eplus48u.la \
|
||||
libas6e.la libavision.la libbh.la \
|
||||
libas6e.la libavision.la libbh.la libbrother_mfp.la \
|
||||
libcanon.la libcanon630u.la libcanon_dr.la \
|
||||
libcanon_lide70.la \
|
||||
libcanon_pp.la libcardscan.la libcoolscan.la \
|
||||
|
@ -194,7 +194,7 @@ be_convenience_libs = libabaton.la libagfafocus.la \
|
|||
# Format is libsane-${backend}.la.
|
||||
be_dlopen_libs = libsane-abaton.la libsane-agfafocus.la \
|
||||
libsane-apple.la libsane-artec.la libsane-artec_eplus48u.la \
|
||||
libsane-as6e.la libsane-avision.la libsane-bh.la \
|
||||
libsane-as6e.la libsane-avision.la libsane-bh.la libsane-brother_mfp.la \
|
||||
libsane-canon.la libsane-canon630u.la libsane-canon_dr.la \
|
||||
libsane-canon_lide70.la \
|
||||
libsane-canon_pp.la libsane-cardscan.la libsane-coolscan.la \
|
||||
|
@ -381,6 +381,34 @@ libsane_bh_la_LIBADD = $(COMMON_LIBS) libbh.la \
|
|||
$(SCSI_LIBS) $(RESMGR_LIBS)
|
||||
EXTRA_DIST += bh.conf.in
|
||||
|
||||
|
||||
libbrother_mfp_la_SOURCES = \
|
||||
brother_mfp/brother_mfp-driver_usb.cpp \
|
||||
brother_mfp/brother_mfp-driver_network.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 $(SNMP_CFLAGS)
|
||||
|
||||
nodist_libsane_brother_mfp_la_SOURCES = brother_mfp-s.cpp
|
||||
libsane_brother_mfp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=brother_mfp
|
||||
libsane_brother_mfp_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
|
||||
libsane_brother_mfp_la_LIBADD = $(COMMON_LIBS) libbrother_mfp.la \
|
||||
../sanei/sanei_init_debug.lo \
|
||||
../sanei/sanei_constrain_value.lo \
|
||||
../sanei/sanei_usb.lo \
|
||||
../sanei/sanei_config.lo \
|
||||
sane_strstatus.lo \
|
||||
$(USB_LIBS) $(JPEG_LIBS) $(SNMP_LIBS)
|
||||
EXTRA_DIST += brother_mfp.conf.in
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
libcanon_la_SOURCES = canon.c canon.h
|
||||
libcanon_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
# 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
|
|
@ -0,0 +1,66 @@
|
|||
/* sane - Scanner Access Now Easy.
|
||||
|
||||
BACKEND brother_mfp
|
||||
|
||||
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/>.
|
||||
|
||||
This file implements a SANE backend for Brother Multifunction Devices.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define BACKEND_NAME brother_mfp
|
||||
#define BROTHER_MFP_CONFIG_FILE "brother_mfp.conf"
|
||||
|
||||
/*
|
||||
* Model capabilities.
|
||||
*
|
||||
* TODO: Some of these capabilities might be redundant if all models possess them.
|
||||
* E.g. MODE_GRAY
|
||||
*
|
||||
*/
|
||||
#define CAP_MODE_COLOUR (1u << 0)
|
||||
#define CAP_MODE_GRAY (1u << 1)
|
||||
#define CAP_MODE_GRAY_DITHER (1u << 2)
|
||||
#define CAP_MODE_BW (1u << 3)
|
||||
|
||||
#define CAP_BUTTON_HAS_SCAN_EMAIL (1u << 4)
|
||||
#define CAP_BUTTON_HAS_SCAN_OCR (1u << 5)
|
||||
#define CAP_BUTTON_HAS_SCAN_FILE (1u << 6)
|
||||
#define CAP_BUTTON_HAS_SCAN_IMAGE (1u << 7)
|
||||
|
||||
#define CAP_SOURCE_HAS_FLATBED (1u << 8)
|
||||
#define CAP_SOURCE_HAS_ADF (1u << 9)
|
||||
#define CAP_SOURCE_HAS_ADF_DUPLEX (1u << 10)
|
||||
|
||||
#define CAP_ENCODING_HAS_RAW (1u << 11)
|
||||
#define CAP_ENCODING_HAS_JPEG (1u << 12)
|
||||
|
||||
// Oddities of particular models.
|
||||
#define CAP_ENCODING_RAW_IS_CrYCb (1u << 13)
|
||||
|
||||
/*
|
||||
* Diagnostic levels.
|
||||
*
|
||||
*/
|
||||
#define DBG_IMPORTANT 1
|
||||
#define DBG_SERIOUS 2
|
||||
#define DBG_WARN 3
|
||||
#define DBG_EVENT 4
|
||||
#define DBG_DETAIL 5
|
||||
#define DBG_DEBUG 6
|
|
@ -0,0 +1,242 @@
|
|||
/* sane - Scanner Access Now Easy.
|
||||
|
||||
BACKEND brother_mfp
|
||||
|
||||
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/>.
|
||||
|
||||
This file implements a SANE backend for Brother Multifunction Devices.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#define BUILD 0
|
||||
|
||||
#include "../include/sane/config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "brother_mfp-common.h"
|
||||
|
||||
#include "../include/sane/sane.h"
|
||||
#include "../include/sane/sanei.h"
|
||||
#include "../include/sane/saneopts.h"
|
||||
#include "../include/sane/sanei_config.h"
|
||||
#include "../include/sane/sanei_usb.h"
|
||||
|
||||
#include "brother_mfp-encoder.h"
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Handy timeout macros for use with usecond_t-based functions.
|
||||
*
|
||||
*/
|
||||
#define TIMEOUT_SECS(x) ((x) * 1000000)
|
||||
#define TIMEOUT_MILLISECS(x) ((x) * 1000)
|
||||
#define TIMEOUT_MICROSECS(x) (x)
|
||||
|
||||
|
||||
/*
|
||||
* Transport base and implementations.
|
||||
*
|
||||
* We have a base which lays the groundwork for our
|
||||
* scanner communications and the interface for the SANE
|
||||
* frontend to talk with the device.
|
||||
*
|
||||
* We have implementations for both USB and Ethernet.
|
||||
*
|
||||
*/
|
||||
class BrotherDriver
|
||||
{
|
||||
public:
|
||||
explicit BrotherDriver (BrotherFamily family, SANE_Word capabilities);
|
||||
|
||||
BrotherDriver(const BrotherDriver &) = delete;
|
||||
BrotherDriver &operator=(const BrotherDriver &) = delete;
|
||||
|
||||
virtual ~BrotherDriver();
|
||||
|
||||
/*
|
||||
* Will include the INIT sequence.
|
||||
*
|
||||
*/
|
||||
virtual SANE_Status Connect () = 0;
|
||||
|
||||
/*
|
||||
* Will ensure that we stop a session if active.
|
||||
*
|
||||
*/
|
||||
virtual SANE_Status Disconnect () = 0;
|
||||
|
||||
/*
|
||||
* Will open a session.
|
||||
*
|
||||
*/
|
||||
virtual SANE_Status StartScan () = 0;
|
||||
|
||||
virtual SANE_Status CancelScan () = 0;
|
||||
|
||||
virtual SANE_Status CheckSensor(BrotherSensor &status) = 0;
|
||||
|
||||
virtual SANE_Status ReadScanData (SANE_Byte *data, size_t data_len,
|
||||
size_t *bytes_read) = 0;
|
||||
|
||||
/*
|
||||
* Parameter setting.
|
||||
*
|
||||
*/
|
||||
SANE_Status SetSource (BrotherSource source)
|
||||
{
|
||||
return encoder->DecodeStatusToSaneStatus (encoder->SetSource (source));
|
||||
}
|
||||
|
||||
SANE_Status SetScanMode (BrotherScanMode scan_mode)
|
||||
{
|
||||
return encoder->DecodeStatusToSaneStatus (encoder->SetScanMode (scan_mode));
|
||||
}
|
||||
|
||||
SANE_Status SetRes (SANE_Int x, SANE_Int y)
|
||||
{
|
||||
return encoder->DecodeStatusToSaneStatus (encoder->SetRes (x, y));
|
||||
}
|
||||
|
||||
SANE_Status SetContrast (SANE_Int contrast)
|
||||
{
|
||||
return encoder->DecodeStatusToSaneStatus (encoder->SetContrast (contrast));
|
||||
}
|
||||
|
||||
SANE_Status SetBrightness (SANE_Int brightness)
|
||||
{
|
||||
return encoder->DecodeStatusToSaneStatus (encoder->SetBrightness (brightness));
|
||||
}
|
||||
|
||||
SANE_Status SetCompression (SANE_Bool compression)
|
||||
{
|
||||
return encoder->DecodeStatusToSaneStatus (encoder->SetCompression (compression));
|
||||
}
|
||||
|
||||
SANE_Status SetScanDimensions (SANE_Int pixel_x_offset, SANE_Int pixel_x_width,
|
||||
SANE_Int pixel_y_offset, SANE_Int pixel_y_height)
|
||||
{
|
||||
return encoder->DecodeStatusToSaneStatus (encoder->SetScanDimensions (pixel_x_offset,
|
||||
pixel_x_width,
|
||||
pixel_y_offset,
|
||||
pixel_y_height));
|
||||
}
|
||||
|
||||
protected:
|
||||
BrotherFamily family;
|
||||
SANE_Word capabilities;
|
||||
BrotherEncoder *encoder;
|
||||
};
|
||||
|
||||
class BrotherUSBDriver : public BrotherDriver
|
||||
{
|
||||
public:
|
||||
BrotherUSBDriver (const char *devicename, BrotherFamily family, SANE_Word capabilities);
|
||||
|
||||
~BrotherUSBDriver ();
|
||||
|
||||
SANE_Status Connect () override;
|
||||
|
||||
SANE_Status Disconnect () override;
|
||||
|
||||
SANE_Status StartScan () override;
|
||||
|
||||
SANE_Status CancelScan () override;
|
||||
|
||||
SANE_Status CheckSensor(BrotherSensor &status) override;
|
||||
|
||||
SANE_Status ReadScanData (SANE_Byte *data, size_t data_len,
|
||||
size_t *bytes_read) override;
|
||||
|
||||
private:
|
||||
SANE_Status StartSession ();
|
||||
SANE_Status StopSession ();
|
||||
SANE_Status ExecStartSession ();
|
||||
SANE_Status ExecStopSession ();
|
||||
SANE_Status Init ();
|
||||
|
||||
SANE_Status PollForReadFlush (useconds_t max_time);
|
||||
SANE_Status PollForRead (SANE_Byte *buffer, size_t *buf_len,
|
||||
useconds_t *max_time);
|
||||
bool is_open;
|
||||
bool in_session;
|
||||
bool is_scanning;
|
||||
bool was_cancelled;
|
||||
char *devicename;
|
||||
SANE_Int next_frame_number;
|
||||
SANE_Int fd;
|
||||
|
||||
SANE_Byte small_buffer[1024];
|
||||
SANE_Byte *data_buffer;
|
||||
size_t data_buffer_bytes;
|
||||
|
||||
bool out_of_docs;
|
||||
|
||||
};
|
||||
|
||||
class BrotherNetworkDriver : public BrotherDriver
|
||||
{
|
||||
public:
|
||||
BrotherNetworkDriver (const char *devicename, BrotherFamily family, SANE_Word capabilities);
|
||||
|
||||
~BrotherNetworkDriver ();
|
||||
|
||||
SANE_Status Connect () override;
|
||||
|
||||
SANE_Status Disconnect () override;
|
||||
|
||||
SANE_Status StartScan () override;
|
||||
|
||||
SANE_Status CancelScan () override;
|
||||
|
||||
SANE_Status CheckSensor(BrotherSensor &status) override;
|
||||
|
||||
SANE_Status ReadScanData (SANE_Byte *data, size_t data_len,
|
||||
size_t *bytes_read) override;
|
||||
|
||||
private:
|
||||
SANE_Status Init ();
|
||||
|
||||
SANE_Status SNMPRegisterButtons ();
|
||||
|
||||
// SANE_Status PollForReadFlush (useconds_t max_time);
|
||||
// SANE_Status PollForRead (SANE_Byte *buffer, size_t *buf_len,
|
||||
// useconds_t *max_time);
|
||||
bool is_open;
|
||||
bool in_session;
|
||||
bool is_scanning;
|
||||
bool was_cancelled;
|
||||
char *devicename;
|
||||
SANE_Int next_frame_number;
|
||||
|
||||
SANE_Byte small_buffer[1024];
|
||||
SANE_Byte *data_buffer;
|
||||
size_t data_buffer_bytes;
|
||||
|
||||
bool out_of_docs;
|
||||
|
||||
int sockfd;
|
||||
|
||||
};
|
|
@ -0,0 +1,309 @@
|
|||
/* sane - Scanner Access Now Easy.
|
||||
|
||||
BACKEND brother_mfp
|
||||
|
||||
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/>.
|
||||
|
||||
This file implements a SANE backend for Brother Multifunction Devices.
|
||||
*/
|
||||
|
||||
#define DEBUG_DECLARE_ONLY
|
||||
|
||||
#include "../include/sane/config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include <netdb.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
|
||||
|
||||
#include "../include/sane/sane.h"
|
||||
#include "../include/sane/sanei.h"
|
||||
#include "../include/sane/saneopts.h"
|
||||
#include "../include/sane/sanei_config.h"
|
||||
#include "../include/sane/sanei_debug.h"
|
||||
|
||||
#include "brother_mfp-common.h"
|
||||
#include "brother_mfp-driver.h"
|
||||
|
||||
#define BROTHER_READ_BUFFER_LEN (16 * 1024)
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
|
||||
union BrotherSocketAddr
|
||||
{
|
||||
struct sockaddr_storage storage;
|
||||
struct sockaddr addr;
|
||||
struct sockaddr_in ipv4;
|
||||
struct sockaddr_in6 ipv6;
|
||||
};
|
||||
|
||||
SANE_Status BrotherNetworkDriver::Connect ()
|
||||
{
|
||||
int val;
|
||||
|
||||
if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
|
||||
{
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
|
||||
val = 1;
|
||||
setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
|
||||
|
||||
/*
|
||||
* Using TCP_NODELAY improves responsiveness, especially on systems
|
||||
* with a slow loopback interface...
|
||||
*/
|
||||
|
||||
val = 1;
|
||||
setsockopt (sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
|
||||
|
||||
/*
|
||||
* Close this socket when starting another process...
|
||||
*/
|
||||
|
||||
fcntl (sockfd, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
BrotherSocketAddr adr_inet;
|
||||
memset (&adr_inet, 0, sizeof adr_inet);
|
||||
|
||||
adr_inet.ipv4.sin_family = AF_INET;
|
||||
adr_inet.ipv4.sin_port = htons (54921);
|
||||
|
||||
if (!inet_aton ("192.168.1.19", &adr_inet.ipv4.sin_addr))
|
||||
{
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
|
||||
if (connect (sockfd, (struct sockaddr*) &adr_inet, sizeof(adr_inet.ipv4)) < 0)
|
||||
{
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
|
||||
SANE_Status init_res = Init ();
|
||||
|
||||
if (init_res != SANE_STATUS_GOOD)
|
||||
{
|
||||
DBG (DBG_SERIOUS, "BrotherUSBDriver::Connect: failed to send init session: %d\n", init_res);
|
||||
Disconnect ();
|
||||
}
|
||||
|
||||
/*
|
||||
* Register buttons.
|
||||
*
|
||||
*/
|
||||
(void)SNMPRegisterButtons();
|
||||
|
||||
return SANE_STATUS_NO_MEM;
|
||||
}
|
||||
|
||||
|
||||
#if HAVE_LIBSNMP
|
||||
#include <net-snmp/net-snmp-config.h>
|
||||
#include <net-snmp/net-snmp-includes.h>
|
||||
#endif
|
||||
|
||||
SANE_Status BrotherNetworkDriver::SNMPRegisterButtons ()
|
||||
{
|
||||
#if HAVE_LIBSNMP
|
||||
init_snmp ("brother_mfp");
|
||||
|
||||
/*
|
||||
* Initialize a "session" that defines who we're going to talk to
|
||||
*/
|
||||
struct snmp_session session;
|
||||
|
||||
snmp_sess_init (&session); /* set up defaults */
|
||||
session.peername = (char*) "192.168.1.19";
|
||||
|
||||
session.version = SNMP_VERSION_1;
|
||||
|
||||
/* set the SNMPv1 community name used for authentication */
|
||||
session.community = (u_char*) "internal";
|
||||
session.community_len = strlen ("internal");
|
||||
|
||||
SOCK_STARTUP;
|
||||
|
||||
/*
|
||||
* Open the session
|
||||
*/
|
||||
struct snmp_session *ss = snmp_open (&session);
|
||||
|
||||
if (!ss)
|
||||
{
|
||||
snmp_perror ("ack");
|
||||
snmp_log (LOG_ERR, "something horrible happened!!!\n");
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
|
||||
netsnmp_pdu *pdu;
|
||||
oid the_oid[MAX_OID_LEN];
|
||||
size_t oid_len;
|
||||
const char *oid_str = ".1.3.6.1.4.1.2435.2.3.9.2.11.1.1.0";
|
||||
|
||||
pdu = snmp_pdu_create (SNMP_MSG_SET);
|
||||
oid_len = MAX_OID_LEN;
|
||||
|
||||
// Parse the OID
|
||||
if (snmp_parse_oid (oid_str, the_oid, &oid_len) == 0)
|
||||
{
|
||||
snmp_perror (oid_str);
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
|
||||
struct ButtonApp
|
||||
{
|
||||
const char *function;
|
||||
unsigned int app_num;
|
||||
} button_apps[] =
|
||||
{
|
||||
{ "IMAGE", 1 },
|
||||
{ "OCR", 3 },
|
||||
{ "FILE", 5 },
|
||||
{ "EMAIL", 2 },
|
||||
{ nullptr, 0 } };
|
||||
|
||||
const char *backend_host_addr = "192.168.1.12";
|
||||
unsigned int backend_host_port = 54925;
|
||||
const char *backend_host_name = "BACKEND_HOST";
|
||||
unsigned int reg_lifetime = 360;
|
||||
|
||||
for (const ButtonApp *app = button_apps; app->function; app++)
|
||||
{
|
||||
(void) snprintf ((char*) small_buffer,
|
||||
sizeof(small_buffer),
|
||||
"TYPE=BR;BUTTON=SCAN;USER=\"%s\";FUNC=%s;HOST=%s:%u;APPNUM=%u;DURATION=%u;",
|
||||
backend_host_name,
|
||||
app->function,
|
||||
backend_host_addr,
|
||||
backend_host_port,
|
||||
app->app_num,
|
||||
reg_lifetime);
|
||||
|
||||
if (snmp_pdu_add_variable (pdu, the_oid, oid_len, ASN_OCTET_STR,
|
||||
(const char*) small_buffer, strlen ((const char*) small_buffer))
|
||||
== nullptr)
|
||||
{
|
||||
snmp_perror ("failed");
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// Send the request
|
||||
if (snmp_send (ss, pdu) == 0)
|
||||
{
|
||||
snmp_perror ("SNMP: Error while sending!");
|
||||
snmp_free_pdu (pdu);
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
|
||||
// TODO: cleanup and shutdown of SNMP stuff!!!!!
|
||||
|
||||
return SANE_STATUS_NO_MEM;
|
||||
#else
|
||||
return SANE_STATUS_GOOD;
|
||||
#endif
|
||||
}
|
||||
|
||||
SANE_Status BrotherNetworkDriver::Disconnect ()
|
||||
{
|
||||
DBG (DBG_EVENT, "BrotherNetworkDriver::Disconnect: `%s'\n", devicename);
|
||||
|
||||
if (sockfd)
|
||||
{
|
||||
close(sockfd);
|
||||
sockfd = 0;
|
||||
}
|
||||
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
SANE_Status BrotherNetworkDriver::Init ()
|
||||
{
|
||||
return SANE_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
SANE_Status BrotherNetworkDriver::CancelScan ()
|
||||
{
|
||||
return SANE_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
SANE_Status BrotherNetworkDriver::StartScan ()
|
||||
{
|
||||
return SANE_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
SANE_Status BrotherNetworkDriver::CheckSensor (BrotherSensor &status)
|
||||
{
|
||||
(void)status;
|
||||
return SANE_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
SANE_Status BrotherNetworkDriver::ReadScanData (SANE_Byte *data, size_t max_length, size_t *length)
|
||||
{
|
||||
(void)data;
|
||||
(void)max_length;
|
||||
(void)length;
|
||||
return SANE_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
BrotherNetworkDriver::BrotherNetworkDriver (const char *devicename, BrotherFamily family,
|
||||
SANE_Word capabilities) :
|
||||
BrotherDriver (family, capabilities),
|
||||
is_open (false),
|
||||
in_session (false),
|
||||
is_scanning (false),
|
||||
was_cancelled (false),
|
||||
devicename (nullptr),
|
||||
next_frame_number (0),
|
||||
small_buffer { 0 },
|
||||
data_buffer (nullptr),
|
||||
data_buffer_bytes (0),
|
||||
out_of_docs (false),
|
||||
sockfd (0)
|
||||
{
|
||||
this->devicename = strdup(devicename);
|
||||
}
|
||||
|
||||
BrotherNetworkDriver::~BrotherNetworkDriver ()
|
||||
{
|
||||
delete[] data_buffer;
|
||||
free (devicename);
|
||||
}
|
Plik diff jest za duży
Load Diff
Plik diff jest za duży
Load Diff
|
@ -0,0 +1,756 @@
|
|||
/* sane - Scanner Access Now Easy.
|
||||
|
||||
BACKEND brother_mfp
|
||||
|
||||
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/>.
|
||||
|
||||
This file implements a SANE backend for Brother Multifunction Devices.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../include/sane/config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <jpeglib.h>
|
||||
#include <jerror.h>
|
||||
|
||||
#include "brother_mfp-common.h"
|
||||
|
||||
#include "../include/sane/sane.h"
|
||||
#include "../include/sane/sanei.h"
|
||||
#include "../include/sane/saneopts.h"
|
||||
#include "../include/sane/sanei_config.h"
|
||||
#include "../include/sane/sanei_usb.h"
|
||||
|
||||
|
||||
/*
|
||||
* Functionality sets.
|
||||
*
|
||||
* For the moment, I am going to assume that the various proprietary
|
||||
* drivers follow the broad protocol versions and I will reflect this
|
||||
* until I see different.
|
||||
*
|
||||
* So these will reflect the brscan2, brscan3, etc that Brother use.
|
||||
*
|
||||
* We will have a encoder/decoder for each family.
|
||||
* From what I have seen, pretty much all the Brother families implement
|
||||
* the same basic protocol sequence, just with variations in technology.
|
||||
* So we don't need to abstract out the entire sequence, just the encoding
|
||||
* and decoding of each packet. The biggest aspect by far is the difference
|
||||
* in scan data formats.
|
||||
*
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
BROTHER_FAMILY_NONE,
|
||||
BROTHER_FAMILY_1,
|
||||
BROTHER_FAMILY_2,
|
||||
BROTHER_FAMILY_3,
|
||||
BROTHER_FAMILY_4,
|
||||
BROTHER_FAMILY_5
|
||||
} BrotherFamily;
|
||||
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BROTHER_SCAN_MODE_COLOR,
|
||||
BROTHER_SCAN_MODE_GRAY,
|
||||
BROTHER_SCAN_MODE_GRAY_DITHERED,
|
||||
BROTHER_SCAN_MODE_TEXT
|
||||
} BrotherScanMode;
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BROTHER_SOURCE_NONE,
|
||||
BROTHER_SOURCE_AUTO,
|
||||
BROTHER_SOURCE_FLATBED,
|
||||
BROTHER_SOURCE_ADF,
|
||||
BROTHER_SOURCE_ADF_DUPLEX,
|
||||
} BrotherSource;
|
||||
|
||||
typedef SANE_Int BrotherSensor;
|
||||
|
||||
#define BROTHER_SENSOR_NONE 0
|
||||
#define BROTHER_SENSOR_EMAIL (1 << 0)
|
||||
#define BROTHER_SENSOR_FILE (1 << 1)
|
||||
#define BROTHER_SENSOR_OCR (1 << 2)
|
||||
#define BROTHER_SENSOR_IMAGE (1 << 3)
|
||||
|
||||
struct BrotherSessionResponse
|
||||
{
|
||||
SANE_Bool ready;
|
||||
};
|
||||
|
||||
struct BrotherButtonQueryResponse
|
||||
{
|
||||
SANE_Bool has_button_press;
|
||||
};
|
||||
|
||||
struct BrotherButtonStateResponse
|
||||
{
|
||||
BrotherSensor button_value; // raw value we get from the packet
|
||||
};
|
||||
|
||||
struct BrotherParameters
|
||||
{
|
||||
BrotherParameters():
|
||||
param_brightness (0),
|
||||
param_contrast (0),
|
||||
param_compression (SANE_TRUE),
|
||||
param_pixel_x_offset (0),
|
||||
param_pixel_x_width (0),
|
||||
param_pixel_y_offset (0),
|
||||
param_pixel_y_height (0),
|
||||
param_scan_mode (BROTHER_SCAN_MODE_COLOR),
|
||||
param_source(BROTHER_SOURCE_FLATBED),
|
||||
param_x_res(100),
|
||||
param_y_res(100)
|
||||
{
|
||||
}
|
||||
SANE_Int param_brightness;
|
||||
SANE_Int param_contrast;
|
||||
SANE_Bool param_compression;
|
||||
|
||||
SANE_Int param_pixel_x_offset;
|
||||
SANE_Int param_pixel_x_width;
|
||||
SANE_Int param_pixel_y_offset;
|
||||
SANE_Int param_pixel_y_height;
|
||||
|
||||
BrotherScanMode param_scan_mode;
|
||||
BrotherSource param_source;
|
||||
|
||||
SANE_Int param_x_res;
|
||||
SANE_Int param_y_res;
|
||||
|
||||
};
|
||||
|
||||
struct BrotherBasicParamResponse
|
||||
{
|
||||
int dummy;
|
||||
// fill me
|
||||
};
|
||||
|
||||
struct BrotherQueryResponse
|
||||
{
|
||||
int dummy;
|
||||
// fill me
|
||||
};
|
||||
|
||||
struct BrotherSourceStatusResponse
|
||||
{
|
||||
SANE_Bool source_ready;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* DecodeStatus
|
||||
*
|
||||
*/
|
||||
enum DecodeStatus
|
||||
{
|
||||
DECODE_STATUS_GOOD,
|
||||
DECODE_STATUS_TRUNCATED,
|
||||
DECODE_STATUS_ENDOFDATA,
|
||||
DECODE_STATUS_ENDOFFRAME_NO_MORE,
|
||||
DECODE_STATUS_ENDOFFRAME_WITH_MORE,
|
||||
DECODE_STATUS_CANCEL,
|
||||
DECODE_STATUS_ERROR,
|
||||
DECODE_STATUS_MEMORY,
|
||||
DECODE_STATUS_INVAL,
|
||||
DECODE_STATUS_UNSUPPORTED,
|
||||
DECODE_STATUS_PAPER_JAM,
|
||||
DECODE_STATUS_COVER_OPEN,
|
||||
DECODE_STATUS_NO_DOCS,
|
||||
};
|
||||
|
||||
struct ScanDataHeader
|
||||
{
|
||||
ScanDataHeader():
|
||||
block_type(0),
|
||||
block_len(0),
|
||||
image_number(0)
|
||||
{
|
||||
}
|
||||
SANE_Byte block_type;
|
||||
size_t block_len;
|
||||
SANE_Int image_number;
|
||||
};
|
||||
|
||||
class BrotherEncoder
|
||||
{
|
||||
public:
|
||||
BrotherEncoder ()
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~BrotherEncoder ()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void NewPage () = 0;
|
||||
|
||||
DecodeStatus SetSource (BrotherSource source);
|
||||
DecodeStatus SetScanMode (BrotherScanMode scan_mode);
|
||||
DecodeStatus SetRes (SANE_Int x, SANE_Int y);
|
||||
DecodeStatus SetContrast (SANE_Int contrast);
|
||||
DecodeStatus SetBrightness (SANE_Int brightness);
|
||||
DecodeStatus SetCompression (SANE_Bool compression);
|
||||
|
||||
DecodeStatus SetScanDimensions (SANE_Int pixel_x_offset, SANE_Int pixel_x_width,
|
||||
SANE_Int pixel_y_offset, SANE_Int pixel_y_height);
|
||||
|
||||
SANE_Status DecodeStatusToSaneStatus(DecodeStatus dec_ret)
|
||||
{
|
||||
static SANE_Status status_lookup[] =
|
||||
{
|
||||
SANE_STATUS_GOOD,
|
||||
SANE_STATUS_GOOD,
|
||||
SANE_STATUS_EOF,
|
||||
SANE_STATUS_EOF,
|
||||
SANE_STATUS_EOF,
|
||||
SANE_STATUS_CANCELLED,
|
||||
SANE_STATUS_IO_ERROR,
|
||||
SANE_STATUS_NO_MEM,
|
||||
SANE_STATUS_INVAL,
|
||||
SANE_STATUS_UNSUPPORTED,
|
||||
SANE_STATUS_JAMMED,
|
||||
SANE_STATUS_COVER_OPEN,
|
||||
SANE_STATUS_NO_DOCS,
|
||||
};
|
||||
|
||||
return status_lookup[dec_ret];
|
||||
}
|
||||
|
||||
const char *DecodeStatusToString(DecodeStatus dec_ret)
|
||||
{
|
||||
static const char * status_lookup[] =
|
||||
{
|
||||
"DECODE_STATUS_GOOD",
|
||||
"DECODE_STATUS_TRUNCATED",
|
||||
"DECODE_STATUS_ENDOFDATA",
|
||||
"DECODE_STATUS_ENDOFFRAME_NO_MORE",
|
||||
"DECODE_STATUS_ENDOFFRAME_WITH_MORE",
|
||||
"DECODE_STATUS_CANCEL",
|
||||
"DECODE_STATUS_ERROR",
|
||||
"DECODE_STATUS_MEMORY",
|
||||
"DECODE_STATUS_INVAL",
|
||||
"DECODE_STATUS_UNSUPPORTED",
|
||||
"DECODE_STATUS_PAPER_JAM",
|
||||
"DECODE_STATUS_COVER_OPEN",
|
||||
"DECODE_STATUS_NO_DOCS",
|
||||
};
|
||||
|
||||
return status_lookup[dec_ret];
|
||||
}
|
||||
|
||||
|
||||
virtual const char* ScanModeToText (BrotherScanMode scan_mode);
|
||||
|
||||
// Buttons.
|
||||
virtual DecodeStatus DecodeSessionResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherSessionResponse &response) = 0;
|
||||
|
||||
virtual DecodeStatus DecodeButtonQueryResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherButtonQueryResponse &response) = 0;
|
||||
|
||||
virtual DecodeStatus DecodeButtonStateResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherButtonStateResponse &response) = 0;
|
||||
|
||||
// Requests and responses.
|
||||
virtual DecodeStatus EncodeQueryBlock (SANE_Byte *data, size_t data_len, size_t *length) = 0;
|
||||
|
||||
virtual DecodeStatus DecodeQueryBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherQueryResponse &response) = 0;
|
||||
|
||||
virtual DecodeStatus EncodeBasicParameterBlock (SANE_Byte *data, size_t data_len,
|
||||
size_t *length) = 0;
|
||||
|
||||
virtual DecodeStatus DecodeBasicParameterBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherBasicParamResponse &response) = 0;
|
||||
|
||||
virtual DecodeStatus EncodeSourceStatusBlock (SANE_Byte *data, size_t data_len, size_t *length) = 0;
|
||||
|
||||
virtual DecodeStatus DecodeSourceStatusBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherSourceStatusResponse &response) = 0;
|
||||
|
||||
virtual DecodeStatus EncodeSourceSelectBlock (SANE_Byte *data, size_t data_len, size_t *length) = 0;
|
||||
|
||||
virtual DecodeStatus DecodeSourceSelectBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherSourceStatusResponse &response) = 0;
|
||||
|
||||
virtual DecodeStatus EncodeParameterBlock (SANE_Byte *data, size_t data_len, size_t *length) = 0;
|
||||
|
||||
virtual DecodeStatus EncodeParameterBlockBlank (SANE_Byte *data, size_t data_len,
|
||||
size_t *length) = 0;
|
||||
|
||||
// Scan data decoding.
|
||||
virtual 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) = 0;
|
||||
|
||||
protected:
|
||||
BrotherParameters scan_params;
|
||||
};
|
||||
|
||||
class BrotherJFIFDecoder
|
||||
{
|
||||
public:
|
||||
BrotherJFIFDecoder():
|
||||
decompress_bytes(0)
|
||||
{
|
||||
/*
|
||||
* 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));
|
||||
|
||||
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);
|
||||
|
||||
~BrotherJFIFDecoder()
|
||||
{
|
||||
jpeg_destroy_decompress(&state.cinfo);
|
||||
}
|
||||
|
||||
void NewBlock();
|
||||
void NewPage(const BrotherParameters ¶ms);
|
||||
|
||||
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);
|
||||
|
||||
DecodeStatus DecodeScanData_CompressBuffer (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);
|
||||
|
||||
struct CompressionState
|
||||
{
|
||||
struct jpeg_decompress_struct cinfo;
|
||||
struct jpeg_error_mgr jerr;
|
||||
struct jpeg_source_mgr src_mgr;
|
||||
bool have_read_header;
|
||||
jmp_buf my_env;
|
||||
} state;
|
||||
|
||||
SANE_Byte decompress_buffer[1024 * 16];
|
||||
size_t decompress_bytes;
|
||||
|
||||
BrotherParameters decode_params;
|
||||
};
|
||||
|
||||
class BrotherGrayRLengthDecoder
|
||||
{
|
||||
public:
|
||||
BrotherGrayRLengthDecoder()
|
||||
{
|
||||
}
|
||||
void NewBlock();
|
||||
|
||||
void NewPage(const BrotherParameters ¶ms);
|
||||
|
||||
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:
|
||||
BrotherParameters decode_params;
|
||||
};
|
||||
|
||||
|
||||
class BrotherInterleavedRGBColourDecoder
|
||||
{
|
||||
public:
|
||||
explicit BrotherInterleavedRGBColourDecoder(SANE_Word capabilities):
|
||||
capabilities(capabilities),
|
||||
scanline_buffer(nullptr),
|
||||
scanline_buffer_size(0),
|
||||
scanline_length(0),
|
||||
scanline_buffer_data(0)
|
||||
{
|
||||
}
|
||||
|
||||
~BrotherInterleavedRGBColourDecoder()
|
||||
{
|
||||
free(scanline_buffer);
|
||||
}
|
||||
void NewBlock();
|
||||
|
||||
void NewPage(const BrotherParameters ¶ms);
|
||||
|
||||
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);
|
||||
|
||||
enum ChannelEncoding
|
||||
{
|
||||
CHANNELS_RGB, // RGB
|
||||
CHANNELS_CrYCb // YCrCb
|
||||
};
|
||||
private:
|
||||
static void ConvertYCbCrToRGB (SANE_Byte y, SANE_Byte cb, SANE_Byte cr, SANE_Byte *red,
|
||||
SANE_Byte *green, SANE_Byte *blue);
|
||||
|
||||
BrotherParameters decode_params;
|
||||
SANE_Word capabilities;
|
||||
|
||||
SANE_Byte *scanline_buffer;
|
||||
size_t scanline_buffer_size;
|
||||
size_t scanline_length;
|
||||
size_t scanline_buffer_data;
|
||||
};
|
||||
|
||||
|
||||
class BrotherGrayRawDecoder
|
||||
{
|
||||
public:
|
||||
BrotherGrayRawDecoder()
|
||||
{
|
||||
}
|
||||
void NewBlock();
|
||||
|
||||
void NewPage(const BrotherParameters ¶ms);
|
||||
|
||||
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:
|
||||
BrotherParameters decode_params;
|
||||
};
|
||||
|
||||
class BrotherEncoderFamily2 : public BrotherEncoder
|
||||
{
|
||||
public:
|
||||
explicit BrotherEncoderFamily2(SANE_Word capabilities):
|
||||
colour_decoder(capabilities)
|
||||
{
|
||||
}
|
||||
|
||||
~BrotherEncoderFamily2 ()
|
||||
{
|
||||
}
|
||||
|
||||
void NewPage () override
|
||||
{
|
||||
current_header.block_type = 0;
|
||||
|
||||
jfif_decoder.NewPage (scan_params);
|
||||
gray_decoder.NewPage (scan_params);
|
||||
gray_raw_decoder.NewPage (scan_params);
|
||||
colour_decoder.NewPage (scan_params);
|
||||
}
|
||||
|
||||
DecodeStatus EncodeQueryBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
|
||||
|
||||
DecodeStatus DecodeQueryBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherQueryResponse &response) override;
|
||||
|
||||
DecodeStatus DecodeSessionResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherSessionResponse &response) override;
|
||||
|
||||
DecodeStatus EncodeBasicParameterBlock (SANE_Byte *data, size_t data_len, size_t *length)
|
||||
override;
|
||||
|
||||
DecodeStatus DecodeBasicParameterBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherBasicParamResponse &response) override;
|
||||
|
||||
DecodeStatus EncodeSourceStatusBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
|
||||
|
||||
DecodeStatus DecodeSourceStatusBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherSourceStatusResponse &response) override;
|
||||
|
||||
DecodeStatus EncodeSourceSelectBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
|
||||
|
||||
DecodeStatus DecodeSourceSelectBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherSourceStatusResponse &response) override;
|
||||
|
||||
DecodeStatus EncodeParameterBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
|
||||
|
||||
DecodeStatus EncodeParameterBlockBlank (SANE_Byte *data, size_t data_len, size_t *length)
|
||||
override;
|
||||
|
||||
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) override;
|
||||
|
||||
DecodeStatus DecodeButtonQueryResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherButtonQueryResponse &response) override;
|
||||
|
||||
DecodeStatus DecodeButtonStateResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherButtonStateResponse &response) override;
|
||||
|
||||
private:
|
||||
DecodeStatus DecodeScanDataHeader (const SANE_Byte *src_data, size_t src_data_len,
|
||||
size_t *src_data_consumed, ScanDataHeader &header);
|
||||
|
||||
ScanDataHeader current_header;
|
||||
|
||||
BrotherJFIFDecoder jfif_decoder;
|
||||
BrotherGrayRLengthDecoder gray_decoder;
|
||||
BrotherGrayRawDecoder gray_raw_decoder;
|
||||
BrotherInterleavedRGBColourDecoder colour_decoder;
|
||||
};
|
||||
|
||||
class BrotherEncoderFamily3 : public BrotherEncoder
|
||||
{
|
||||
public:
|
||||
explicit BrotherEncoderFamily3(SANE_Word capabilities):
|
||||
colour_decoder(capabilities)
|
||||
{
|
||||
}
|
||||
|
||||
~BrotherEncoderFamily3 ()
|
||||
{
|
||||
}
|
||||
|
||||
void NewPage() override
|
||||
{
|
||||
current_header.block_type = 0;
|
||||
|
||||
gray_raw_decoder.NewPage(scan_params);
|
||||
gray_decoder.NewPage(scan_params);
|
||||
colour_decoder.NewPage(scan_params);
|
||||
jfif_decoder.NewPage(scan_params);
|
||||
}
|
||||
|
||||
DecodeStatus EncodeQueryBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
|
||||
|
||||
DecodeStatus DecodeQueryBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherQueryResponse &response) override;
|
||||
|
||||
DecodeStatus DecodeSessionResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherSessionResponse &response) override;
|
||||
|
||||
DecodeStatus EncodeBasicParameterBlock (SANE_Byte *data, size_t data_len, size_t *length)
|
||||
override;
|
||||
|
||||
DecodeStatus DecodeBasicParameterBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherBasicParamResponse &response) override;
|
||||
|
||||
DecodeStatus EncodeSourceStatusBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
|
||||
|
||||
DecodeStatus DecodeSourceStatusBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherSourceStatusResponse &response) override;
|
||||
|
||||
DecodeStatus EncodeSourceSelectBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
|
||||
|
||||
DecodeStatus DecodeSourceSelectBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherSourceStatusResponse &response) override;
|
||||
|
||||
DecodeStatus EncodeParameterBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
|
||||
|
||||
DecodeStatus EncodeParameterBlockBlank (SANE_Byte *data, size_t data_len, size_t *length)
|
||||
override;
|
||||
|
||||
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) override;
|
||||
|
||||
DecodeStatus DecodeButtonQueryResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherButtonQueryResponse &response) override;
|
||||
|
||||
DecodeStatus DecodeButtonStateResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherButtonStateResponse &response) override;
|
||||
|
||||
private:
|
||||
DecodeStatus DecodeScanDataHeader (const SANE_Byte *src_data, size_t src_data_len,
|
||||
size_t *src_data_consumed, ScanDataHeader &header);
|
||||
|
||||
ScanDataHeader current_header;
|
||||
|
||||
BrotherGrayRawDecoder gray_raw_decoder;
|
||||
BrotherGrayRLengthDecoder gray_decoder;
|
||||
BrotherInterleavedRGBColourDecoder colour_decoder;
|
||||
BrotherJFIFDecoder jfif_decoder;
|
||||
};
|
||||
|
||||
class BrotherEncoderFamily4 : public BrotherEncoder
|
||||
{
|
||||
public:
|
||||
explicit BrotherEncoderFamily4(SANE_Word capabilities)
|
||||
{
|
||||
(void)capabilities;
|
||||
}
|
||||
|
||||
~BrotherEncoderFamily4 ()
|
||||
{
|
||||
}
|
||||
|
||||
void NewPage() override
|
||||
{
|
||||
current_header.block_type = 0;
|
||||
|
||||
jfif_decoder.NewPage(scan_params);
|
||||
gray_decoder.NewPage (scan_params);
|
||||
gray_raw_decoder.NewPage (scan_params);
|
||||
}
|
||||
|
||||
DecodeStatus EncodeQueryBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
|
||||
|
||||
DecodeStatus DecodeQueryBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherQueryResponse &response) override;
|
||||
|
||||
DecodeStatus DecodeSessionResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherSessionResponse &response) override;
|
||||
|
||||
DecodeStatus EncodeBasicParameterBlock (SANE_Byte *data, size_t data_len, size_t *length)
|
||||
override;
|
||||
|
||||
DecodeStatus DecodeBasicParameterBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherBasicParamResponse &response) override;
|
||||
|
||||
DecodeStatus EncodeSourceStatusBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
|
||||
|
||||
DecodeStatus DecodeSourceStatusBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherSourceStatusResponse &response) override;
|
||||
|
||||
DecodeStatus EncodeSourceSelectBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
|
||||
|
||||
DecodeStatus DecodeSourceSelectBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherSourceStatusResponse &response) override;
|
||||
|
||||
DecodeStatus EncodeParameterBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
|
||||
|
||||
DecodeStatus EncodeParameterBlockBlank (SANE_Byte *data, size_t data_len, size_t *length)
|
||||
override;
|
||||
|
||||
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) override;
|
||||
|
||||
DecodeStatus DecodeButtonQueryResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherButtonQueryResponse &response) override;
|
||||
|
||||
DecodeStatus DecodeButtonStateResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherButtonStateResponse &response) override;
|
||||
|
||||
private:
|
||||
DecodeStatus DecodeScanDataHeader (const SANE_Byte *src_data, size_t src_data_len,
|
||||
size_t *src_data_consumed, ScanDataHeader &header);
|
||||
|
||||
ScanDataHeader current_header;
|
||||
|
||||
BrotherJFIFDecoder jfif_decoder;
|
||||
BrotherGrayRLengthDecoder gray_decoder;
|
||||
BrotherGrayRawDecoder gray_raw_decoder;
|
||||
};
|
||||
|
||||
class BrotherEncoderFamily5 : public BrotherEncoder
|
||||
{
|
||||
public:
|
||||
explicit BrotherEncoderFamily5(SANE_Word capabilities)
|
||||
{
|
||||
(void)capabilities;
|
||||
}
|
||||
|
||||
~BrotherEncoderFamily5 ()
|
||||
{
|
||||
}
|
||||
|
||||
void NewPage() override
|
||||
{
|
||||
current_header.block_type = 0;
|
||||
|
||||
jfif_decoder.NewPage(scan_params);
|
||||
gray_decoder.NewPage (scan_params);
|
||||
}
|
||||
|
||||
const char* ScanModeToText (BrotherScanMode scan_mode) override;
|
||||
|
||||
DecodeStatus EncodeQueryBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
|
||||
|
||||
DecodeStatus DecodeQueryBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherQueryResponse &response) override;
|
||||
|
||||
DecodeStatus DecodeSessionResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherSessionResponse &response) override;
|
||||
|
||||
DecodeStatus EncodeBasicParameterBlock (SANE_Byte *data, size_t data_len, size_t *length)
|
||||
override;
|
||||
|
||||
DecodeStatus DecodeBasicParameterBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherBasicParamResponse &response) override;
|
||||
|
||||
DecodeStatus EncodeSourceStatusBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
|
||||
|
||||
DecodeStatus DecodeSourceStatusBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherSourceStatusResponse &response) override;
|
||||
|
||||
DecodeStatus EncodeSourceSelectBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
|
||||
|
||||
DecodeStatus DecodeSourceSelectBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherSourceStatusResponse &response) override;
|
||||
|
||||
DecodeStatus EncodeParameterBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
|
||||
|
||||
DecodeStatus EncodeParameterBlockBlank (SANE_Byte *data, size_t data_len, size_t *length)
|
||||
override;
|
||||
|
||||
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) override;
|
||||
|
||||
DecodeStatus DecodeButtonQueryResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherButtonQueryResponse &response) override;
|
||||
|
||||
DecodeStatus DecodeButtonStateResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherButtonStateResponse &response) override;
|
||||
|
||||
private:
|
||||
DecodeStatus DecodeScanDataHeader (const SANE_Byte *src_data, size_t src_data_len,
|
||||
size_t *src_data_consumed, ScanDataHeader &header);
|
||||
|
||||
ScanDataHeader current_header;
|
||||
|
||||
BrotherJFIFDecoder jfif_decoder;
|
||||
BrotherGrayRLengthDecoder gray_decoder;
|
||||
};
|
Plik diff jest za duży
Load Diff
|
@ -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
|
|
@ -667,7 +667,7 @@ AC_ARG_ENABLE(local-backends,
|
|||
[turn off compilation of all backends but net]))
|
||||
|
||||
ALL_BACKENDS="abaton agfafocus apple artec artec_eplus48u as6e \
|
||||
avision bh canon canon630u canon_dr canon_lide70 canon_pp cardscan \
|
||||
avision bh brother_mfp canon canon630u canon_dr canon_lide70 canon_pp cardscan \
|
||||
coolscan coolscan2 coolscan3 dc25 dc210 dc240 \
|
||||
dell1600n_net dmc epjitsu epson epson2 epsonds escl fujitsu \
|
||||
genesys gphoto2 gt68xx hp hp3500 hp3900 hp4200 hp5400 \
|
||||
|
@ -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])
|
||||
|
|
|
@ -38,7 +38,7 @@ BACKEND_5MANS = sane-abaton.5 sane-agfafocus.5 sane-apple.5 sane-as6e.5 \
|
|||
sane-hp5590.5 sane-hpljm1005.5 sane-cardscan.5 sane-hp3900.5 \
|
||||
sane-epjitsu.5 sane-hs2p.5 sane-canon_dr.5 sane-xerox_mfp.5 \
|
||||
sane-rts8891.5 sane-coolscan3.5 sane-kvs1025.5 sane-kvs20xx.5 \
|
||||
sane-kvs40xx.5 sane-p5.5 sane-magicolor.5 sane-lexmark_x2600.5
|
||||
sane-kvs40xx.5 sane-p5.5 sane-magicolor.5 sane-lexmark_x2600.5 sane-brother_mfp.5
|
||||
|
||||
EXTRA_DIST += sane-abaton.man sane-agfafocus.man sane-apple.man sane-as6e.man \
|
||||
sane-canon_lide70.man \
|
||||
|
@ -64,7 +64,7 @@ EXTRA_DIST += sane-abaton.man sane-agfafocus.man sane-apple.man sane-as6e.man \
|
|||
sane-cardscan.man sane-hp3900.man sane-epjitsu.man sane-hs2p.man \
|
||||
sane-canon_dr.man sane-xerox_mfp.man sane-rts8891.man \
|
||||
sane-coolscan3.man sane-kvs1025.man sane-kvs20xx.man sane-kvs40xx.man \
|
||||
sane-p5.man sane-magicolor.man sane-lexmark_x2600.man
|
||||
sane-p5.man sane-magicolor.man sane-lexmark_x2600.man sane-brother_mfp.man
|
||||
|
||||
man7_MANS = sane.7
|
||||
EXTRA_DIST += sane.man
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
.TH "sane\-brother_mfp" "5" "20 Nov 2022" "@PACKAGEVERSION@" "SANE Scanner Access Now Easy"
|
||||
.IX sane\-brother_mfp
|
||||
.SH "NAME"
|
||||
sane\-brother_mfp \- SANE backend for Brother Multifunction Printer/Scanners
|
||||
.SH "DESCRIPTION"
|
||||
The
|
||||
.B sane\-brother_mfp
|
||||
library implements a SANE (Scanner Access Now Easy) backend that provides
|
||||
access to a number of machines by Brother. These are mainly in the DCP and MFC line of multi\-function
|
||||
devices, but also include some dedicated scanners in the AD range.
|
||||
|
||||
.PP
|
||||
The backend should be considered Beta quality at the moment as work is ongoing to decode tha various
|
||||
options supported by the machine range.
|
||||
|
||||
|
||||
.SH OPTIONS
|
||||
|
||||
.TP
|
||||
.BR \-\-source
|
||||
Selects the scanning method for the device. Valid options vary depending on the capabilities
|
||||
of the device. Options available are:
|
||||
.IR Flatbed ", " "Automatic Document Feeder" ", " "Automatic Document Feeder (one sided)"
|
||||
and
|
||||
.IR "Automatic Document Feeder (duplex)" .
|
||||
.I Flatbed
|
||||
is the default.
|
||||
|
||||
.TP
|
||||
.BR \-\-mode
|
||||
Selects the type of scan to perform. Most devices support:
|
||||
.IR "Color" ", " "Gray" ", " "Gray (dithered)"
|
||||
and
|
||||
.IR "Lineart" .
|
||||
.I Color
|
||||
is the default.
|
||||
|
||||
|
||||
.TP
|
||||
.BR \-\-split\-resolution
|
||||
When selected, activates the
|
||||
.B \-\-x\-resolution
|
||||
and
|
||||
.B \-\-y\-resolution
|
||||
options. This allows different resolutions to be selected for the horizontal and vertical.
|
||||
When not selected, then the
|
||||
.B \-\-resolution
|
||||
option is activated and the same resolution is selected for both.
|
||||
|
||||
|
||||
|
||||
.TP
|
||||
.BR \-\-resolution
|
||||
Selects the resolution for both the horizontal and vertical directions of the scan.
|
||||
The parameter is selected from a list of valid values for the device.
|
||||
|
||||
|
||||
.TP
|
||||
.BR \-\-x\-resolution ", " \-\-y\-resolution
|
||||
Selects the individual resolutions for the horizontal and vertical directions of the scan.
|
||||
The parameter is selected from a list of valid values for the device for each direction, and different
|
||||
ranges for each option may be available.
|
||||
|
||||
|
||||
.TP
|
||||
.BR \-\-preview
|
||||
Selects a resolution for both the x and y direction suitable for previewing.
|
||||
The option will select the lowest available resolutions.
|
||||
|
||||
|
||||
.TP
|
||||
.BR \-\-tl\-x ", " \-\-tl\-y ", " \-\-br\-x ", " \-\-br\-y
|
||||
Selects the area to scan. All measurements are in mm and are relative to the top, left hand corner
|
||||
of the scan area. The
|
||||
.B \-\-tl\-x
|
||||
and
|
||||
.B \-\-tl\-y
|
||||
options specify the coordinates of the top left corner. The
|
||||
.B \-\-br\-x
|
||||
and
|
||||
.B \-\-br\-y
|
||||
options specify the coordinates of the bottom right corner.
|
||||
The default values cover the maximum scan area for the selected source.
|
||||
|
||||
|
||||
.TP
|
||||
.BR \-\-brightness
|
||||
Alters the brightness of the generated image when
|
||||
.I Gray (dithered)
|
||||
or
|
||||
.I Lineart
|
||||
modes are selected. Valid values are between \-50 and +50.
|
||||
Default value is 0.
|
||||
|
||||
.TP
|
||||
.BR \-\-contrast
|
||||
Alters the contrast of the generated image when
|
||||
.I Gray (dithered)
|
||||
or
|
||||
.I Lineart
|
||||
modes are selected. Valid values are between \-50 and +50.
|
||||
Default value is 0.
|
||||
|
||||
|
||||
.TP
|
||||
.BR \-\-compression
|
||||
For devices that offer both raw and compressed (JPEG) scan image delivery, this option
|
||||
is used to select which option is desired. If set, then JPEG will be used.
|
||||
If not set, then whatever raw, uncompressed option is used.
|
||||
The effect of unsetting this option will be to increase the volume of data sent from the
|
||||
scanner with a small increase in image quality.
|
||||
Default for this option is for it to be set.
|
||||
|
||||
|
||||
|
||||
.TP
|
||||
.BR \-\-email-sensor ", " \-\-file-sensor ", " \-\-image-sensor ", " \-\-ocr-sensor
|
||||
These options provide a readonly capability to sense when a soft scan button is selected on the
|
||||
device. Typically, this would be a menu option intended to elicit a specific scanning operation
|
||||
by the backend. To use this function, a monitoring daemon would be required such as
|
||||
.BR scanbd (8).
|
||||
|
||||
If the corresponding operation has been requested on the device, querying this option would
|
||||
show that it is set. Once the sensor has been queried, it will be reset on the device so that
|
||||
the event can only be sensed once.
|
||||
|
||||
|
||||
.SH "CONFIGURATION"
|
||||
The contents of the
|
||||
.I brother_mfp.conf
|
||||
file contains information related to supported devices. Also there is a section to indicate
|
||||
the location of network devices than cannot be auto detected.
|
||||
|
||||
.SH "FILES"
|
||||
.TP
|
||||
.I @CONFIGDIR@/brother_mfp.conf
|
||||
The backend configuration file (see also description of
|
||||
.B SANE_CONFIG_DIR
|
||||
below).
|
||||
.TP
|
||||
.I @LIBDIR@/libsane\-brother_mfp.a
|
||||
The static library implementing this backend.
|
||||
.TP
|
||||
.I @LIBDIR@/libsane\-brother_mfp.so
|
||||
The shared library implementing this backend (present on systems that
|
||||
support dynamic loading).
|
||||
|
||||
.SH "ENVIRONMENT"
|
||||
.TP
|
||||
.B SANE_CONFIG_DIR
|
||||
This environment variable specifies the list of directories that may
|
||||
contain the configuration file. On *NIX systems, the directories are
|
||||
separated by a colon (`:'), under OS/2, they are separated by a
|
||||
semi-colon (`;'). If this variable is not set, the configuration file
|
||||
is searched in two default directories: first, the current working
|
||||
directory (".") and then in
|
||||
.IR @CONFIGDIR@ .
|
||||
If the value of the environment variable ends with the directory separator
|
||||
character, then the default directories are searched after the explicitly
|
||||
specified directories. For example, setting
|
||||
.B SANE_CONFIG_DIR
|
||||
to "/tmp/config:" would result in directories
|
||||
.IR tmp/config ,
|
||||
.IR . ,
|
||||
and
|
||||
.I "@CONFIGDIR@"
|
||||
being searched (in this order).
|
||||
.TP
|
||||
.B SANE_DEBUG_BROTHER_MFP
|
||||
If the library was compiled with debug support enabled, this environment
|
||||
variable controls the debug level for this backend. Valid values are 1 (IMPORTANT),
|
||||
2 (SERIOUS), 3 (WARNINGS), 4 (EVENT), 5 (DETAIL) and 6 (DEBUG). Selecting 5 or 6 will generate
|
||||
a large amount of output.
|
||||
|
||||
|
||||
.SH CREDITS
|
||||
|
||||
.TP
|
||||
.I David R Roberts, GitHub user “davidar”
|
||||
For his analysis of another Brother machine, which has led to me
|
||||
getting a good head start on this process and for inspiring me to write this backend.
|
||||
|
||||
.TP
|
||||
.I Various GitLab users
|
||||
For their help in checking out models of devices that I do not have access to and patiently
|
||||
making PCAP captures and diag log output for me to look at!
|
||||
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR sane (7),
|
||||
.BR sane\-usb (5),
|
||||
.BR scanbd (8)
|
||||
.br
|
||||
|
||||
|
||||
.SH "AUTHOR"
|
||||
Ralph Little
|
||||
.RI < skelband@gmail.com >
|
||||
|
||||
.SH "BUGS"
|
||||
There are no specific bugs to report for this backend.
|
|
@ -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)
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
## 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) $(JPEG_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_tests_family4.cpp \
|
||||
brother_mfp_tests_family3.cpp \
|
||||
brother_mfp_tests_family2.cpp \
|
||||
brother_mfp_tests_gray_rlength.cpp \
|
||||
brother_mfp_tests_colour_int_rgb.cpp \
|
||||
brother_mfp_tests_colour_jpeg.cpp \
|
||||
../genesys/minigtest.cpp
|
||||
|
||||
brother_mfp_unit_tests_LDADD = $(TEST_LDADD)
|
|
@ -0,0 +1,39 @@
|
|||
/* 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_NOT_STATIC
|
||||
|
||||
#include "../../include/sane/sanei_debug.h"
|
||||
#include "../genesys/minigtest.h"
|
||||
#include "brother_mfp_tests.h"
|
||||
|
||||
int main ()
|
||||
{
|
||||
DBG_INIT ();
|
||||
|
||||
test_family4 ();
|
||||
test_family3 ();
|
||||
test_family2 ();
|
||||
test_gray_rlength ();
|
||||
test_colour_int_rgb();
|
||||
test_colour_jpeg();
|
||||
|
||||
return finish_tests ();
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/* 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
|
||||
|
||||
extern void test_family4();
|
||||
extern void test_family3();
|
||||
extern void test_family2();
|
||||
extern void test_gray_rlength();
|
||||
extern void test_colour_int_rgb();
|
||||
extern void test_colour_jpeg();
|
|
@ -0,0 +1,170 @@
|
|||
/* 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 "../../include/sane/sanei_debug.h"
|
||||
#include "brother_mfp_tests.h"
|
||||
#include "../../backend/brother_mfp/brother_mfp-encoder.h"
|
||||
#include "../genesys/minigtest.h"
|
||||
|
||||
/*
|
||||
* TEST: BrotherInterleavedRGBColourDecoder()
|
||||
*
|
||||
*/
|
||||
static void test_colour_int_rgb_enc_rgb()
|
||||
{
|
||||
BrotherInterleavedRGBColourDecoder decoder(CAP_MODE_COLOUR);
|
||||
const SANE_Byte *src_data;
|
||||
SANE_Byte dest_data[1024];
|
||||
DecodeStatus res_code;
|
||||
size_t src_data_consumed;
|
||||
size_t dest_data_written;
|
||||
|
||||
/*
|
||||
* Normal decode.
|
||||
*
|
||||
*/
|
||||
BrotherParameters params;
|
||||
params.param_pixel_x_width = 6;
|
||||
|
||||
decoder.NewPage(params);
|
||||
src_data = (const SANE_Byte *)"123456";
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
strlen((const char *)src_data),
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)6);
|
||||
ASSERT_EQ(dest_data_written, (size_t)0);
|
||||
|
||||
decoder.NewBlock();
|
||||
src_data = (const SANE_Byte *)"ABCDEF";
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
strlen((const char *)src_data),
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)6);
|
||||
ASSERT_EQ(dest_data_written, (size_t)0);
|
||||
|
||||
decoder.NewBlock();
|
||||
src_data = (const SANE_Byte *)"MNOPQR";
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
strlen((const char *)src_data),
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)6);
|
||||
ASSERT_EQ(dest_data_written, (size_t)18);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "1AM2BN3CO4DP5EQ6FR", 18), 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void test_colour_int_rgb_enc_ycrcb()
|
||||
{
|
||||
BrotherInterleavedRGBColourDecoder decoder(CAP_MODE_COLOUR | CAP_ENCODING_RAW_IS_CrYCb);
|
||||
const SANE_Byte *src_data;
|
||||
SANE_Byte dest_data[1024];
|
||||
DecodeStatus res_code;
|
||||
size_t src_data_consumed;
|
||||
size_t dest_data_written;
|
||||
|
||||
/*
|
||||
* Normal decode.
|
||||
*
|
||||
*/
|
||||
BrotherParameters params;
|
||||
params.param_pixel_x_width = 7;
|
||||
|
||||
decoder.NewPage(params);
|
||||
decoder.NewBlock();
|
||||
src_data = (const SANE_Byte *)"\x5B" "\x63" "\x60" "\x5D" "\x5D" "\x62" "\x6A";
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
strlen((const char *)src_data),
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)7);
|
||||
ASSERT_EQ(dest_data_written, (size_t)0);
|
||||
|
||||
decoder.NewBlock();
|
||||
src_data = (const SANE_Byte *)"\xDD" "\xE9" "\xEE" "\xEF" "\xED" "\xED" "\xEB";
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
strlen((const char *)src_data),
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)7);
|
||||
ASSERT_EQ(dest_data_written, (size_t)0);
|
||||
|
||||
decoder.NewBlock();
|
||||
src_data = (const SANE_Byte *)"\x70" "\x6E" "\x6D" "\x6E" "\x6E" "\x6E" "\x6D";
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
strlen((const char *)src_data),
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)7);
|
||||
ASSERT_EQ(dest_data_written, (size_t)21);
|
||||
|
||||
// YCbCr data converted to RGB:
|
||||
ASSERT_EQ(memcmp (dest_data,
|
||||
"\xa9" "\xfc" "\xc0" "\xc0" "\xff" "\xc9" "\xc1" "\xff"
|
||||
"\xcc" "\xbd" "\xff" "\xcf" "\xbb" "\xff" "\xcd" "\xc2"
|
||||
"\xff" "\xcd" "\xcc" "\xff" "\xc9",
|
||||
21),
|
||||
0);
|
||||
}
|
||||
/*
|
||||
* Run all the tests.
|
||||
*
|
||||
*/
|
||||
void test_colour_int_rgb()
|
||||
{
|
||||
test_colour_int_rgb_enc_rgb();
|
||||
test_colour_int_rgb_enc_ycrcb();
|
||||
}
|
|
@ -0,0 +1,225 @@
|
|||
/* 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 "../../include/sane/sanei_debug.h"
|
||||
#include "brother_mfp_tests.h"
|
||||
#include "../../backend/brother_mfp/brother_mfp-encoder.h"
|
||||
#include "../genesys/minigtest.h"
|
||||
|
||||
/*
|
||||
* TEST: BrotherJFIFDecoder()
|
||||
*
|
||||
*/
|
||||
|
||||
static void test_colour_jpeg_normal()
|
||||
{
|
||||
BrotherJFIFDecoder decoder;
|
||||
const SANE_Byte *src_data;
|
||||
SANE_Byte dest_data[1024];
|
||||
DecodeStatus res_code;
|
||||
size_t src_data_consumed;
|
||||
size_t dest_data_written;
|
||||
|
||||
/*
|
||||
* Normal decode.
|
||||
*
|
||||
* Test image is 7x14 pixels.
|
||||
*
|
||||
*/
|
||||
|
||||
#define HEX2DEC(ptr) ((ptr) >= 'a' && (ptr) <= 'f'? (ptr) - 'a' + 10: (ptr) - '0')
|
||||
|
||||
src_data = (const SANE_Byte *)"ffd8ffdb008400"
|
||||
"010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010"
|
||||
"101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101"
|
||||
"010101010101010101010101010101010101010101010101ffdd00040000ffc0001108000e000703012200021101031101ffc401a"
|
||||
"20000010501010101010100000000000000000102030405060708090a0b100002010303020403050504040000017d010203000411"
|
||||
"05122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434"
|
||||
"445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6"
|
||||
"a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9fa010"
|
||||
"0030101010101010101010000000000000102030405060708090a0b11000201020404030407050404000102770001020311040521"
|
||||
"31061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a43444"
|
||||
"5464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6"
|
||||
"a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda000"
|
||||
"c03010002110311003f00fe929ffe0a19adf807c37f1447ed15fb3378c7e0bfc56f87be1ed37c5ba47c32b3f17e8fe3b87c79e1ed"
|
||||
"5af534bb2bad03c5ba3585ae991bc7a93ada5f5bcd687ece4131b4ce92431f51a7fede07c33e1cf8a371f1f7e0c6bff03fc77f0d3"
|
||||
"40d13c5f1f810f88f4ff18cde2ef0b78866b6b5d36f741d4f4fb0b088ddc77575059ea1a6cd6919b59dc0599d63b816ff006df8bf"
|
||||
"f626fd9abc7fac6b9e20f1b780f57f14eb5e23d134ef0e6a9a8eb7f137e2bdfdc1d0f4abd4d4ac74dd38cfe3765d12de2bf8d6e9f"
|
||||
"f00b1174e7b89b2d72d36e605fe32fd8aff0066cf887ab6b7aef8e3c03a9f8a356f10f87f4af0b6ab7bac7c47f8a375249a068b73"
|
||||
"05e69ba6da2b78d045a5c30dddbc57323e951d94d7738796f249de594bfec74f8a3c2ea90a0b11c279861e55ead0a9984b2f963ff"
|
||||
"d8e341e50a587c8e38de2dc4c6385c5468e70b131cd96618b8bc5615e0f1b8454d470ff009d4b23e35929a867186a0aa29b8db170"
|
||||
"aff535cb5a30a54e3538720b1897b5a32856adec151960e8a9e1b150ad8a856fffd9";
|
||||
|
||||
SANE_Byte *in_buffer = new SANE_Byte[strlen((const char *)src_data) / 2];
|
||||
SANE_Byte *in_ptr = in_buffer;
|
||||
|
||||
for (const SANE_Byte *src_ptr = src_data; *src_ptr; src_ptr += 2)
|
||||
{
|
||||
*in_ptr++ = HEX2DEC(src_ptr[0]) << 4 | HEX2DEC(src_ptr[1]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test JPEG image has expected width.
|
||||
*
|
||||
*/
|
||||
BrotherParameters params;
|
||||
params.param_pixel_x_width = 7;
|
||||
|
||||
decoder.NewPage(params);
|
||||
decoder.NewBlock();
|
||||
|
||||
res_code = decoder.DecodeScanData (in_buffer,
|
||||
in_ptr - in_buffer,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)(in_ptr - in_buffer));
|
||||
ASSERT_EQ(dest_data_written, (size_t)294);
|
||||
|
||||
const SANE_Byte expected_dest[] = "\xe4" "\xf0" "\xf0" "\xe8" "\xf2" "\xf4" "\xea" "\xed" "\xf6" "\xeb"
|
||||
"\xee" "\xf7" "\xeb" "\xee" "\xf7" "\xeb" "\xf0" "\xf6" "\xed" "\xf0" "\xf9" "\xea" "\xf5" "\xf7"
|
||||
"\xe7" "\xf2" "\xf6" "\xea" "\xee" "\xf7" "\xea" "\xee" "\xf7" "\xe9" "\xf0" "\xf8" "\xe8" "\xef"
|
||||
"\xf5" "\xea" "\xee" "\xf7" "\xe9" "\xf6" "\xfc" "\xe9" "\xf6" "\xfc" "\xea" "\xf5" "\xfb" "\xea"
|
||||
"\xf5" "\xfb" "\xe9" "\xf4" "\xfa" "\xe8" "\xf3" "\xf9" "\xe9" "\xf2" "\xf7" "\xdc" "\xe9" "\xff"
|
||||
"\xd9" "\xe8" "\xff" "\xdd" "\xee" "\xff" "\xe0" "\xf5" "\xff" "\xe3" "\xf7" "\xff" "\xe3" "\xf7"
|
||||
"\xff" "\xe3" "\xf6" "\xff" "\x4e" "\x59" "\xa9" "\x4c" "\x5e" "\xaa" "\x61" "\x7e" "\xc4" "\xa9"
|
||||
"\xca" "\xfd" "\xd8" "\xf8" "\xff" "\xd5" "\xf9" "\xff" "\xb2" "\xda" "\xfe" "\x55" "\x5e" "\xad"
|
||||
"\x4e" "\x5e" "\xac" "\x3f" "\x5c" "\xa8" "\x5b" "\x7f" "\xbd" "\xb2" "\xd6" "\xf6" "\xc2" "\xe9"
|
||||
"\xff" "\x76" "\xa1" "\xd6" "\xd8" "\xdf" "\xf9" "\xce" "\xdb" "\xfd" "\x90" "\xa4" "\xd6" "\x5e"
|
||||
"\x77" "\xad" "\x7b" "\x9a" "\xc6" "\xa3" "\xc3" "\xf2" "\x69" "\x88" "\xc8" "\xe9" "\xfe" "\xff"
|
||||
"\xe7" "\xfd" "\xff" "\xcf" "\xe5" "\xff" "\x76" "\x8e" "\xbe" "\x73" "\x8d" "\xbe" "\x9e" "\xb9"
|
||||
"\xf0" "\x74" "\x8c" "\xd2" "\xd1" "\xff" "\xff" "\xd5" "\xff" "\xff" "\xbd" "\xe3" "\xff" "\x6c"
|
||||
"\x8d" "\xba" "\x72" "\x8d" "\xba" "\xa0" "\xb9" "\xef" "\x76" "\x8e" "\xd4" "\xa2" "\xcf" "\xd4"
|
||||
"\x9c" "\xc6" "\xd2" "\x70" "\x92" "\xad" "\x5a" "\x74" "\x95" "\x8d" "\xa1" "\xc2" "\xb4" "\xc6"
|
||||
"\xec" "\x80" "\x91" "\xc5" "\xf3" "\xff" "\xff" "\xf5" "\xff" "\xff" "\xf7" "\xff" "\xff" "\xf8"
|
||||
"\xff" "\xff" "\xf9" "\xff" "\xff" "\xf9" "\xff" "\xff" "\xf9" "\xfe" "\xff" "\xff" "\xff" "\xff"
|
||||
"\xff" "\xff" "\xff" "\xff" "\xff" "\xfd" "\xff" "\xff" "\xfd" "\xff" "\xff" "\xff" "\xff" "\xff"
|
||||
"\xff" "\xff" "\xff" "\xff" "\xfe" "\xfe" "\xfc" "\xff" "\xff" "\xfd" "\xff" "\xff" "\xff" "\xff"
|
||||
"\xff" "\xff" "\xfe" "\xfe" "\xfe" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xfd"
|
||||
"\xff" "\xff" "\xfd" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff"
|
||||
"\xff" "\xff" "\xff" "\xff" ;
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, expected_dest, 294), 0);
|
||||
|
||||
// /*
|
||||
// * Test JPEG image has extra width: expecting 5.
|
||||
// *
|
||||
// */
|
||||
// params.param_pixel_x_width = 5;
|
||||
//
|
||||
// decoder.NewPage(params);
|
||||
// decoder.NewBlock();
|
||||
//
|
||||
// res_code = decoder.DecodeScanData (in_buffer,
|
||||
// in_ptr - in_buffer,
|
||||
// &src_data_consumed,
|
||||
// dest_data,
|
||||
// sizeof(dest_data),
|
||||
// &dest_data_written);
|
||||
//
|
||||
// ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
// ASSERT_EQ(src_data_consumed, (size_t)(in_ptr - in_buffer));
|
||||
// ASSERT_EQ(dest_data_written, (size_t)210);
|
||||
//
|
||||
// const SANE_Byte expected_dest2[] = "\xe4" "\xf0" "\xf0" "\xe8" "\xf2" "\xf4" "\xea" "\xed" "\xf6" "\xeb"
|
||||
// "\xee" "\xf7" "\xeb" "\xee" "\xf7" "\xea" "\xf5" "\xf7" "\xe7" "\xf2" "\xf6" "\xea" "\xee" "\xf7"
|
||||
// "\xea" "\xee" "\xf7" "\xe9" "\xf0" "\xf8" "\xe9" "\xf6" "\xfc" "\xe9" "\xf6" "\xfc" "\xea" "\xf5"
|
||||
// "\xfb" "\xea" "\xf5" "\xfb" "\xe9" "\xf4" "\xfa" "\xdc" "\xe9" "\xff" "\xd9" "\xe8" "\xff" "\xdd"
|
||||
// "\xee" "\xff" "\xe0" "\xf5" "\xff" "\xe3" "\xf7" "\xff" "\x4e" "\x59" "\xa9" "\x4c" "\x5e" "\xaa"
|
||||
// "\x61" "\x7e" "\xc4" "\xa9" "\xca" "\xfd" "\xd8" "\xf8" "\xff" "\x55" "\x5e" "\xad" "\x4e" "\x5e"
|
||||
// "\xac" "\x3f" "\x5c" "\xa8" "\x5b" "\x7f" "\xbd" "\xb2" "\xd6" "\xf6" "\xd8" "\xdf" "\xf9" "\xce"
|
||||
// "\xdb" "\xfd" "\x90" "\xa4" "\xd6" "\x5e" "\x77" "\xad" "\x7b" "\x9a" "\xc6" "\xe9" "\xfe" "\xff"
|
||||
// "\xe7" "\xfd" "\xff" "\xcf" "\xe5" "\xff" "\x76" "\x8e" "\xbe" "\x73" "\x8d" "\xbe" "\xd1" "\xff"
|
||||
// "\xff" "\xd5" "\xff" "\xff" "\xbd" "\xe3" "\xff" "\x6c" "\x8d" "\xba" "\x72" "\x8d" "\xba" "\xa2"
|
||||
// "\xcf" "\xd4" "\x9c" "\xc6" "\xd2" "\x70" "\x92" "\xad" "\x5a" "\x74" "\x95" "\x8d" "\xa1" "\xc2"
|
||||
// "\xf3" "\xff" "\xff" "\xf5" "\xff" "\xff" "\xf7" "\xff" "\xff" "\xf8" "\xff" "\xff" "\xf9" "\xff"
|
||||
// "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xfd" "\xff" "\xff" "\xfd" "\xff"
|
||||
// "\xff" "\xff" "\xfe" "\xfe" "\xfc" "\xff" "\xff" "\xfd" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff"
|
||||
// "\xfe" "\xfe" "\xfe" "\xff" "\xff" "\xfd" "\xff" "\xff" "\xfd" "\xff" "\xff" "\xff" "\xff" "\xff"
|
||||
// "\xff" "\xff" "\xff" "\xff";
|
||||
//
|
||||
// ASSERT_EQ(memcmp(dest_data, expected_dest2, 210), 0);
|
||||
//
|
||||
// /*
|
||||
// * Test JPEG image has short width: expecting 9.
|
||||
// * Output will be padded with black.
|
||||
// *
|
||||
// */
|
||||
// params.param_pixel_x_width = 9;
|
||||
//
|
||||
// decoder.NewPage(params);
|
||||
// decoder.NewBlock();
|
||||
//
|
||||
// res_code = decoder.DecodeScanData (in_buffer,
|
||||
// in_ptr - in_buffer,
|
||||
// &src_data_consumed,
|
||||
// dest_data,
|
||||
// sizeof(dest_data),
|
||||
// &dest_data_written);
|
||||
//
|
||||
// ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
// ASSERT_EQ(src_data_consumed, (size_t)(in_ptr - in_buffer));
|
||||
// ASSERT_EQ(dest_data_written, (size_t)378);
|
||||
//
|
||||
// const SANE_Byte expected_dest3[] = "\xe4" "\xf0" "\xf0" "\xe8" "\xf2" "\xf4" "\xea" "\xed" "\xf6" "\xeb"
|
||||
// "\xee" "\xf7" "\xeb" "\xee" "\xf7" "\xeb" "\xf0" "\xf6" "\xed" "\xf0" "\xf9" "\x00" "\x00" "\x00"
|
||||
// "\x00" "\x00" "\x00" "\xea" "\xf5" "\xf7" "\xe7" "\xf2" "\xf6" "\xea" "\xee" "\xf7" "\xea" "\xee"
|
||||
// "\xf7" "\xe9" "\xf0" "\xf8" "\xe8" "\xef" "\xf5" "\xea" "\xee" "\xf7" "\x00" "\x00" "\x00" "\x00"
|
||||
// "\x00" "\x00" "\xe9" "\xf6" "\xfc" "\xe9" "\xf6" "\xfc" "\xea" "\xf5" "\xfb" "\xea" "\xf5" "\xfb"
|
||||
// "\xe9" "\xf4" "\xfa" "\xe8" "\xf3" "\xf9" "\xe9" "\xf2" "\xf7" "\x00" "\x00" "\x00" "\x00" "\x00"
|
||||
// "\x00" "\xdc" "\xe9" "\xff" "\xd9" "\xe8" "\xff" "\xdd" "\xee" "\xff" "\xe0" "\xf5" "\xff" "\xe3"
|
||||
// "\xf7" "\xff" "\xe3" "\xf7" "\xff" "\xe3" "\xf6" "\xff" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00"
|
||||
// "\x4e" "\x59" "\xa9" "\x4c" "\x5e" "\xaa" "\x61" "\x7e" "\xc4" "\xa9" "\xca" "\xfd" "\xd8" "\xf8"
|
||||
// "\xff" "\xd5" "\xf9" "\xff" "\xb2" "\xda" "\xfe" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x55"
|
||||
// "\x5e" "\xad" "\x4e" "\x5e" "\xac" "\x3f" "\x5c" "\xa8" "\x5b" "\x7f" "\xbd" "\xb2" "\xd6" "\xf6"
|
||||
// "\xc2" "\xe9" "\xff" "\x76" "\xa1" "\xd6" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\xd8" "\xdf"
|
||||
// "\xf9" "\xce" "\xdb" "\xfd" "\x90" "\xa4" "\xd6" "\x5e" "\x77" "\xad" "\x7b" "\x9a" "\xc6" "\xa3"
|
||||
// "\xc3" "\xf2" "\x69" "\x88" "\xc8" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\xe9" "\xfe" "\xff"
|
||||
// "\xe7" "\xfd" "\xff" "\xcf" "\xe5" "\xff" "\x76" "\x8e" "\xbe" "\x73" "\x8d" "\xbe" "\x9e" "\xb9"
|
||||
// "\xf0" "\x74" "\x8c" "\xd2" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\xd1" "\xff" "\xff" "\xd5"
|
||||
// "\xff" "\xff" "\xbd" "\xe3" "\xff" "\x6c" "\x8d" "\xba" "\x72" "\x8d" "\xba" "\xa0" "\xb9" "\xef"
|
||||
// "\x76" "\x8e" "\xd4" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\xa2" "\xcf" "\xd4" "\x9c" "\xc6"
|
||||
// "\xd2" "\x70" "\x92" "\xad" "\x5a" "\x74" "\x95" "\x8d" "\xa1" "\xc2" "\xb4" "\xc6" "\xec" "\x80"
|
||||
// "\x91" "\xc5" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\xf3" "\xff" "\xff" "\xf5" "\xff" "\xff"
|
||||
// "\xf7" "\xff" "\xff" "\xf8" "\xff" "\xff" "\xf9" "\xff" "\xff" "\xf9" "\xff" "\xff" "\xf9" "\xfe"
|
||||
// "\xff" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff"
|
||||
// "\xff" "\xfd" "\xff" "\xff" "\xfd" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff"
|
||||
// "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\xfe" "\xfe" "\xfc" "\xff" "\xff" "\xfd" "\xff" "\xff"
|
||||
// "\xff" "\xff" "\xff" "\xff" "\xfe" "\xfe" "\xfe" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\x00"
|
||||
// "\x00" "\x00" "\x00" "\x00" "\x00" "\xff" "\xff" "\xfd" "\xff" "\xff" "\xfd" "\xff" "\xff" "\xff"
|
||||
// "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\xff" "\x00" "\x00"
|
||||
// "\x00" "\x00" "\x00" "\x00";
|
||||
//
|
||||
// ASSERT_EQ(memcmp(dest_data, expected_dest3, 378), 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Run all the tests.
|
||||
*
|
||||
*/
|
||||
void test_colour_jpeg()
|
||||
{
|
||||
test_colour_jpeg_normal();
|
||||
}
|
|
@ -0,0 +1,414 @@
|
|||
/* 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 "brother_mfp_tests.h"
|
||||
#include "../../backend/brother_mfp/brother_mfp-encoder.h"
|
||||
#include "../genesys/minigtest.h"
|
||||
|
||||
/*
|
||||
* TEST: DecodeSessionResp()
|
||||
*
|
||||
*/
|
||||
static void test_family2_decode_session_resp()
|
||||
{
|
||||
DecodeStatus decode_resp;
|
||||
BrotherSessionResponse sess_resp;
|
||||
|
||||
BrotherEncoderFamily2 encoder(0);
|
||||
|
||||
// SUCCESS status
|
||||
const SANE_Byte *data = (const SANE_Byte *)"\x05" "\x10" "\x01" "\x02" "\x00";
|
||||
|
||||
decode_resp = encoder.DecodeSessionResp (data, 5, sess_resp);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
ASSERT_TRUE(sess_resp.ready);
|
||||
|
||||
// BUSY status
|
||||
data = (const SANE_Byte *)"\x05" "\x10" "\x01" "\x02" "\x80";
|
||||
|
||||
decode_resp = encoder.DecodeSessionResp (data, 5, sess_resp);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
ASSERT_FALSE(sess_resp.ready);
|
||||
|
||||
// Length issues
|
||||
data = (const SANE_Byte *)"\x05" "\x10" "\x01" "\x02" "\x20" "\x32";
|
||||
|
||||
decode_resp = encoder.DecodeSessionResp (data, 6, sess_resp);
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_ERROR);
|
||||
|
||||
decode_resp = encoder.DecodeSessionResp (data, 4, sess_resp);
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_ERROR);
|
||||
|
||||
decode_resp = encoder.DecodeSessionResp (data, 0, sess_resp);
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_ERROR);
|
||||
|
||||
// Content problems.
|
||||
const char *content_problems[] = {
|
||||
"\x32" "\x10" "\x01" "\x02" "\x20",
|
||||
"\x06" "\x32" "\x01" "\x02" "\x20",
|
||||
"\x06" "\x10" "\x32" "\x02" "\x20",
|
||||
"\x06" "\x10" "\x01" "\x32" "\x20",
|
||||
"\x06" "\x10" "\x01" "\x02" "\x32",
|
||||
nullptr
|
||||
};
|
||||
|
||||
for (size_t test = 0; test; test++)
|
||||
{
|
||||
decode_resp = encoder.DecodeSessionResp ((const SANE_Byte *)content_problems[test], 5, sess_resp);
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TEST: DecodeBasicParameterBlockResp()
|
||||
*
|
||||
*/
|
||||
static void test_family2_decode_basic_param_resp()
|
||||
{
|
||||
/*
|
||||
* TODO: Nothing to do here yet.
|
||||
* We don't decode anything from this block.
|
||||
* Watch this space.
|
||||
*
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* TEST: DecodeADFBlockResp()
|
||||
*
|
||||
*/
|
||||
static void test_family2_decode_source_status_resp()
|
||||
{
|
||||
DecodeStatus decode_resp;
|
||||
BrotherSourceStatusResponse adf_resp;
|
||||
|
||||
BrotherEncoderFamily2 encoder(0);
|
||||
|
||||
// SUCCESS status
|
||||
const SANE_Byte *data = (const SANE_Byte *)"\xc2";
|
||||
decode_resp = encoder.DecodeSourceStatusBlockResp (data, 1, adf_resp);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
ASSERT_FALSE(adf_resp.source_ready);
|
||||
|
||||
data = (const SANE_Byte *)"\x80";
|
||||
decode_resp = encoder.DecodeSourceStatusBlockResp (data, 1, adf_resp);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
ASSERT_TRUE(adf_resp.source_ready);
|
||||
|
||||
// Wrong length.
|
||||
decode_resp = encoder.DecodeSourceStatusBlockResp (data, 0, adf_resp);
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_ERROR);
|
||||
|
||||
decode_resp = encoder.DecodeSourceStatusBlockResp (data, 20, adf_resp);
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* TEST: EncodeBasicParameterBlock()
|
||||
*
|
||||
*/
|
||||
static void test_family2_encode_basic_param()
|
||||
{
|
||||
DecodeStatus decode_resp;
|
||||
SANE_Byte data_buffer[1024];
|
||||
size_t ret_length;
|
||||
|
||||
BrotherEncoderFamily2 encoder(0);
|
||||
|
||||
// All defaults.
|
||||
decode_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=100,100\nM=CGRAY\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t)22);
|
||||
ASSERT_EQ(memcmp(test_ret, data_buffer, sizeof(test_ret)), 0);
|
||||
}
|
||||
|
||||
// Different resolutions.
|
||||
encoder.SetRes(200,300);
|
||||
|
||||
decode_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=200,300\nM=CGRAY\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t)22);
|
||||
ASSERT_EQ(memcmp(test_ret, data_buffer, sizeof(test_ret)), 0);
|
||||
}
|
||||
|
||||
// GRAY mode.
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_GRAY);
|
||||
decode_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=200,300\nM=GRAY64\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t )23);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// COLOR mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_COLOR);
|
||||
decode_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=200,300\nM=CGRAY\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t )22);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// GRAY DITHERED mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_GRAY_DITHERED);
|
||||
decode_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=200,300\nM=ERRDIF\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t )23);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// TEXT mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_TEXT);
|
||||
decode_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=200,300\nM=TEXT\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t )21);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// Buffer too short.
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_TEXT);
|
||||
decode_resp = encoder.EncodeBasicParameterBlock (data_buffer, 15, &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_INVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* TEST: EncodeParameterBlock()
|
||||
*
|
||||
*/
|
||||
static void test_family2_encode_param()
|
||||
{
|
||||
DecodeStatus decode_resp;
|
||||
SANE_Byte data_buffer[1024];
|
||||
size_t ret_length;
|
||||
|
||||
BrotherEncoderFamily2 encoder(0);
|
||||
|
||||
// All defaults.
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=100,100\nM=CGRAY\nC=JPEG\nJ=MID\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp(test_ret, data_buffer, sizeof(test_ret)), 0);
|
||||
}
|
||||
|
||||
// Different resolutions.
|
||||
encoder.SetRes(200,300);
|
||||
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=CGRAY\nC=JPEG\nJ=MID\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp(test_ret, data_buffer, sizeof(test_ret)), 0);
|
||||
}
|
||||
|
||||
// Different modes:
|
||||
// GRAY mode.
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_GRAY);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=GRAY64\nC=RLENGTH\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// COLOR mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_COLOR);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=CGRAY\nC=JPEG\nJ=MID\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// GRAY DITHERED mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_GRAY_DITHERED);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=ERRDIF\nC=RLENGTH\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// TEXT mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_TEXT);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=TEXT\nC=RLENGTH\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// Different brightness and contrast, positive and negative.
|
||||
encoder.SetBrightness (-20);
|
||||
encoder.SetContrast (-30);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=TEXT\nC=RLENGTH\n"
|
||||
"B=30\nN=20\nA=0,0,0,0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
encoder.SetBrightness (50);
|
||||
encoder.SetContrast (40);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=TEXT\nC=RLENGTH\n"
|
||||
"B=100\nN=90\nA=0,0,0,0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// Different dimensions
|
||||
encoder.SetScanDimensions (0, 10, 50, 100);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=TEXT\nC=RLENGTH\n"
|
||||
"B=100\nN=90\nA=0,50,10,150\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// ADF duplex
|
||||
encoder.SetScanDimensions (0, 10, 50, 100);
|
||||
encoder.SetSource (BROTHER_SOURCE_ADF_DUPLEX);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=TEXT\nC=RLENGTH\n"
|
||||
"B=100\nN=90\nA=0,50,10,150\nD=DUP\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// Buffer too short.
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, 15, &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_INVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* TEST: EncodeADFBlock()
|
||||
*
|
||||
*/
|
||||
static void test_family2_encode_source_status()
|
||||
{
|
||||
DecodeStatus decode_resp;
|
||||
SANE_Byte data_buffer[1024];
|
||||
size_t ret_length;
|
||||
|
||||
BrotherEncoderFamily2 encoder(0);
|
||||
|
||||
// Standard call.
|
||||
decode_resp = encoder.EncodeSourceStatusBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "D\nADF\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp(test_ret, data_buffer, sizeof(test_ret)), 0);
|
||||
}
|
||||
|
||||
// Buffer too short.
|
||||
decode_resp = encoder.EncodeSourceStatusBlock (data_buffer, 5, &ret_length);
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_INVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Run all the tests.
|
||||
*
|
||||
*/
|
||||
void test_family2 ()
|
||||
{
|
||||
// Decodes.
|
||||
test_family2_decode_session_resp();
|
||||
test_family2_decode_basic_param_resp();
|
||||
test_family2_decode_source_status_resp();
|
||||
|
||||
// Encodes.
|
||||
test_family2_encode_basic_param();
|
||||
test_family2_encode_param();
|
||||
test_family2_encode_source_status();
|
||||
}
|
|
@ -0,0 +1,414 @@
|
|||
/* 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 "brother_mfp_tests.h"
|
||||
#include "../../backend/brother_mfp/brother_mfp-encoder.h"
|
||||
#include "../genesys/minigtest.h"
|
||||
|
||||
/*
|
||||
* TEST: DecodeSessionResp()
|
||||
*
|
||||
*/
|
||||
static void test_family3_decode_session_resp()
|
||||
{
|
||||
DecodeStatus decode_resp;
|
||||
BrotherSessionResponse sess_resp;
|
||||
|
||||
BrotherEncoderFamily3 encoder(0);
|
||||
|
||||
// SUCCESS status
|
||||
const SANE_Byte *data = (const SANE_Byte *)"\x05" "\x10" "\x01" "\x02" "\x00";
|
||||
|
||||
decode_resp = encoder.DecodeSessionResp (data, 5, sess_resp);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
ASSERT_TRUE(sess_resp.ready);
|
||||
|
||||
// BUSY status
|
||||
data = (const SANE_Byte *)"\x05" "\x10" "\x01" "\x02" "\x80";
|
||||
|
||||
decode_resp = encoder.DecodeSessionResp (data, 5, sess_resp);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
ASSERT_FALSE(sess_resp.ready);
|
||||
|
||||
// Length issues
|
||||
data = (const SANE_Byte *)"\x05" "\x10" "\x01" "\x02" "\x20" "\x32";
|
||||
|
||||
decode_resp = encoder.DecodeSessionResp (data, 6, sess_resp);
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_ERROR);
|
||||
|
||||
decode_resp = encoder.DecodeSessionResp (data, 4, sess_resp);
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_ERROR);
|
||||
|
||||
decode_resp = encoder.DecodeSessionResp (data, 0, sess_resp);
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_ERROR);
|
||||
|
||||
// Content problems.
|
||||
const char *content_problems[] = {
|
||||
"\x32" "\x10" "\x01" "\x02" "\x20",
|
||||
"\x06" "\x32" "\x01" "\x02" "\x20",
|
||||
"\x06" "\x10" "\x32" "\x02" "\x20",
|
||||
"\x06" "\x10" "\x01" "\x32" "\x20",
|
||||
"\x06" "\x10" "\x01" "\x02" "\x32",
|
||||
nullptr
|
||||
};
|
||||
|
||||
for (size_t test = 0; test; test++)
|
||||
{
|
||||
decode_resp = encoder.DecodeSessionResp ((const SANE_Byte *)content_problems[test], 5, sess_resp);
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TEST: DecodeBasicParameterBlockResp()
|
||||
*
|
||||
*/
|
||||
static void test_family3_decode_basic_param_resp()
|
||||
{
|
||||
/*
|
||||
* TODO: Nothing to do here yet.
|
||||
* We don't decode anything from this block.
|
||||
* Watch this space.
|
||||
*
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* TEST: DecodeADFBlockResp()
|
||||
*
|
||||
*/
|
||||
static void test_family3_decode_sourcestatus_resp()
|
||||
{
|
||||
DecodeStatus decode_resp;
|
||||
BrotherSourceStatusResponse adf_resp;
|
||||
|
||||
BrotherEncoderFamily3 encoder(0);
|
||||
|
||||
// SUCCESS status
|
||||
const SANE_Byte *data = (const SANE_Byte *)"\xc2";
|
||||
decode_resp = encoder.DecodeSourceStatusBlockResp (data, 1, adf_resp);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
ASSERT_FALSE(adf_resp.source_ready);
|
||||
|
||||
data = (const SANE_Byte *)"\x80";
|
||||
decode_resp = encoder.DecodeSourceStatusBlockResp (data, 1, adf_resp);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
ASSERT_TRUE(adf_resp.source_ready);
|
||||
|
||||
// Wrong length.
|
||||
decode_resp = encoder.DecodeSourceStatusBlockResp (data, 0, adf_resp);
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_ERROR);
|
||||
|
||||
decode_resp = encoder.DecodeSourceStatusBlockResp (data, 20, adf_resp);
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* TEST: EncodeBasicParameterBlock()
|
||||
*
|
||||
*/
|
||||
static void test_family3_encode_basic_param()
|
||||
{
|
||||
DecodeStatus decode_resp;
|
||||
SANE_Byte data_buffer[1024];
|
||||
size_t ret_length;
|
||||
|
||||
BrotherEncoderFamily3 encoder(0);
|
||||
|
||||
// All defaults.
|
||||
decode_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=100,100\nM=CGRAY\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t)22);
|
||||
ASSERT_EQ(memcmp(test_ret, data_buffer, sizeof(test_ret)), 0);
|
||||
}
|
||||
|
||||
// Different resolutions.
|
||||
encoder.SetRes(200,300);
|
||||
|
||||
decode_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=200,300\nM=CGRAY\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t)22);
|
||||
ASSERT_EQ(memcmp(test_ret, data_buffer, sizeof(test_ret)), 0);
|
||||
}
|
||||
|
||||
// GRAY mode.
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_GRAY);
|
||||
decode_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=200,300\nM=GRAY64\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t )23);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// COLOR mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_COLOR);
|
||||
decode_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=200,300\nM=CGRAY\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t )22);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// GRAY DITHERED mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_GRAY_DITHERED);
|
||||
decode_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=200,300\nM=ERRDIF\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t )23);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// TEXT mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_TEXT);
|
||||
decode_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=200,300\nM=TEXT\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t )21);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// Buffer too short.
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_TEXT);
|
||||
decode_resp = encoder.EncodeBasicParameterBlock (data_buffer, 15, &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_INVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* TEST: EncodeParameterBlock()
|
||||
*
|
||||
*/
|
||||
static void test_family3_encode_param()
|
||||
{
|
||||
DecodeStatus decode_resp;
|
||||
SANE_Byte data_buffer[1024];
|
||||
size_t ret_length;
|
||||
|
||||
BrotherEncoderFamily3 encoder(0);
|
||||
|
||||
// All defaults.
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=100,100\nM=CGRAY\nC=JPEG\nJ=MID\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp(test_ret, data_buffer, sizeof(test_ret)), 0);
|
||||
}
|
||||
|
||||
// Different resolutions.
|
||||
encoder.SetRes(200,300);
|
||||
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=CGRAY\nC=JPEG\nJ=MID\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp(test_ret, data_buffer, sizeof(test_ret)), 0);
|
||||
}
|
||||
|
||||
// Different modes:
|
||||
// GRAY mode.
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_GRAY);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=GRAY64\nC=RLENGTH\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// COLOR mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_COLOR);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=CGRAY\nC=JPEG\nJ=MID\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// GRAY DITHERED mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_GRAY_DITHERED);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=ERRDIF\nC=RLENGTH\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// TEXT mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_TEXT);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=TEXT\nC=RLENGTH\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// Different brightness and contrast, positive and negative.
|
||||
encoder.SetBrightness (-20);
|
||||
encoder.SetContrast (-30);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=TEXT\nC=RLENGTH\n"
|
||||
"B=30\nN=20\nA=0,0,0,0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
encoder.SetBrightness (50);
|
||||
encoder.SetContrast (40);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=TEXT\nC=RLENGTH\n"
|
||||
"B=100\nN=90\nA=0,0,0,0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// Different dimensions
|
||||
encoder.SetScanDimensions (0, 10, 50, 100);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=TEXT\nC=RLENGTH\n"
|
||||
"B=100\nN=90\nA=0,50,10,150\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// ADF duplex
|
||||
encoder.SetScanDimensions (0, 10, 50, 100);
|
||||
encoder.SetSource(BROTHER_SOURCE_ADF_DUPLEX);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=TEXT\nC=RLENGTH\n"
|
||||
"B=100\nN=90\nA=0,50,10,150\nD=DUP\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// Buffer too short.
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, 15, &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_INVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* TEST: EncodeADFBlock()
|
||||
*
|
||||
*/
|
||||
static void test_family3_encode_adf()
|
||||
{
|
||||
DecodeStatus decode_resp;
|
||||
SANE_Byte data_buffer[1024];
|
||||
size_t ret_length;
|
||||
|
||||
BrotherEncoderFamily3 encoder(0);
|
||||
|
||||
// Standard call.
|
||||
decode_resp = encoder.EncodeSourceStatusBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "D\nADF\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp(test_ret, data_buffer, sizeof(test_ret)), 0);
|
||||
}
|
||||
|
||||
// Buffer too short.
|
||||
decode_resp = encoder.EncodeSourceStatusBlock (data_buffer, 5, &ret_length);
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_INVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Run all the tests.
|
||||
*
|
||||
*/
|
||||
void test_family3 ()
|
||||
{
|
||||
// Decodes.
|
||||
test_family3_decode_session_resp();
|
||||
test_family3_decode_basic_param_resp();
|
||||
test_family3_decode_sourcestatus_resp();
|
||||
|
||||
// Encodes.
|
||||
test_family3_encode_basic_param();
|
||||
test_family3_encode_param();
|
||||
test_family3_encode_adf();
|
||||
}
|
|
@ -0,0 +1,424 @@
|
|||
/* 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 "brother_mfp_tests.h"
|
||||
#include "../../backend/brother_mfp/brother_mfp-encoder.h"
|
||||
#include "../genesys/minigtest.h"
|
||||
|
||||
/*
|
||||
* TEST: DecodeSessionResp()
|
||||
*
|
||||
*/
|
||||
static void test_family4_decode_session_resp()
|
||||
{
|
||||
DecodeStatus decode_resp;
|
||||
BrotherSessionResponse sess_resp;
|
||||
|
||||
BrotherEncoderFamily4 encoder(0);
|
||||
|
||||
// SUCCESS status
|
||||
const SANE_Byte *data = (const SANE_Byte *)"\x05" "\x10" "\x01" "\x02" "\x00";
|
||||
|
||||
decode_resp = encoder.DecodeSessionResp (data, 5, sess_resp);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
ASSERT_TRUE(sess_resp.ready);
|
||||
|
||||
// BUSY status
|
||||
data = (const SANE_Byte *)"\x05" "\x10" "\x01" "\x02" "\x80";
|
||||
|
||||
decode_resp = encoder.DecodeSessionResp (data, 5, sess_resp);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
ASSERT_FALSE(sess_resp.ready);
|
||||
|
||||
// Length issues
|
||||
data = (const SANE_Byte *)"\x05" "\x10" "\x01" "\x02" "\x20" "\x32";
|
||||
|
||||
decode_resp = encoder.DecodeSessionResp (data, 6, sess_resp);
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_ERROR);
|
||||
|
||||
decode_resp = encoder.DecodeSessionResp (data, 4, sess_resp);
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_ERROR);
|
||||
|
||||
decode_resp = encoder.DecodeSessionResp (data, 0, sess_resp);
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_ERROR);
|
||||
|
||||
// Content problems.
|
||||
const char *content_problems[] = {
|
||||
"\x32" "\x10" "\x01" "\x02" "\x20",
|
||||
"\x06" "\x32" "\x01" "\x02" "\x20",
|
||||
"\x06" "\x10" "\x32" "\x02" "\x20",
|
||||
"\x06" "\x10" "\x01" "\x32" "\x20",
|
||||
"\x06" "\x10" "\x01" "\x02" "\x32",
|
||||
nullptr
|
||||
};
|
||||
|
||||
for (size_t test = 0; test; test++)
|
||||
{
|
||||
decode_resp = encoder.DecodeSessionResp ((const SANE_Byte *)content_problems[test], 5, sess_resp);
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TEST: DecodeBasicParameterBlockResp()
|
||||
*
|
||||
*/
|
||||
static void test_family4_decode_basic_param_resp()
|
||||
{
|
||||
/*
|
||||
* TODO: Nothing to do here yet.
|
||||
* We don't decode anything from this block.
|
||||
* Watch this space.
|
||||
*
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* TEST: DecodeADFBlockResp()
|
||||
*
|
||||
*/
|
||||
static void test_family4_decode_adf_resp()
|
||||
{
|
||||
DecodeStatus decode_resp;
|
||||
BrotherSourceStatusResponse adf_resp;
|
||||
|
||||
BrotherEncoderFamily4 encoder(0);
|
||||
|
||||
// SUCCESS status
|
||||
const SANE_Byte *data = (const SANE_Byte *)"\xc2";
|
||||
decode_resp = encoder.DecodeSourceStatusBlockResp (data, 1, adf_resp);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
ASSERT_FALSE(adf_resp.source_ready);
|
||||
|
||||
data = (const SANE_Byte *)"\x80";
|
||||
decode_resp = encoder.DecodeSourceStatusBlockResp (data, 1, adf_resp);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
ASSERT_TRUE(adf_resp.source_ready);
|
||||
|
||||
// Wrong length.
|
||||
decode_resp = encoder.DecodeSourceStatusBlockResp (data, 0, adf_resp);
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_ERROR);
|
||||
|
||||
decode_resp = encoder.DecodeSourceStatusBlockResp (data, 20, adf_resp);
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* TEST: EncodeBasicParameterBlock()
|
||||
*
|
||||
*/
|
||||
static void test_family4_encode_basic_param()
|
||||
{
|
||||
DecodeStatus decode_resp;
|
||||
SANE_Byte data_buffer[1024];
|
||||
size_t ret_length;
|
||||
|
||||
BrotherEncoderFamily4 encoder(0);
|
||||
|
||||
// All defaults.
|
||||
decode_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=100,100\nM=CGRAY\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t)22);
|
||||
ASSERT_EQ(memcmp(test_ret, data_buffer, sizeof(test_ret)), 0);
|
||||
}
|
||||
|
||||
// Different resolutions.
|
||||
encoder.SetRes(200,300);
|
||||
|
||||
decode_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=200,300\nM=CGRAY\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t)22);
|
||||
ASSERT_EQ(memcmp(test_ret, data_buffer, sizeof(test_ret)), 0);
|
||||
}
|
||||
|
||||
// GRAY mode.
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_GRAY);
|
||||
decode_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=200,300\nM=GRAY64\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t )23);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// COLOR mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_COLOR);
|
||||
decode_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=200,300\nM=CGRAY\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t )22);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// GRAY DITHERED mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_GRAY_DITHERED);
|
||||
decode_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=200,300\nM=ERRDIF\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t )23);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// TEXT mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_TEXT);
|
||||
decode_resp = encoder.EncodeBasicParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "I\nR=200,300\nM=TEXT\n" "\x80";
|
||||
ASSERT_EQ(ret_length, (size_t )21);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// Buffer too short.
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_TEXT);
|
||||
decode_resp = encoder.EncodeBasicParameterBlock (data_buffer, 15, &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_INVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* TEST: EncodeParameterBlock()
|
||||
*
|
||||
*/
|
||||
static void test_family4_encode_param()
|
||||
{
|
||||
DecodeStatus decode_resp;
|
||||
SANE_Byte data_buffer[1024];
|
||||
size_t ret_length;
|
||||
|
||||
BrotherEncoderFamily4 encoder(0);
|
||||
|
||||
// All defaults.
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=100,100\nM=CGRAY\nC=JPEG\nJ=MID\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nS=NORMAL_SCAN\nP=0\n"
|
||||
"G=0\nL=0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp(test_ret, data_buffer, sizeof(test_ret)), 0);
|
||||
}
|
||||
|
||||
// Different resolutions.
|
||||
encoder.SetRes(200,300);
|
||||
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=CGRAY\nC=JPEG\nJ=MID\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nS=NORMAL_SCAN\nP=0\n"
|
||||
"G=0\nL=0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp(test_ret, data_buffer, sizeof(test_ret)), 0);
|
||||
}
|
||||
|
||||
// Different modes:
|
||||
// GRAY mode.
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_GRAY);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=GRAY64\nC=RLENGTH\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nS=NORMAL_SCAN\nP=0\n"
|
||||
"G=0\nL=0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// COLOR mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_COLOR);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=CGRAY\nC=JPEG\nJ=MID\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nS=NORMAL_SCAN\nP=0\n"
|
||||
"G=0\nL=0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// GRAY DITHERED mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_GRAY_DITHERED);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=ERRDIF\nC=RLENGTH\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nS=NORMAL_SCAN\nP=0\n"
|
||||
"G=0\nL=0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// TEXT mode
|
||||
encoder.SetScanMode (BROTHER_SCAN_MODE_TEXT);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=TEXT\nC=RLENGTH\n"
|
||||
"B=50\nN=50\nA=0,0,0,0\nS=NORMAL_SCAN\nP=0\n"
|
||||
"G=0\nL=0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// Different brightness and contrast, positive and negative.
|
||||
encoder.SetBrightness (-20);
|
||||
encoder.SetContrast (-30);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=TEXT\nC=RLENGTH\n"
|
||||
"B=30\nN=20\nA=0,0,0,0\nS=NORMAL_SCAN\nP=0\n"
|
||||
"G=0\nL=0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
encoder.SetBrightness (50);
|
||||
encoder.SetContrast (40);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=TEXT\nC=RLENGTH\n"
|
||||
"B=100\nN=90\nA=0,0,0,0\nS=NORMAL_SCAN\nP=0\n"
|
||||
"G=0\nL=0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// Different dimensions
|
||||
encoder.SetScanDimensions (0, 10, 50, 100);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=TEXT\nC=RLENGTH\n"
|
||||
"B=100\nN=90\nA=0,50,10,150\nS=NORMAL_SCAN\nP=0\n"
|
||||
"G=0\nL=0\nD=SIN\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// Duplex ADF
|
||||
encoder.SetScanDimensions (0, 10, 50, 100);
|
||||
encoder.SetSource (BROTHER_SOURCE_ADF_DUPLEX);
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "X\nR=200,300\nM=TEXT\nC=RLENGTH\n"
|
||||
"B=100\nN=90\nA=0,50,10,150\nS=NORMAL_SCAN\nP=0\n"
|
||||
"G=0\nL=0\nD=DUP\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp (test_ret, data_buffer, sizeof(test_ret) - 1), 0);
|
||||
}
|
||||
|
||||
// Buffer too short.
|
||||
decode_resp = encoder.EncodeParameterBlock (data_buffer, 15, &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_INVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* TEST: EncodeADFBlock()
|
||||
*
|
||||
*/
|
||||
static void test_family4_encode_adf()
|
||||
{
|
||||
DecodeStatus decode_resp;
|
||||
SANE_Byte data_buffer[1024];
|
||||
size_t ret_length;
|
||||
|
||||
BrotherEncoderFamily4 encoder(0);
|
||||
|
||||
// Standard call.
|
||||
decode_resp = encoder.EncodeSourceStatusBlock (data_buffer, sizeof(data_buffer), &ret_length);
|
||||
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
|
||||
|
||||
{
|
||||
const char test_ret[] = "\x1b" "D\nADF\n" "\x80";
|
||||
ASSERT_EQ(ret_length, sizeof(test_ret) - 1);
|
||||
ASSERT_EQ(memcmp(test_ret, data_buffer, sizeof(test_ret)), 0);
|
||||
}
|
||||
|
||||
// Buffer too short.
|
||||
decode_resp = encoder.EncodeSourceStatusBlock (data_buffer, 5, &ret_length);
|
||||
ASSERT_EQ(decode_resp, DECODE_STATUS_INVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Run all the tests.
|
||||
*
|
||||
*/
|
||||
void test_family4 ()
|
||||
{
|
||||
// Decodes.
|
||||
test_family4_decode_session_resp();
|
||||
test_family4_decode_basic_param_resp();
|
||||
test_family4_decode_adf_resp();
|
||||
|
||||
// Encodes.
|
||||
test_family4_encode_basic_param();
|
||||
test_family4_encode_param();
|
||||
test_family4_encode_adf();
|
||||
}
|
|
@ -0,0 +1,251 @@
|
|||
/* 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 "../../include/sane/sanei_debug.h"
|
||||
#include "brother_mfp_tests.h"
|
||||
#include "../../backend/brother_mfp/brother_mfp-encoder.h"
|
||||
#include "../genesys/minigtest.h"
|
||||
|
||||
/*
|
||||
* TEST: BrotherGrayRLengthDecoder()
|
||||
*
|
||||
*/
|
||||
static void test_gray_rlength_no_compress()
|
||||
{
|
||||
BrotherGrayRLengthDecoder decoder;
|
||||
const SANE_Byte *src_data;
|
||||
SANE_Byte dest_data[1024];
|
||||
DecodeStatus res_code;
|
||||
size_t src_data_consumed;
|
||||
size_t dest_data_written;
|
||||
|
||||
/*
|
||||
* Normal decode.
|
||||
*
|
||||
*/
|
||||
src_data = (const SANE_Byte *)"\x04" "ABCDE";
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
strlen((const char *)src_data),
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)6);
|
||||
ASSERT_EQ(dest_data_written, (size_t)5);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "ABCDE", 5), 0);
|
||||
|
||||
// Boundary condition: 1 character only.
|
||||
src_data = (const SANE_Byte *)"\x00" "X";
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
2,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)2);
|
||||
ASSERT_EQ(dest_data_written, (size_t)1);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "X", 1), 0);
|
||||
|
||||
/*
|
||||
* Decodes broken through src exhaustion (fragmentation of input).
|
||||
*
|
||||
*/
|
||||
// Break after length: can't decode: need full miniblock.
|
||||
src_data = (const SANE_Byte *)"\x04";
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
1,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)0);
|
||||
ASSERT_EQ(dest_data_written, (size_t)0);
|
||||
|
||||
// BREAK part way through the data portion: can't decode: need full miniblock.
|
||||
src_data = (const SANE_Byte *)"\x05" "ABC";
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
4,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)0);
|
||||
ASSERT_EQ(dest_data_written, (size_t)0);
|
||||
|
||||
/*
|
||||
* Decodes broken by exhausted output buffer.
|
||||
*
|
||||
*/
|
||||
// BREAK part way through the data portion: can't decode: need full miniblock.
|
||||
src_data = (const SANE_Byte *)"\x05" "MNOPQR";
|
||||
memset(dest_data, 0, sizeof(dest_data));
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
7,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
1,
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)0);
|
||||
ASSERT_EQ(dest_data_written, (size_t)0);
|
||||
}
|
||||
|
||||
static void test_gray_rlength_compression()
|
||||
{
|
||||
BrotherGrayRLengthDecoder decoder;
|
||||
const SANE_Byte *src_data;
|
||||
SANE_Byte dest_data[1024];
|
||||
DecodeStatus res_code;
|
||||
size_t src_data_consumed;
|
||||
size_t dest_data_written;
|
||||
|
||||
/*
|
||||
* Normal decode.
|
||||
*
|
||||
*/
|
||||
src_data = (const SANE_Byte *)"\xfd" "A";
|
||||
memset(dest_data, 0, sizeof(dest_data));
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
strlen((const char *)src_data),
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)2);
|
||||
ASSERT_EQ(dest_data_written, (size_t)4);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "AAAA", 4), 0);
|
||||
|
||||
// Boundary check: minimal compression: 2 chars
|
||||
src_data = (const SANE_Byte *)"\xff" "X";
|
||||
memset(dest_data, 0, sizeof(dest_data));
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
strlen((const char *)src_data),
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)2);
|
||||
ASSERT_EQ(dest_data_written, (size_t)2);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "XX", 2), 0);
|
||||
|
||||
// Upper limit of compression: 0x80 (gives 129 bytes of output)
|
||||
src_data = (const SANE_Byte *)"\x80" "Y";
|
||||
memset(dest_data, 0, sizeof(dest_data));
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
strlen((const char *)src_data),
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)2);
|
||||
ASSERT_EQ(dest_data_written, (size_t)129);
|
||||
|
||||
ASSERT_EQ(strrchr((const char *)dest_data, 'Y'), (const char *)&dest_data[128]);
|
||||
|
||||
/*
|
||||
* Fragmentation due to dest exhaustion. Can't decode: need full miniblock.
|
||||
*
|
||||
*/
|
||||
src_data = (const SANE_Byte *)"\xfd" "Z";
|
||||
memset(dest_data, 0, sizeof(dest_data));
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
strlen((const char *)src_data),
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
1,
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)0);
|
||||
ASSERT_EQ(dest_data_written, (size_t)0);
|
||||
|
||||
/*
|
||||
* Fragmentation due to src exhaustion.
|
||||
* The only case here is that we see the length, but not the
|
||||
* following character so we cannot actually do anything.
|
||||
*
|
||||
*/
|
||||
src_data = (const SANE_Byte *)"\xfd" "A";
|
||||
memset(dest_data, 0, sizeof(dest_data));
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
1,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)0);
|
||||
ASSERT_EQ(dest_data_written, (size_t)0);
|
||||
|
||||
res_code = decoder.DecodeScanData (src_data,
|
||||
2,
|
||||
&src_data_consumed,
|
||||
dest_data,
|
||||
sizeof(dest_data),
|
||||
&dest_data_written);
|
||||
|
||||
ASSERT_EQ(res_code, DECODE_STATUS_GOOD);
|
||||
ASSERT_EQ(src_data_consumed, (size_t)2);
|
||||
ASSERT_EQ(dest_data_written, (size_t)4);
|
||||
|
||||
ASSERT_EQ(memcmp(dest_data, "AAAA", 4), 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Run all the tests.
|
||||
*
|
||||
*/
|
||||
void test_gray_rlength()
|
||||
{
|
||||
test_gray_rlength_no_compress();
|
||||
test_gray_rlength_compression();
|
||||
}
|
Ładowanie…
Reference in New Issue