D-Link DNS-323 as print and scan server (part 3)

Putting it all together.

In part 1 of this series I wrote how I hooked up my printer and scanner to the DNS-323 box, used the out-of-the-box printer services and installed sane for scanner service. In part 2 I enabled local printing directly from the NAS box. To use this for making photocopies without additional PC I looked at KScannerButtons, tried porting it to optware, but it didn’t recognize any button presses on my epson scanner. Porting scanbuttond to optware solved that issue. (You can download my package here, and the source here.)

So, I can detect button presses on the scanner, I can print the output. Now, we need to scan an image and transform it for printing. Here’s one way of doing it:

  1. scanimage --device-name <scanner-device-name> --format tiff --mode Gray --quick-format A4 --resolution 600 > scan.tiff
  2. /opt/bin/tiff2ps* -z -w 8.27 -h 11.69 scan.tiff > scan.ps
  3. cat scan.ps | gs -r300 -q -dNOPAUSE -dBATCH -dNOMEDIAATTRS -sDEVICE=pbmraw -sOutputFile=scan.pbm -
  4. nice -n -10 /opt/lib/cups/filter/pbmtospl2 -P /opt/share/cups/model/samsung/ml2010de.ppd -p A4 scan.pbm > scan.spl2
  5. /sys/crfs/LPRng/lpr scan.spl2

The scanner-device-name can be obtained through sane-find-scanner.

While this approach worked well with the align.ps test document from openprinting.org, with a scanned tiff image, ghostscript takes ages for converision. So, I thought, perhaps there is some room for optimization in conversion from tiff to ps to pbm to spl2. I installed ImageMagik to convert from tiff to pbm directly. Still, a conversion of a tiff that took 1 minute 14 seconds on my AMD Athlon XP home PC did not finish on the DNS323 in a quarter of an hour. From looking at /proc/cpuinfo, I suppose that that is to be expected: The home PC has slightly more than 4K bogomips, the DNS323 has slightly more than 300. The bottom line seems to be: The DNS323 is just not made for number crunching.

Even the roundabout 75 seconds on the home PC seems close to the maximum tolerable delay between scanning and printing. Since there’s no way of getting anywhere near that number, no matter what, I needed do something simpler. Because I’m already using pbmtospl2 the natural thing to do is scan to pbm directly. That is actually possible, even if scanimage only lists tiff and pnm as available formats. Without the “format” parameter, scanimage will select the output file type based on the “mode” parameter. The “mode” parameter governs the type of scan as in colour, grayscale, or lineart scan. With the scanimage binary available from the optware repository, a mode of “Binary” creates a pbm image. And that can be printed very quickly. Obviously, a lineart scan is of limited quality. For copying a printed letter, however, it seems quite sufficient. The much longer delay involved in higher quality copies are such that I can easily boot up my home PC in that time and launch the copy there with the required processing happening on the faster CPU. So my /opt/etc/scanbuttond/buttonpress.sh, now, looks like this:

#!/bin/sh
##exec >/opt/tmp/buttonpress.sh.log 2>&1
##set -x

# This script is started by scanbuttond whenever a scanner button has been pressed.
# Scanbuttond passes the following parameters to us:
# $1 ... the button number
# $2 ... the scanner's SANE device name, which comes in handy if there are two or
# more scanners. In this case we can pass the device name to SANE programs
# like scanimage.

TMPDIR="/opt/tmp"
TMPFILE1="${TMPDIR}/scan.tiff"
TMPFILE2="${TMPDIR}/scan.ps"
TMPFILE3="${TMPDIR}/scan.pbm"
TMPFILE4="${TMPDIR}/scan.spl2"
LOCKFILE="${TMPDIR}/copy.lock"

case $1 in
1)
echo "button 1 has been pressed on $2"
;;
2)
echo "button 2 has been pressed on $2"
if [ -f $LOCKFILE ]; then
echo "Error: Another scanning operation is currently in progress"
exit
fi
touch $LOCKFILE
rm -f $TMPFILE1 $TMPFILE2 $TMPFILE3 $TMPFILE4
scanimage --device-name $2 --mode Binary --quick-format A4 \
--resolution 600 > $TMPFILE3
nice -n -10 /opt/lib/cups/filter/pbmtospl2 -P \ /opt/share/cups/model/samsung/ml2010de.ppd -p A4 $TMPFILE3 > $TMPFILE4
/sys/crfs/LPRng/lpr $TMPFILE4
rm -f $LOCKFILE
# rm -f $TMPFILE1 $TMPFILE2 $TMPFILE3 $TMPFILE4
;;
3)
echo "button 3 has been pressed on $2"
;;
4)
echo "button 4 has been pressed on $2"
;;
esac

One more thing struck me, though: The disks in my NAS box didn’t seem to spin down anymore. This I presume was due to scanbuttond needing to poll the scanner over and over again. My scanner, however, is turned off most the time, and the ventilation situation of the spot where I run my DNS323 doesn’t really allow for the extra heat of running the disks all the time (let alone the extra noise). To work around that, scanbuttond should only be running when the scanner is turned on. Enter hotplug to the rescue. Rather than starting scanbuttond and xinetd from standard init scripts in /mnt/HD_a2/fun_plug.d/start, I decided to patch /etc/hotplug/usb.agent and let hotplug do its work. So, I removed the executable bits from the start scripts for xinetd and scanbuttond and instead implemented this start script:

#!/bin/sh

OW_BINDIR=/opt/bin
DIFFFILE=/mnt/HD_a2/fun_plug.d/start/usb.agent.diff

hpp_start() {
if [ -x "${OW_BINDIR}/patch" ]; then
if [ -r "$DIFFFILE" ]; then
echo "patching /etc/hotplug/usb.agent ... "
cd /
${OW_BINDIR}/patch -r /opt/tmp/hpp.rej -N -t -p1 <$DIFFFILE
else
echo "ERROR: patch file not found"
fi
else
echo "ERROR: patch command not found or not executable"
fi

# if scanner was already turned on during boot, hp won't have done
# anything and will not pick up on it's own
SCANNER=`${OW_BINDIR}/sane-find-scanner | grep ^found`
if [ ! "x${SCANNER}" = "x" ]; then

PATH=/opt/bin:/opt/sbin:/mnt/HD_a2/fun_plug.d/bin:\
/mnt/HD_a2/fun_plug.d/sbin:"${PATH}"\
sh /mnt/HD_a2/fun_plug.d/start/05xinetd.sh start

PATH=/opt/bin:/opt/sbin:/mnt/HD_a2/fun_plug.d/bin:\
/mnt/HD_a2/fun_plug.d/sbin:"${PATH}"\
sh /mnt/HD_a2/fun_plug.d/start/06scanbuttond.sh start
fi

}

hpp_stop() {
# make sure xinetd and scanbuttond are stopped even if the dns323 is
# stopped with the scanner still attached
PATH=/opt/bin:/opt/sbin:/mnt/HD_a2/fun_plug.d/bin:/mnt/HD_a2/fun_plug.d/sbin:"${PATH}" \

sh /mnt/HD_a2/fun_plug.d/start/05xinetd.sh stop
PATH=/opt/bin:/opt/sbin:/mnt/HD_a2/fun_plug.d/bin:/mnt/HD_a2/fun_plug.d/sbin:"${PATH}" \

sh /mnt/HD_a2/fun_plug.d/start/06scanbuttond.sh stop
}

case "$1" in
start|'')
hpp_start
;;
stop)
hpp_stop
;;
*)
echo "Usage: $0 start"
;;
esac

This script applies a patch to /etc/hotplug/usb.agent. To do that, you need patchutils from optware (the “patch” package doesn’t seem to work the way I’m used to). The script also starts xinetd and scanbuttond if the scanner is already attached, because hotplug has already missed the event. This is the case when the scanner is attached and turned on during the DNS323’s boot process. The start script here only patches hotplug after it has run during boot and will make hotplug do the right thing after it has run, but it needs to take care of what happened before, too. It also needs to stop xinetd and scanbuttond on shutdown, because hotplug might not, if the NAS device is shut down with the scanner still turned on. The patch to go with this script is this (watch out, the blog messes up the layout. In the block of lines starting with a “+” there should be no lines not starting with it. If there are, they need to be appended to the previous line):

--- /etc/hotplug/usb.agent 2005-12-27 08:46:09.000000000 +0100
+++ /mnt/HD_a2/usb.agent.bak 2008-04-28 08:43:59.000000000 +0100
@@ -58,6 +58,21 @@
cd /etc/hotplug
. ./hotplug.functions

+## echo "$ACTION - $PRODUCT - $INTERFACE - $TYPE" >>/opt/tmp/usb.hp.out
+## echo "arg1: $1" >>/opt/tmp/usb.hp.out
+if [ "$PRODUCT" = "4b8/10b/104" ]; then
+ if [ "$ACTION" = "add" ]; then
+## echo "Detected Scanner, starting scanbuttond" >>/opt/tmp/usb.hp.out
+ PATH=/opt/bin:/opt/sbin:/mnt/HD_a2/fun_plug.d/bin:/mnt/HD_a2/fun_plug.d/sbin:"${PATH}" sh -x /mnt
/HD_a2/fun_plug.d/start/05xinetd.sh start ## >>/opt/tmp/usb.hp.out
+ PATH=/opt/bin:/opt/sbin:/mnt/HD_a2/fun_plug.d/bin:/mnt/HD_a2/fun_plug.d/sbin:"${PATH}" sh -x /mnt
/HD_a2/fun_plug.d/start/06scanbuttond.sh start ## >>/opt/tmp/usb.hp.out
+ elif [ "$ACTION" = "remove" ]; then
+## echo "Detected Scanner removal, stopping scanbuttond" >>/opt/tmp/usb.hp.out
+ PATH=/opt/bin:/opt/sbin:/mnt/HD_a2/fun_plug.d/bin:/mnt/HD_a2/fun_plug.d/sbin:"${PATH}" sh -x /mnt
/HD_a2/fun_plug.d/start/06scanbuttond.sh stop ## >>/opt/tmp/usb.hp.out
+ PATH=/opt/bin:/opt/sbin:/mnt/HD_a2/fun_plug.d/bin:/mnt/HD_a2/fun_plug.d/sbin:"${PATH}" sh -x /mnt
/HD_a2/fun_plug.d/start/05xinetd.sh stop ## >>/opt/tmp/usb.hp.out
+ fi
+fi
+
+
#DEBUG=yes export DEBUG #+Wilson11072003

# generated by modutils, for current 2.4.x (and later) kernels

To find the right USB product ID for your scanner, look at /proc/bus/usb/devices when your scanner is attached and powered on. Note, too, how the start script relies on the 05xinetd.sh and 06scanbuttond.sh to be present. Don't remove them completely. My 06scanbuttond.sh looks like this:

#!/bin/sh

OW_BINDIR=/opt/bin

scanbuttond_start() {
if [ -x "${OW_BINDIR}/scanbuttond" ]; then
echo "Starting scanbuttond... "

${OW_BINDIR}/scanbuttond
else
echo "ERROR: ${OW_BINDIR}/scanbuttond not found or not executable"
fi
}

scanbuttond_stop() {
killall scanbuttond
}

scanbuttond_status() {
if [ -n "$(pidof scanbuttond)" ]; then
echo "running"
else
echo "stopped"
fi
}

case "$1" in
stop)
scanbuttond_stop
;;
restart)
scanbuttond_stop
sleep 1
scanbuttond_start
;;
status)
scanbuttond_status
;;
start|'')
scanbuttond_start
;;
*)
echo "Usage: $0 start|stop|restart|status"
;;
esac

To play it absolutely safe, you may also want to add xinetd and scanbuttond to your cleanboot.sh script in /mnt/HD_a2/fun_plug.d/share/cleanboot. Find the part that looks like this:

# kill daemons
/bin/kill -9 $(pidof mt-daapd) $(pidof ftpd) $(pidof pure-ftpd) \
$(pidof telnetd) $(pidof dropbear) $(pidof svnserve) \
$(pidof smbclient) $(pidof smbd) $(pidof nmbd) \
$(pidof wget) $(pidof btget) $(pidof sftp-server) \
$(pidof SyncMms) $(pidof getMsg) $(pidof lpd) \
$(pidof upnp) $(pidof rsyncd) $(pidof unfsd)

To the last line of the "kill" command, add " $(pidof xinetd) $(pidof scanbuttond)

If you have no idea what I'm talking about, reread the DNS-323 wiki, because you will absolutely want cleanboot.

Tagged , , , , , ,

10 thoughts on “D-Link DNS-323 as print and scan server (part 3)

  1. Great info! I am curious, do you think it is possible to have something scanned from a printer directly and stored in a folder on the DNS-323?

    • guillaume says:

      Hi shipiboconibo,

      did you manage to make it working ? if yes, could you send me the script you are using please ? I have a samsung scx-3205 and just want the “press and scan” in the dns-323 folder function.

      thx a million in advance

  2. Hi shipiboconibo,
    that should be even easier, because it would save you the step of converting from whatever image format you scan as to the raster format your printer understands (of course, my example with spl2 does not apply to everybody. People with native postscript printers might be far better off).

    To just store the files, all you would need to is edit your /opt/etc/scanbuttond/buttonpress.sh. You would replace the following lines:

    scanimage –device-name $2 –mode Binary –quick-format A4 \
    –resolution 600 > $TMPFILE3
    nice -n -10 /opt/lib/cups/filter/pbmtospl2 -P \ /opt/share/cups/model/samsung/ml2010de.ppd -p A4 $TMPFILE3 > $TMPFILE4
    /sys/crfs/LPRng/lpr $TMPFILE4

    Basically, you’d remove all but the first line and change the definition of TMPFILE3 (further up) to something more clever inside an existing folder on your DNS323 (e. g. /mnt/HD_a2/). To be able to do this several times and keep all your files, the easiest approach will probably be to incorporate the current timestamp into the file name.

    Cheers,
    Karl.

    • bodbod says:

      hi Karl,

      sorry to annoy you with this, I presume it is a long time you haven’t looked at your prior workings but would it be possible that you explain better the part for the script regarding the above request with the scanned files stored directly to the DNS. As well, will this work with Fun plug 5.0 as time has passed since you created your first script.

      I have a samsung SCX-3205 (printer/scanner) and just want the scan function saving automatically files to the DNS-323. My DNS-323 is running with Fun plug 5.0.

      PS : I don’t understand why shareport has not been designed to work for scanning as well.

      much appreciated

      • Hi,

        I _think_ it should work with 5.0, too … but not sure

        as for the script changes … the following lines scan and print

        scanimage –device-name $2 –mode Binary –quick-format A4 \
        –resolution 600 > $TMPFILE3
        nice -n -10 /opt/lib/cups/filter/pbmtospl2 -P \ /opt/share/cups/model/samsung/ml2010de.ppd -p A4 $TMPFILE3 > $TMPFILE4
        /sys/crfs/LPRng/lpr $TMPFILE4

        If you only want to scan to file, you only need the first command from scanimage to $TMPFILE3
        Like I was writing, you want to make sure TMPFILE3 has a value that works for multiple subsequent scans

  3. […] other thing was that my scan server setup no longer worked when turning on the scanner after booting the DNS-323. Detection of devices after […]

  4. Anatoly says:

    Hi, great info thanks!
    Question: how did you connected both printer and scanner, the device has only 1 usb port… did you used usb hub for that?

  5. Bob says:

    Hi,

    Really useful information. Thanks to this site I was able to setup my printer and scanner.

    Now, I am trying to setup auto-scanning feature, but I can figure out how you connected xinetd and scanbuttond.

    Will it be possible for you to share you scanbuttond.sh and xinetd.sh?

    Thanks,

    • scanbutton.sh is already posted above
      I have this for xinetd
      # more fun_plug.d/start/05xinetd.sh

      #!/bin/sh

      OW_SBINDIR=/opt/sbin

      xinetd_start() {
      if [ -x “${OW_SBINDIR}/xinetd” ]; then
      echo “Starting inetd… ”
      ${OW_SBINDIR}/xinetd
      else
      echo “ERROR: inetd not found or not executable”
      fi
      }

      xinetd_stop() {
      killall xinetd
      }

      xinetd_status() {
      if [ -n “$(pidof xinetd)” ]; then
      echo “running”
      else
      echo “stopped”
      fi
      }

      case “$1″ in
      stop)
      xinetd_stop
      ;;
      restart)
      xinetd_stop
      sleep 1
      xinetd_start
      ;;
      status)
      xinetd_status
      ;;
      start|”)
      xinetd_start
      ;;
      *)
      echo “Usage: $0 start|stop|restart|status”
      ;;
      esac

Leave a reply to guillaume Cancel reply