Tag Archives: fun_plug

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 , , , , , ,

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

Even if I feel like doing too many things at the same time that has never stopped me playing around with a new gadget. This time I’ve added the D-Link DNS-323 NAS device to my home office so I can have automatic, reliable backups soon. The device itself is really cool, with some nice services (e. g. an iTunes server) and a USB port for hooking up external devices. Adding a printer there turns the box into a print server. The most important feature to me for picking this product from the range of comparable products, though, was its openness. There is no need to install any proprietary software on the client, and it runs a Linux kernel, which makes it really open for software extension.

The print server was absolutely a feature I wanted to use. So I hooked up my Samsung ML 2010 printer to the USB port of the NAS device, changed my printer definition on my gutsy clients to the samba queue “lp” on the IP address of the DNS-323, and lo and behold: Printing worked out of the box. (This is making a long story short because printing did not work from my laptop due to an average of 60% packet on the powerline home link between the WLAN access point and the gigabit network hosting the DNS-323. But that was fixed by adding two separate power outlets.) I read that the 1.4 version of the firmware fixes an issue with the disks not spinning down when using the print server alongside with UTF8 issues and installed that.

What of the scanner now? Leave that attached to the home PC? Of course not! But as there’s no scanner service running on the box as it comes off the shelf, this started my quest for how to extend the services on the DNS-323.

Definetely the most important resource I found is the DNS-323 wiki. It has loads of information, howtos, forums, etc. Basically, for extending the device there are three options documented on that site:

  1. Use a fun_plug script to start up services after the box itself has started,
  2. Install Linux into a chroot’ed environment,
  3. Flash the device to run Linux natively.

Variant 3 definetely looked like it would be beyond my hardware modding skills or ambitions (you first need a serial port). Variant 2 still looked too complicated for my taste. So, I started with the fun_plug. On the wiki there are links to a ready-to-use fun_flug framework, called ffp. First I installed version 0.5 beta and it looked quit good. However, I soon found that it didn’t have nearly as much additional software pre-compiled for the box’s ARM processor as I was hoping for. There is, however, the optware project originally targeted at Linksys routers which has a considerable number of software packages ready and helpful instructions for adding further software. Optware recommends using the stable version 0.4 of ffp. That is because that uses libraries provided by the firmware in a number of instances where 0.5 brings its own libraries. That in turn saves some disk access, and as I decided only to use ffp for providing a mechanism to start services, that’s fine for me.

After bootstrapping the optware framework (again see the DNS-323 wiki), I installed the sane-backends package, configured saned.conf to allow network access from my local network, started the daemon, configured sane on my clients to query the DNS-323 … and could scan. At first, the sane client would always ask me to select from two scanners. That was because my epson scanner is served by two variant epson drivers for sane. To solve that, I edited sane’s dll.conf on the DNS-323 and made sure of the two lines “epson” and “epson2” only one was active by commenting the other with a “#”.

Then I needed a way to start the sane service automatically, so here’s what I added to the fun_plug.d/start directory:

1. A link to /opt/etc/init.d/S01sane-backends for adding the sane-port definition to /etc/services on each reboot. Make sure that script is executable: ln -s /opt/etc/init.d/S01sane-backends /mnt/HD_a2/fun_plug.d/start/04sane-backends.sh

2. A script to start xinetd (which can be installed from the optware repository) 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

That’s that. Are we done? Not quite, because now that I can scan and print without using my home PC, I want to be able to make photocopies without PC, too.
But that’s a topic for my next post.

Tagged , , , , ,