brother_mfp: start of network driver.

We start with SNMP experiments for button registration and general
network driver framework.
brother_mfp_backend
Ralph Little 2022-11-27 18:04:49 -08:00
rodzic 311a38c76f
commit 45416ffe03
6 zmienionych plików z 512 dodań i 9 usunięć

Wyświetl plik

@ -383,13 +383,14 @@ EXTRA_DIST += bh.conf.in
libbrother_mfp_la_SOURCES = \
brother_mfp/brother_mfp-driver.cpp \
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
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
@ -400,7 +401,7 @@ libsane_brother_mfp_la_LIBADD = $(COMMON_LIBS) libbrother_mfp.la \
../sanei/sanei_usb.lo \
../sanei/sanei_config.lo \
sane_strstatus.lo \
$(USB_LIBS) $(JPEG_LIBS)
$(USB_LIBS) $(JPEG_LIBS) $(SNMP_LIBS)
EXTRA_DIST += brother_mfp.conf.in

Wyświetl plik

@ -145,8 +145,6 @@ public:
}
protected:
static const char *ScanModeToText(BrotherScanMode scan_mode);
BrotherFamily family;
SANE_Word capabilities;
BrotherEncoder *encoder;
@ -197,3 +195,48 @@ private:
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;
};

Wyświetl plik

@ -0,0 +1,318 @@
/* 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"
/*
* Protocol defines.
*
*/
#define BROTHER_USB_REQ_STARTSESSION 1
#define BROTHER_USB_REQ_STOPSESSION 2
#define BROTHER_USB_REQ_BUTTONSTATE 3
#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;
oid anOID[MAX_OID_LEN];
size_t anOID_len = MAX_OID_LEN;
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);
// const char *value = "TYPE=BR;BUTTON=SCAN;USER=\"MYTESTSVR\";FUNC=OCR;HOST=192.168.1.12:54925;APPNUM=3;DURATION=360;";
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;
}
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)
{
return SANE_STATUS_UNSUPPORTED;
}
SANE_Status BrotherNetworkDriver::ReadScanData (SANE_Byte *data, size_t max_length, size_t *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);
}

Wyświetl plik

@ -241,6 +241,22 @@ static Brother_Model models[] =
CAP_BUTTON_HAS_SCAN_IMAGE |
CAP_ENCODING_HAS_JPEG },
{ "Brother", "DCP-1610W", BROTHER_FAMILY_4, 0x04f9, 0x035b,
{ 0, SANE_FIX(211.5), 0 },
{ 0, SANE_FIX(297), 0 },
{ 6, 100, 150, 200, 300, 600, 1200 },
{ 7, 100, 150, 200, 300, 600, 1200, 2400 },
CAP_MODE_COLOUR |
CAP_MODE_GRAY |
CAP_MODE_GRAY_DITHER |
CAP_MODE_BW |
CAP_SOURCE_HAS_FLATBED |
CAP_BUTTON_HAS_SCAN_EMAIL |
CAP_BUTTON_HAS_SCAN_FILE |
CAP_BUTTON_HAS_SCAN_OCR |
CAP_BUTTON_HAS_SCAN_IMAGE |
CAP_ENCODING_HAS_JPEG },
{NULL, NULL, BROTHER_FAMILY_NONE, 0, 0, {0, 0, 0}, {0, 0, 0}, {0}, {0}, 0}
};
@ -291,7 +307,11 @@ static SANE_Device **devlist = NULL;
static const SANE_Range constraint_brightness_contrast = { -50, +50, 1 };
enum BrotherDeviceCommsType
{
BROTHER_DEVICE_COMMS_TYPE_USB,
BROTHER_DEVICE_COMMS_TYPE_NETWORK,
};
static SANE_Status
attach_with_ret (const char *devicename, BrotherDevice **dev)
@ -432,7 +452,115 @@ attach_with_ret (const char *devicename, BrotherDevice **dev)
return SANE_STATUS_GOOD;
}
//
//
//static SANE_Status
//attach_with_ret_network (const char *devicename, Brother_Model *model, BrotherDevice **dev)
//{
// BrotherDevice *device;
// SANE_Status status;
//
// DBG (DBG_EVENT, "attach_with_ret_network: %s\n", devicename);
//
// /*
// * See if we already know about the device.
// *
// */
// for (device = first_dev; device; device = device->next)
// {
// if (strcmp (device->sane_device.name, devicename) == 0)
// {
// if (dev)
// {
// *dev = device;
// }
// return SANE_STATUS_GOOD;
// }
// }
//
// /*
// * Create a new entry for this device.
// *
// */
// device = new BrotherDevice;
// if (!device)
// {
// DBG (DBG_SERIOUS, "attach_with_ret_network: failed to allocate device entry %zu\n", sizeof(*device));
// return SANE_STATUS_NO_MEM;
// }
//
// device->name = strdup (devicename);
// device->sane_device.name = device->name;
// device->sane_device.vendor = "BROTHER";
// device->sane_device.model = model->model;
// device->sane_device.type = "multi-function peripheral";
// device->model = model;
//
// /*
// * Generate a driver for this device.
// *
// */
// device->driver = new BrotherNetworkDriver(devicename, model->family, model->capabilities);
// if (nullptr == device->driver)
// {
// DBG (DBG_SERIOUS, "attach_with_ret_network: failed to create Brother driver: %s\n", devicename);
// return SANE_STATUS_NO_MEM;
// }
//
// /*
// * Create the modes list.
// *
// */
// size_t num_modes = 0;
// if (model->capabilities & CAP_MODE_COLOUR)
// {
// device->modes[num_modes++] = SANE_VALUE_SCAN_MODE_COLOR;
// }
// if (model->capabilities & CAP_MODE_GRAY)
// {
// device->modes[num_modes++] = SANE_VALUE_SCAN_MODE_GRAY;
// }
// if (model->capabilities & CAP_MODE_GRAY_DITHER)
// {
// device->modes[num_modes++] = SANE_VALUE_SCAN_MODE_GRAY_DITHER;
// }
// if (model->capabilities & CAP_MODE_BW)
// {
// device->modes[num_modes++] = SANE_VALUE_SCAN_MODE_LINEART;
// }
//
// /*
// * Create the sources list.
// *
// */
// size_t num_sources = 0;
// if (model->capabilities & CAP_SOURCE_HAS_FLATBED)
// {
// device->sources[num_sources++] = SANE_VALUE_SOURCE_FLATBED;
// }
//
// if (model->capabilities & CAP_SOURCE_HAS_ADF)
// {
// device->sources[num_sources++] = SANE_VALUE_SOURCE_ADF;
// }
// else if (model->capabilities & CAP_SOURCE_HAS_ADF_DUPLEX)
// {
// device->sources[num_sources++] = SANE_VALUE_SOURCE_ADF_SIMPLEX;
// device->sources[num_sources++] = SANE_VALUE_SOURCE_ADF_DUPLEX;
// }
//
// ++num_devices;
// device->next = first_dev;
// first_dev = device;
//
// if (dev)
// {
// *dev = device;
// }
//
// return SANE_STATUS_GOOD;
//}
//
static SANE_Status
attach_with_no_ret (const char *devicename)
@ -836,6 +964,19 @@ SANE_Status sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
sanei_usb_find_devices (model->usb_vendor, model->usb_product, attach_with_no_ret);
}
/*
* Probe for network devices.
*
*/
#if 0
BrotherDevice *device;
attach_with_ret_network ("NetworkDevice", &models[0], &device);
#endif
return SANE_STATUS_GOOD;
}

Wyświetl plik

@ -169,7 +169,7 @@ being searched (in this order).
.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), 5 (DETAIL) and 6 (DEBUG). Selecting 5 or 6 will generate
2 (SERIOUS), 3 (WARNINGS), 4 (EVENT), 5 (DETAIL) and 6 (DEBUG). Selecting 5 or 6 will generate
a large amount of output.
@ -182,7 +182,7 @@ getting a good head start on this process and for inspiring me to write this bac
.TP
.I Various GitLab users
For their help in checkout out models of devices that I do not have access to and patiently
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!