[sane-devel] Interactive use of scanner buttons

Paul Wolneykien manowar at altlinux.org
Wed Dec 8 18:23:19 GMT 2021


3 декабря 2021 г. 19:00:25 GMT+03:00, Paul Wolneykien
<manowar at altlinux.org> пишет:
>В Fri, 03 Dec 2021 10:34:05 -0500
>ryniker at ryniker.org пишет:
>> A callback mechanism provides a framework that can naturally avoid
>> missed button events, and can support variations such as capture of
>> "button down" and "button release" events without a requirement for
>> the program with physical access to the hardware to maintain state
>> information until a suitable poll operation is received.
>> 
>> A callback design is better able to support multiple
>> buttons. Applications have less need for complex polling operations
>> (three buttons... which was pressed first?) 
>
>  Then, I'll try to experiment this way with my scanner.

  I think we have a problem with concurrent SANE access.

  First of all, the USB abstraction in SANE seems to be thread unsafe:
at least the USB read timeout is set separately from read with
sanei_usb_set_timeout() while the actual reading is done with
sanei_usb_read_*(). With libusb_timeout being a global variable in
sanei_usb.c I don't understand is it possible to work even with two
different devices (scanners) from the same app in parallel?

  And what about concurrent calls to sane_control_option(),
sane_start() related to the same device from the same app?
It might be possible to synchronize (enqueue) these calls with
saned daemon, but in the simplest local-running case they seem to be
unsynchronized... Is that true?

  Secondly. With the notification callback scheme we've discussed
earlier (above), it's important not to make the notification calls come
from "nowhere" (a separate thread spawned in the backend). That was
really wrong. The scanning application should explicitly maintain all
the threads that can call its own functions. And there is a known
solution to this problem in libusb: the libusb_handle_events*() set of
functions. However, this approach is really a lighter version of
polling: a polling of the internal state without sending any packets
over USB. We can call this a "software polling" meaning no regular
signals are sent over the wire.

  So, if we would even try to add a sane_handle_events() in SANE it
would still be a polling solution, a solution requiring polling
procedure in a single-threaded frontend as we can't safely access two
USB endpoints in parallel with SANE.

  Then, a question arise: can we get a software polling with the
present SANE API? And again I think we can.

  With adding the new option capability

+ #define SANE_CAP_EVENT

  we can mark options which state is safe to be asked as frequently as
you want. Technically this can be achieved by using
sanei_usb_read_int() on scanners with interrupt endpoint for buttons:
that function doesn't sent anything to the device but just checks the
state of the internal queue for the presence of any already received
data (that is pushed by the scanner to the PC).

  Moreover, reading a SANE_CAP_EVENT option shouldn't just return a
"now" value --- it should return the next available value from the
event queue, as a number of events could have been received by the
time of the read. It should not be "the button is down (up) now at
the moment you ask" as it is now with button options.

  Having an event queue is the useful approach to work with events,
but only if you have a way to reset the queue and start over: i. e. if
you can throw away meaningless events from the past. And that's also
can be naturally done with the present API: invocation of
SANE_ACTION_SET_VALUE against the event option should do the trick.

  What about the network (remote scanner) case? I think, that in that
case, a regular polling of SANE_CAP_EVENT options can be done by saned
daemon itself, with some reasonable (and configured) period. In order
to keep it single-threaded the daemon should stop this polling on
reception of a command from the remote frontend (and then, to start it
over being idle again). Then, in the case of an event being read the
daemon should immediately pass it further to the frontend's network
client part, where it should be appended to the internal queue. The
frontend polling procedure would work with that queue under the hood
and wouldn't pollute the network with "read-read-read" commands.

  Actually, the network pollution is still possible with that scheme
but only with the packets coming from (!) the remote scanner to PC ---
from some mad scanner that is trying to DDoS us! :-)

  Any comments about this update?



More information about the sane-devel mailing list