Howto get Asterisk with mISDN V2 and Linux Call Router running on debian lenny


Update 2009-03-31: provide signed archive with archive key, add udev rules, add /etc/modules entries, add amd64.
Update 2009-04-05: typos fixed

This is a short howto how I built the debian patches and how you can — as a user — install everything needed for mISDN version 2 and Linux Call Router (LCR) with asterisk chan_lcr running on debian lenny.

I’m providing debian packages for Kernel (v 2.6.28.5), an updated zaptel (debian lenny zaptel doesn’t compile with newer kernels and zaptel wctdm uses some settings for analogue phones that don’t work with german and austrian phone like the “R”-key or optional pulse dialling), finally I’m providing a slightly patched asterisk for larger buffer sizes when playing long tones, LCR and misdnv2user packages originally built by Joerg Dorchain. My misdnv2user is the same as Joergs. The lcr package contains my bug-fix for DTMF digits A-F (also in Joergs packages now) which don’t work in upstream LCR version 1.3 and an updated /etc/init.d/lcr for querying the status of lcr.

I’m also providing source packages, except for the kernel — the kernel is stock kernel.org 2.6.28.5 configured for use of mISDN. The kernel was built using debians make-kpkg from the kernel-package debian package. And the config used for building the kernel is in the binary package.

I hope I can contribute something in order to get mISDN V2 and LCR into debian… in the meantime others may want to uses these on debian stable.

Installation

apt-get install vim less ssh ntp
apt-get install python-dev openbsd-inetd postfix madplay

Add following lines to /etc/apt/sources.list:

deb http://project.runtux.com/asterisk/debian/ lenny main
deb-src http://project.runtux.com/asterisk/debian/ lenny main

If you want to avoid warnings about an untrusted archive key from apt, you should import the following archive key. Save the key to a file and then issue the command
apt-key add file

—–BEGIN PGP PUBLIC KEY BLOCK—–
Version: GnuPG v1.4.9 (GNU/Linux)

mQENBEnREAIBCADM8+KpoC/HJUCEsx8KZhGgsX/G3ouR4/xkgIuIPgz+t6JoTisj
9QmymDZKUXSy04WmbLjU/088xD5A9ukOEYxoFCGqwWf1tPOKqN1oKpVCkjJb8Dht
vvebqOCzJSV0nfqmIfkpbX+6dUssx+9u0BiFK3aj/GilkEloZl2g+vIT6fveJtKE
qmxz19vL516TDhsbsv3/AKfNKc7QRpsgvPmnNE2IL0CTgQYs26WtnJASlu1MQpwo
Qfb1PrO7ufq9eO58HjEBdfbSNjalQjVj7vLvE4GQglHULO500H9UlfOm2zpO0Vzs
5lGGbwLJdTpAS3HIRhQAW0pueRsQ8zagMn5lABEBAAG0OFJhbGYgU2NobGF0dGVy
YmVjayAoRGViaWFuLVBhY2thZ2UtS2V5KSA8cnNjQHJ1bnR1eC5jb20+iQE2BBMB
AgAgBQJJ0RACAhsDBgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQ5CizCR9G97ah
pAf/eLRYtPVs1apI3+AVi//8y1/r6uL+IxI/Tlt53jCtX/dy3Q3FeAEJt/7fbvcW
TBDnP5K8vWaYUlHHaz+6lbcQyV/KAH4LKJEKkyoINc9ytG1qEG6z8NPfDmKiEluy
HksgLpAqUBrdZy46iWQhcg7f3fpcUIsHHcXrOd2Ip5G9DL2q4/UoRrhBhHC3GNX7
ERaeAKZTF1JRaVN6KSWPC2+yaNmuGn1yoSChG0Q/bBTgzv2fm9Jzvok546f9LE0q
k2q5PvjlUSMGHHojTzzR6tGhnbw5mOfyMUDDs5LuAN1aWbDatepJgiC+dYasprQ5
pZygpoCASqIhWjjCZd3XI5mAEIhGBBARAgAGBQJJ0nZlAAoJEIO0FkDz/lcw0xYA
njBSGef/4KhZpuspIh6WnLM7ORKNAKCw28et9bUoaGu4ESRpIwtwj4asQoicBBAB
AgAGBQJJ0ncuAAoJEJWCQpSoBzk1hpcD/2KXiuvE2Nm0oOi0jBVEjT/Tu/GGkG5m
lf97/I6TMcJxlMpeBlv9SiJD+/BBQo0MGMxmkCwU4t+eBCBsCVcr/bJnrlrKa4Ab
9SR9WQ8PGrSQ+AwMePCDKngqFd5EERz8bxz4sZKGCxn9JVRQOGp03eKSGDG/Yh0v
FY3v7nV0BUaE
=mPtt
—–END PGP PUBLIC KEY BLOCK—–

Then install:

apt-get update
apt-get install linux-headers-2.6.28.5-i686 linux-image-2.6.28.5-i686 
    asterisk zaptel lcr zaptel-modules-2.6.28.5-i686

If you’re on the amd64 architecture, you should replace i686 in the packages above with amd64.

and optionally (for misdn_info):

apt-get install misdnv2user

Edit /etc/default/asterisk and set RUNASTERISK=yes. Then make several directories (should be done by a future version of the lcr package):

mkdir /var/run/lcr
chown asterisk.asterisk /var/run/lcr
mkdir /var/log/lcr
chown asterisk.asterisk /var/log/lcr

I’ve also made a start-script for lcr (for use as /etc/init.d/lcr) ,
downloadable at http://project.runtux.com/asterisk/init.d:lcr
this probably should also be part of the lcr package.

Config file examples used for lcr — these pass
everything to asterisk. File /etc/lcr/interface.conf:

[Ext1]
portnum 0
ptp
nodtmf

[Ext2]
portnum 1
ptp
nodtmf

[Int1]
portnum 2
nt
ptp
nodtmf

[Int2]
portnum 3
nt
ptp
nodtmf

I’m using a Beronet 4 port ISDN card, your config will probably differ: This system only expects incoming calls and needs to check on which line a call comes in. So I distinguish all external interfaces as separate interfaces of LCR. I also need to check an interface by calling out via that interface, you probably would want to make all external ports a trunk by grouping them into one LCR interface.

And the routing config needs to match your interface definition. This config will pass all calls — if asterisk is running — to asterisk. If asterisk isn’t running, I’m calling a test application (untested). The context in asterisk will be the interface name. Again, if you’re using a trunk here, be sure to match the routing config with your interface config. /etc/lcr/routing.conf:

[main]
remote=asterisk interface=Ext1 : remote application=asterisk
remote=asterisk interface=Ext2 : remote application=asterisk
remote=asterisk interface=Int1 : remote application=asterisk
remote=asterisk interface=Int2 : remote application=asterisk
default                        : efi

Update /etc/modules to include the following lines (the command appends the lines between cat and EOF):

cat >> /etc/modules << EOF
mISDN_core debug=0x0
mISDN_dsp debug=0x0 options=0x0
hfcmulti debug=0x0
EOF

Linux udev must be configured to correctly set the user for the isdn device(s):

cat > /etc/udev/rules.d/91-isdn.rules << EOF
ACTION!=”add|change”, GOTO=”permissions_end”

KERNEL==”mISDN*”,       GROUP=”dialout”

LABEL=”permissions_end”
EOF

After a reboot asterisk and lcr should be running.

Building

Getting kernel:

wget http://kernel.org/pub/linux/kernel/v2.6/linux-2.6.28.tar.bz2
wget http://kernel.org/pub/linux/kernel/v2.6/linux-2.6.28.tar.bz2.sign
wget http://kernel.org/pub/linux/kernel/v2.6/patch-2.6.28.5.gz
wget http://kernel.org/pub/linux/kernel/v2.6/patch-2.6.28.5.gz.sign

For compilation (zlib isn’t checked by make-kpkg!):

apt-get install kernel-package bzip2 libncurses5-dev zaptel-source 
    zlib1g-dev fakeroot

Compile Kernel:

tar xvf linux-2.6.28.tar.bz2
cd linux-2.6.28
zcat ../patch-2.6.28.5.gz | patch -N -p1 | less 2>&1
cp /boot/config-2.6.28.5-i686 .config
make oldconfig
make menuconfig # just to be sure

For amd64:

make-kpkg –append-to-version -amd64 –revision 2.6.28.5.1.rsc –us 
    –uc –initrd –rootcmd fakeroot binary > m.out 2> m.err

For i686:

make-kpkg –append-to-version -i686 –revision 2.6.28.5.1.rsc –us 
    –uc –initrd –rootcmd fakeroot binary > m.out 2> m.err

The following doesn’t seem to work although zaptel is installed:
probably need to unpack /usr/src/zaptel.tar.bz2 into
/usr/src/modules/zaptel (tar file contains modules directory!)
this would save us from the m-a a-i step below. amd64:

make-kpkg –append-to-version -amd64 –revision 2.6.28.5.1.rsc –us 
    –uc –initrd –rootcmd fakeroot modules > mo.out 2> mo.err
cd ..

For i686:

make-kpkg –append-to-version -i686 –revision 2.6.28.5.1.rsc –us 
    –uc –initrd –rootcmd fakeroot modules > mo.out 2> mo.err
cd ..

Make a debianized zaptel for new kernel:

apt-get install devscripts libnewt-dev quilt libusb-dev asciidoc
svn checkout http://svn.digium.com/svn/zaptel/branches/1.4 zaptel
apt-get source zaptel-source
cp zaptel/kernel/ztdummy.* zaptel-1.4.11~dfsg/kernel
cd zaptel-1.4.11~dfsg
# Add "Fix compilation for newer kernels"
dch -i
dpkg-buildpackage
cd ..
dpkg -i zaptel-source_1.4.11~dfsg-3.1_all.deb
m-a a-i zaptel

The following installs my patched asterisk, I’m modifying some buffer sizes because I want to play long tones (I’m generating a faked modem guard-tone that is needed in a project). You probably won’t need the patches asterisk, but it won’t hurt to install it. The create-patches script is available from
http://project.runtux.com/asterisk/create-patches

apt-get install libreadline5-dev libgsm1-dev libssl-dev libtonezone-dev 
    libvpb-dev autotools-dev libsqlite-dev libspeex-dev libspeexdsp-dev 
    graphviz libcurl4-openssl-dev doxygen libpopt-dev libopenh323-dev   
    libiksemel-dev libradiusclient-ng-dev freetds-dev libvorbis-dev     
    libsnmp-dev libc-client2007b-dev libcap2-dev libpq-dev unixodbc-dev 
    libpri-dev
apt-get source asterisk
scp ralf@bee:checkout/own/config/asterisk/create-patches .
cd asterisk-1.4.21.2~dfsg/
sh ../create-patches
# Hunk #1 succeeded at 25 (offset 3 lines).
# Add "runtux.com local buffer-size patches"
# and new version-number 1:1.4.21.2.1~dfsg-3
dch -i # add comment
dpkg-buildpackage -rfakeroot
cd ..

For mISDNuser and chan_lcr I’m using Joerg Dorchains packages with my added patches for DTMF codes A-F.

sane snapscan and epson 3590 photo + rpm weirdness


I’ve recently upgraded to debian lenny. Unfortunately after this upgrade my epson 3590 scanner stopped working. After some googling around I managed to find an rpm package with the binary firmware image. But the package converter alien would not let me convert the file, the message was

Unpacking of ‘iscan-firmware-2.8.0.1-48.1.noarch.rpm’ failed at /usr/share/perl5/Alien/Package/Rpm.pm line 155.

After some more searching I found debian bugs 518348 and 509444 of which the latter contains a workaround: Seems that the rpm format changed to a compressed format that can be unpacked with lzma. Now unpacking was possible — after all I was only interested in the firmware file — and now my scanner is working again… For the record, unpacking was done as follows:

mkdir iscan-firmware-2.8.0.1
rpm2cpio iscan-firmware-2.8.0.1-48.1.noarch.rpm
| lzma -d | (cd iscan-firmware-2.8.0.1;
cpio –extract –make-directories
–no-absolute-filenames –preserve-modification-time)

Dämmerungsgesteuerte Hühnerstalltür mit Arduino


Seit einiger Zeit haben wir Hühner. Da wir öfter mal am Abend alle weg sind und dann niemand die Tür vom Hühnerstall zumacht — die Hühner gehen, im Gegensatz zu den Enten die wir früher hatten, von selber bei Dämmerung in den Stall — brauchten wir eine Lösung, die automatisch die Tür schließt. Es gibt fertige Hühnerställe mit einer zeitgesteuerten Tür — aber weder mit Dämmerungsschalter noch eine Türelektronik einzeln.

-)

v.l.n.r Kokoschka, Leuchtfeder, Gertrude :-)


Mein Sohn Max und ich haben also gemeinsam die Tür mit Mechanik und Elektronik und Software selber gemacht.

Alle verwendeten Teile sind bei Conrad erhältlich, wo wir es noch rekonstruieren können geben wir die Bestellnummern und den Link zum Artikel an. Conrad ist zwar relativ teuer, dafür bekommt man für dieses Einmalprojekt alle Teile bei einem Händler und wer was nachbauen will kann im deutschsprachigen Raum über einheitliche Teilenummern auf die gleichen Teile zugreifen, sei es in Österreich, der Schweiz oder Deutschland.

Einige Teile unserer Lösung eignen sich sicher auch für andere Projekte, nicht viele Leute werden eine Hühnerstalltüre brauchen …

Die Hühnerstalltüre funktioniert jetzt schon ein paar Wochen. Anfängliche mechanische Probleme (Tür verklemmte sich einige Male beim Herunterfahren) sind wohl gelöst. Unsere Software hat einen Zeitcheck falls beim Runter- oder Rauffahren doch mal was schiefgeht.

In der Folge beschreiben wir den Aufbau, getrennt nach Mechanik, Elektronik und Software — die Aufteilung zwischen Mechanik und Elektronik ist etwas willkürlich, wir haben die ganze Elektromechanik
(Motor, Schalter) zur Mechanik gerechnet.

Die Mechanik

Mit einem Getriebemotor wird eine Welle über einen Zahnriemen-Antrieb (Übersetzung nochmal 4:1) angetrieben. Der Getriebemotor ist schon 148:1 untersetzt. Die Welle läuft auf Kugellagern, die in einem Holzrahmen montiert sind. Die Lagerflansche sind einfach mit Heisskleber in den ausgestemmten Teil der Holzlatten geklebt. Vorsicht, keinen Heisskleber ins Lager bringen…

Die Übersetzung wurde so gewählt, dass wir eine bis zu 800g schwere Tür mit einer Welle mit Radius 5mm gut hochziehen können. Das Drehmoment des verwendeten Motors ist etwa 1,2 Ncm, mit der 4:1 Übersetzung mit dem Zahnriemen kommen wir auf 4.8 Ncm.

Die Welle wickelt dann eine Nylonschnur auf, die an der Tür angebunden ist. Die Nylonschnur hat einen Durchmesser von 2mm, die Welle wurde mit einem 2mm Titanbohrer gebohrt. Zum Bohren der Welle haben wir einen Stellring verwendet, einfach durch das Schraubenloch des Stellringes gebohrt, der Stellring war mit Klebeband fixiert.

Das Einfädeln der Nylonschnur kann man sich erleichtern, indem man die Nylonschnur mit einem Feuerzeug an einer Stelle erhitzt und auseinanderzieht, die entstehende Spitze eignet sich recht gut zum Einfädeln.

Motor: Eigentlich wollten wir ursprünglich einen kleineren Motor, da der jetzt verwendete Motor bis zu 2A Strom zieht (bei hoher Last — unsere Tür ist relativ leicht, dadurch ist die Last und damit der Strom recht niedrig). Das könnte mal zuviel für den verwendeten H-Bridge Motorcontroller werden.

Die Tür selbst hat einen Magneten, der in zwei Stellungen (Tür ganz oben bzw. ganz unten) jeweils einen Magnetschalter auslöst.

Für das Justieren (von Hand Türe rauf- bzw. runterfaheren) gibt es zwei Taster die an digitalen Inputs des Arduino angeschlossen sind.

Mechanischer
Aufbau

Mechanischer Aufbau

Teileliste Mechanik:

  • 222366 Getriebemotor
  • 222374 Alternativ: kleinerer Motor
  • 237205 Welle 8mm
  • 216011 Lagerflansch für Kugellager
  • 225550 Stellringe 8mm
  • 214493 Kugellager
  • 226043 Zahnriemenscheibe 40 Zähne, für Welle 8mm
  • 226106 Zahnriemenscheibe 10 Zähne, für Welle 6mm (an Motor)
  • 226084 Zahnriemen
  • 753360 Magnetschalter
  • Taster ein (2X)

Im folgenden Bild sieht man die Tür im Zustand “NACHT” (zu). Die Magnetschalter und der Magnet an der Tür sind gut zu erkennen. Oben im Bild ist ein Stück Sperrholz auf Abstandshaltern so montiert, dass die Schnur durchläuft und beim Hochfahren die Tür an die Hüttenwand gedrückt wird.

Hühnerstalltür im geschlossenen Zustand mit Magnet und
Magnetschaltern

Hühnerstalltür im geschlossenen Zustand mit Magnet und Magnetschaltern

Die Elektronik

Der Dämmerungsschalter ist mit einem einfachen Photowiderstand in einem Spannungsteiler mit einem 10k Widerstand realisiert. Der Photowiderstand ist über ein Lautsprecherkabel mit Heisskleber im Holzdach montiert. Oberhalb des Photowiderstands ist ein Acryl-Welldach. Die Magnetschalter sind an digitale Eingangspins des Arduino angeschlossen.

Die Motorsteuerung erfolgt über eine H-Bridge Schaltung in einem IC. Die Elektronik dazu findet auf einer Lochraster-Platine Platz. Die einfache H-Bridge benötigt keine externen Teile. Wie man das mit dem Arduino verdrahtet ist ganz gut auf der Seite der Physical Computing Labs der Tisch School of the Arts beschrieben — ist auch der erste Link auf den ich beim googlen nach “Arduino Motor Control” gestoßen bin.

Wir wollen aber — wegen des größeren Motors — auf eine größere H-Bridge, die braucht externe Schaltdioden (das Datenblatt des L298N schlägt Dioden mit höchstens 200ns reverse recovery time (trr) vor, wir werden die BYV 2100 verwenden mit einer trr von 12.5ns)

Teileliste Elektronik:

Alternative größere H-Bridge:

  • 156128 L298N H-Bridge Dual 2A bzw parallelgeschaltet 3A
  • 160005 BYV 2100 Schnelle Dioden dazu

Die Software

Der Dämmerungsschalter sollte laut Wikipedia bei ca. 100 lux das Öffnen der Tür veranlassen und bei höchstens 3.4 lx (Dark limit of civil twilight under a clear sky) das Schließen. In dem Wikipedia-Artikel ist eine Tabelle, die einen sehr dunklen Tag mit 100lx angibt, die deutsche Version enthält leider keine ausführliche Tabelle. In unseren Experimenten war ein Meßwert des Arduino von 200 für “Jetzt ist es dunkel, Tür zu” und von 300 für “Jetzt ist es hell, Tür auf” gut — auch in den jetzt dunklen Wintertagen (auch bei einem Gewitter) bleibt die Tür tagsüber offen und schliesst zuverlässig bei Dunkelheit. In einer klaren Vollmondnacht blieb die Tür zu.

Die Steuerung ist als Zustandsautomat (State Machine) realisiert. Jenachdem welcher Magnetschalter beim Einschalten Kontakt hat, startet der Automat im Zustand “TAG” bzw. “NACHT”. Wird keiner der Magnetschalter gesehen, gehen wir in den Zustand “ERROR”. Dieser Zustand bildet auch alle anderen Fehlerzustände ab, die im Betrieb auftreten können. Dabei setzen wir eine Fehlermeldung, die dann über die serielle Schnittstelle des Arduino (USB Serial) ausgegeben wird.

Der Zustandsautomat verwendet Statusfunktionen: In einem bestimmten Zustand wird die zugehörige Zustandsfunktion ausgeführt. Wenn diese Funktion 0 zurückliefert, geht der Automat in den nächsten Zustand, sonst bleibt er im alten Zustand.

Durch die Verwendung von Statusfunktionen (und keiner speziellen Funktion beim Zustandsübergang) haben wir zwei zusätzliche Zustände um den Motor einzuschalten, dieser Zustand (START_RAUF bzw. START_RUNTER) schaltet den Motor ein und geht sofort in den nächsten Zustand über.

Die Verdrahtung mit dem Arduino, also an welchen Pins welche Peripherie angeschlossen ist, sind über define’s am Beginn des Programms festgelegt.

Die Logik für die digitalen Inputs verwendet die Arduino-internen Pull-Up Widerstände. Daher ist die Logik invertiert: Wenn der Taster (oder ein Magnetschalter) geschlossen ist, liefert der entsprechende digitale Input eine 0.

Beim Testen haben wir festgestellt, dass bei laufendem Motor gelegentlich eine gedrückte Taste — oder ein geschlossener Magnetschalter detektiert wird. Daher haben wir in Software alle digitalen Inputs entprellt (Funktion debounced_read). Vermutlich sollten wir vor der H-Bridge noch einen Entstörkondensator vorsehen.

Die beiden Taster zum manuellen Rauf- und Runterfahren setzen ein Flag das den Zustandsautomaten neu initialisiert — dadurch muss man nach dem manuellen Kalibrieren kein Reset ausführen: Einfaches Drücken der Rauf- bzw. Runter-Taste reicht, um ein neues Initialisieren durchzuführen.

Im Error-Status warten wir 100ms nach dem Ausgeben der Fehlermeldung. Durch dieses Delay merkt man bei Drücken des Rauf- bzw. Runter-Knopfes sofort, ob sich das Gerät im Error-Zustand befindet: Wenn ein Error-Zustand vorliegt, bewegt sich der Motor nicht sofort, sondern erst nach einem kurzen Delay. Wenn der Zustandsautomat korrekt initialisiert ist, bewegt sich der Motor sofort.

Während der Entwicklung habe ich mit etwas mit einem Bug der Arduino-Entwicklungsumgebung gekämpft: Um Function-Style casts (Typumwandlungen die wie eine Funktion aussehen) zu ermöglichen, macht die Entwicklungsumgebung Code-Rewriting und fügt insbesondere einige Preprozessor-Defines ein, die es verhindern, einen Funktionspointer in C zu deklarieren. Der Workaround ist ein “#undef int” vor der Funktionspointer-Deklaration einzufügen. Gleich am Anfang kann man das nicht machen, da das Code-Rewriting ein #include direkt vor dem ersten Statement (nach allen #include und #define Direktiven) einfügt. Dieses “Feature” hat durch obskure Fehlermeldungen einiges an Zeit gekostet, was mich veranlasst hat, einen Beitrag im Arduino Forum dazu zu schreiben.

Die verwendeten Timer-Routinen (#include <timer.h> und der Typ Arduino_Timer) dienen dazu, auf eine bestimmte Zeit nach dem Aufruf von millis() zu warten — auch wenn die von millis verwendete Variable inzwischen überläuft. Der Timer lässt sich fragen, ob der gewünschte Zeitpunkt schon erreicht ist. Ursprünglich habe ich diese Routinen geschrieben, weil Version 0011 (und früher) der Arduino Entwicklungsumgebung einen Bug hatte, so dass der Timer zu früh überlief. Die entsprechenden Timer Routinen (für Version 0011 oder ab 0012) gebe ich gern auf Anfrage weiter.

#include <timer.h>
#include <stdio.h>

# define LED          13
# define MAGNET_OBEN   7
# define MAGNET_UNTEN  8
# define FOTO          0
# define MOTOR         9
# define MOTOR_DIR1    4
# define MOTOR_DIR2    3
# define MOTOR_MIN  0x7F
# define KNOPF_RAUF   12
# define KNOPF_RUNTER  2

# define HELL        300
# define FINSTER     200

# define STATUS_TAG          0
# define STATUS_ABEND        1
# define STATUS_NACHT        2
# define STATUS_MORGEN       3
# define STATUS_START_RAUF   4
# define STATUS_RAUFFAHREN   5
# define STATUS_START_RUNTER 6
# define STATUS_RUNTERFAHREN 7
# define STATUS_ERROR        8

int status   = STATUS_ERROR;
char errbuf [80];
char *errmsg = “”;
int neuinitialisieren     = 1;
int debounce_magnet       = 0;
int debounce_knopf_runter = 0;
int debounce_knopf_rauf   = 0;

# define TIMER_MS       10000 // 10 seconds debounce 300000 // 5 minutes
# define FAHRZEIT_MS    75000 // max 75 seconds for up/down of door
Arduino_Timer timer (TIMER_MS);

int debounced_read (int iopin, int *counter)
{
    if (!digitalRead (iopin))
    {
        if ((*counter)++ >= 10)
        {
            *counter = 0;
            return 0;
        }
    }
    else
    {
        *counter = 0;
    }
    return 1;
}

void motor_an ()
{
    digitalWrite (LED,   HIGH);
    digitalWrite (MOTOR, HIGH);
}

void motor_aus ()
{
    digitalWrite (LED,   LOW);
    digitalWrite (MOTOR, LOW);
}

void linksrum ()
{
    digitalWrite (MOTOR_DIR1, LOW);
    digitalWrite (MOTOR_DIR2, HIGH);
}

void rechtsrum ()
{
    digitalWrite (MOTOR_DIR1, HIGH);
    digitalWrite (MOTOR_DIR2, LOW);
}

// Wir benutzen Status-Funktionen fuer jeden Status unserer Maschine:
// Wenn die Funktion 0 zurueckliefert, geht die Maschine in den naechsten
// Zustand, sonst bleibt sie im gleichen Zustand.

int fahren (int magnet)
{
    if (!debounced_read (magnet, &debounce_magnet))
    {
        return 1;
    }
    if (timer.is_reached (millis ()))
    {
        motor_aus  ();
        timer.stop ();
        errmsg = “Zeitueberschreitung fahren”;
        status = STATUS_ERROR;
        return 0;
    }
    return 0;
}

int starte_rauffahren ()
{
    if (digitalRead (MAGNET_UNTEN))
    {
        errmsg = “Hochfahren: Tuere nicht unten”;
        status = STATUS_ERROR;
        return 0;
    }
    timer.start (millis (), FAHRZEIT_MS);
    debounce_magnet = 0;
    rechtsrum ();
    motor_an  ();
    return 1;
}

int rauffahren ()
{
    return fahren (MAGNET_OBEN);
}

int starte_runterfahren ()
{
    if (digitalRead (MAGNET_OBEN))
    {
        errmsg = “Hochfahren: Tuere nicht oben”;
        status = STATUS_ERROR;
        return 0;
    }
    timer.start (millis (), FAHRZEIT_MS);
    debounce_magnet = 0;
    linksrum  ();
    motor_an  ();
    return 1;
}

int runterfahren ()
{
    return fahren (MAGNET_UNTEN);
}

int nacht ()
{
    int val;
    motor_aus ();
    val = analogRead (FOTO);
    Serial.println (val);
    if (val > HELL)
    {
        timer.start (millis ());
        return 1;
    }
    return 0;
}

int tag ()
{
    int val;
    motor_aus ();
    val = analogRead (FOTO);
    Serial.println (val);
    if (val < FINSTER)
    {
        timer.start (millis ());
        return 1;
    }
    return 0;
}

int abend ()
{
    int val;
    motor_aus ();
    val = analogRead (FOTO);
    if (val > FINSTER)
    {
        status = STATUS_TAG;
        return 0;
    }
    if (timer.is_reached (millis ()))
    {
        timer.stop ();
        return 1;
    }
    return 0;
}

int morgen ()
{
    int val;
    motor_aus ();
    val = analogRead (FOTO);
    if (val < HELL)
    {
        status = STATUS_NACHT;
        return 0;
    }
    if (timer.is_reached (millis ()))
    {
        timer.stop ();
        return 1;
    }
    return 0;
}

int error ()
{
    motor_aus ();
    Serial.println (errmsg);
    delay (100);
    return 0;
}

# undef int
struct state {
    int status;
    int next_status;
    int (*statefun)();
};

// Stati muessen in der Reihenfolge der numerischen Zustandswerte sein
// Zustaende muessen lueckenlos nummeriert sein
struct state stati [] =
{ { STATUS_TAG,          STATUS_ABEND,        tag                 }
, { STATUS_ABEND,        STATUS_START_RUNTER, abend               }
, { STATUS_NACHT,        STATUS_MORGEN,       nacht               }
, { STATUS_MORGEN,       STATUS_START_RAUF,   morgen              }
, { STATUS_START_RAUF,   STATUS_RAUFFAHREN,   starte_rauffahren   }
, { STATUS_RAUFFAHREN,   STATUS_TAG,          rauffahren          }
, { STATUS_START_RUNTER, STATUS_RUNTERFAHREN, starte_runterfahren }
, { STATUS_RUNTERFAHREN, STATUS_NACHT,        runterfahren        }
, { STATUS_ERROR,        STATUS_ERROR,        error               }
};



void setup ()
{
    pinMode (LED,         OUTPUT);
    pinMode (MAGNET_OBEN,  INPUT);
    pinMode (MAGNET_UNTEN, INPUT);
    pinMode (MOTOR,       OUTPUT);
    pinMode (MOTOR_DIR1,  OUTPUT);
    pinMode (MOTOR_DIR2,  OUTPUT);
    pinMode (KNOPF_RUNTER, INPUT);
    pinMode (KNOPF_RAUF,   INPUT);

    digitalWrite (MOTOR,   LOW);
    linksrum ();
    digitalWrite (LED,     HIGH);

    digitalWrite (MAGNET_OBEN,  HIGH); // enable pull-up resistor
    digitalWrite (MAGNET_UNTEN, HIGH); // enable pull-up resistor
    digitalWrite (KNOPF_RUNTER, HIGH); // enable pull-up resistor
    digitalWrite (KNOPF_RAUF,   HIGH); // enable pull-up resistor
    Serial.begin (115200);
    if (FINSTER >= HELL)
    {
        status = STATUS_ERROR;
        errmsg = “FINSTER >= HELL”;
    }
    Serial.print (“initial state: “);
    Serial.println (status);
}

void loop ()
{
    struct state *st = &stati [status];
    if (!debounced_read (KNOPF_RUNTER, &debounce_knopf_runter))
    {
        debounce_knopf_runter = 10;
        linksrum  ();
        motor_an  ();
        neuinitialisieren = 1;
        return;
    }
    else if (!debounced_read (KNOPF_RAUF, &debounce_knopf_rauf))
    {
        debounce_knopf_rauf = 10;
        rechtsrum ();
        motor_an  ();
        neuinitialisieren = 1;
        return;
    }
    else if (neuinitialisieren)
    {
        motor_aus ();
        errmsg = “Unbekannte Tuerposition bei Start”;
        status = STATUS_ERROR;
        if (!digitalRead (MAGNET_OBEN))
        {
            status = STATUS_TAG;
        }
        else if (!digitalRead (MAGNET_UNTEN))
        {
            status = STATUS_NACHT;
        }
        neuinitialisieren = 0;
        debounce_knopf_rauf = debounce_knopf_runter = 0;
        Serial.print (“Initialized to: “);
        Serial.println (status);
        return;
    }
    // Hard-coded error state must work if state-table is broken
    if (status >= STATUS_ERROR)
    {
        error ();
        return;
    }
    if (st->status != status)
    {
        status = STATUS_ERROR;
        sprintf
            ( errbuf
            , “Error in state-table, expected %d got %d”
            , status
            , st->status
            );
        errmsg = errbuf;
        return;
    }
    if (st->statefun ())
    {
        status = st->next_status;
    }
    if (status != st->status)
    {
        sprintf (errbuf, “new state: %d->%d”, st->status, status);
        Serial.println (errbuf);
    }
}

Die vier Grundfreiheiten der Gnu General Public License


Weil ich immer mal wieder gefragt werde, was die Hauptmerkmale von Open Source Lizenzen, insbesondere der Gnu General Public License (GPL) [Deutsche Übersetzung hier] sind, eine ganz gute (deutsche) Erklärung steht in einer Gerichtseingabe von einem Anwaltsbüro, ich gebe das hier wieder:

[Die GPL ist ein Lizenzsystem,] das den Hauptzweck verfolgt, eine möglichst große Verbreitung einer bestimmten Software zu ermöglichen und ausdrücklich zuzulassen, dass Veränderungen an dieser Software vorgenommen werden. Dies aus der Intention, dass sich eine Software stetig dadurch verbessert, dass sie von jedem, der Probleme der Software erkennt, optimiert werden kann.

Die GPL basiert auf den vier sogenannten “Grundfreiheiten” die die Basis der GPL bilden. Diese Grundfreiheiten sind Bestandteil der Lizenz.

Die erste Grundfreiheit gewährt dem Nutzer das Recht, das Programm ohne jede Einschränkung für jeden Zweck zu nutzen. Ausdrücklich ist hierbei auch die kommerzielle Nutzung von dem Nutzungsrecht umfasst.

Die zweite Grundfreiheit wiederum gewährt dem Nutzer das Recht, unter bestimmten Einschränkungen hinsichtlich des sogenannten Quellcodes [...] das Programm zu verbreiten, also kostenlos oder gegen Entgeld zu kopieren und in den Verkehr zu bringen. Nicht erlaubt ist lediglich, Lizenzgebühren für die Nutzung des Programms zu erheben.

Die dritte Grundfreiheit besagt, dass das Programm studiert und den eigenen Bedürfnissen angepasst werden darf.

Letztlich besagt die vierte Grundfreiheit, dass auch die veränderten Versionen des Programms unter den Voraussetzungen der vorgenannten Regelungen in Verkehr gebracht werden können.

Die GPL ist damit eine Sicherheit für den Nutzer: Niemand — auch der ursprüngliche Hersteller der Software — kann die Nutzungsrechte einschränken. Kein “Vendor-lock-in” keine versteckten Kosten in Form von Lizenzgebühren. Sollte der ursprüngliche Anbieter für Wartung zu teuer werden, kann jederzeit der Anbieter gewechselt werden.

Die Software darf (sogar für kommerzielle Zwecke) auch weitergegeben werden — lediglich die Rechte, die man selbst an der Software hat, darf man dem Empfänger nicht vorenthalten.

Lassen Sie uns Ihr Vermoegen hochheben


… mit dem Titel habe ich heute eine Spam-Email bekommen — erinnert sehr an den englischen Begriff “Shoplifting” — oder an die alten Witze ala “Die Telekom will an die Börse — auch an Ihre” :-)

E-voting


Yesterday there was an interesting talk on e-voting @metalab by Goesta Smekal. In the discussion, the audience mostly agreed that e-voting shouldn’t be used because we can never be sure that a machine isn’t modified to do something different from correctly counting votes.

That there may be an incentive to win an election by cheating was pointed out by Bruce Schneier in “Stealing an election” in a 2004 Cryptogram newsletter. Now it’s an old hat that it is possible to hide rogue code that won’t be found by inspecting the source-code since in 1984 Ken Thompson published the computer science classic Reflections on Trusting Trust. Recently it has even been possible for researchers to build malicious hardware — with the budget of a university research lab. Open Source in this case is not an answer to the problem: We can’t be sure that the machine is running our software.

So the question is really: How can each voter be sure that the election is carried out correctly. For inspecting a voting machine — even if this would be theoretically possible and the papers cited above indicate that it’s probably not possible — we need an expert — who can be bribed. With paper ballots an untrained observer can convince himself that the election process is correct. Attacks on the system come at high costs and are detectable with a high probability. So let’s stick to the proven distributed algorithm of casting paper ballots.

Update on open money


Some time ago at linuxwochenende I’ve outlined my current state of reading on alternative money projects and implementations. Slides (mostly english) are online http://runtux.com/events.html and there is even a video of the talk (in german, see linuxwochenende link above for torrent or html download). The funny money in the title refers to a paper by Ted Lewis, “Why Funny Money Will Have the Last Laugh”, Computer, vol. 33, no. 5, pp. 112,110-111, May, 2000 (all citations on the web seem to disagree on the page numbers I’ll have to dig out my copy and see what the page numbers really are) which is probably not very exciting today but got me interested in the subject.

Now I’ve discovered some more interesting bits I want to document here.

I’ve recently discovered OpenCoin via the peer to peer foundations feed. OpenCoin seem to be among the first who tackle money with a scientific approach to money protocols *and* release their code as open source. They’ve started by formulating requirements which are referenced in two preliminary papers on existing crypto protocols:

In these papers they outline the cryptography to use for their implementation and check these against their requirements. These reports are very preliminary (still contain serious typos for example I’m missing a “not” in section “2.2 Anonymity” in the report on Chaum’s Architecture that distorts the meaning of the whole sentence).

More serious may be that the don’t consider newer approaches to money protocols — this may be due to patent and security considerations: Chaums work is older than 20 years. Protocols that have withstood some time of not being broken might have a higher chance of not developing a serious failure in practice… but it may also be an indication that the field is very wide.

And another sad fact: The web-page of the project is not very lively — the last entries on the wiki are from march this year. Seems that they applied for funding from LGA (London Development Agency) and received that (as indicated on the main page) but never published anything after that. Or maybe they anticipated to receive a funding which never came.

Another interesting project — which actually produced software that is used in practice is Cyclos by the Dutch Social Trade Organisation STRO (used to be called Strohalm).

This is a more traditional approach to a system where a trusted organisation manages a local currency like LETS or barter systems. Also microcredit systems are managed with this system according to their web site.

I’ve recently discussed about money alternatives with Clifford — one thing we couldn’t agree on was if one needs the state as the central authority for issuing money. I argued that there are already many projects (some of the mentioned in the linuxwochenende talk above) doing this today. Cliffords answer was that they’re all backed by the existing money system. I’m undecided on this issue but tend to believe that a local community can agree on a currency without a state. It may even be possible to do something like Terra (a good intro to Terra is on p2pfoundation ). At least we can start now that the existing money system still works (Sort of. Or not. Maybe.).

OpenMoko 2008.9


I’ve now had some time to look more closely into my OpenMoko Neo. The first thing I did was upgrade the device to the new Firmware 2008.9

The needed dfu-util is a Debian lenny package, on my lenny-laptop just one apt-get away. The upgrade steps are well documented on the “Flashing the Neo” page.

I’ve also upgraded the bootloader because I wanted to try to install Debian (on the SD card) and the instructions say to upgrade the bootloader.

After booting into the new version I discovered that the “Settings” icon did nothing. The device would auto-suspend after about 30 seconds when not in use via the touch-screen. Fortunately I had experimented earlier how to get a SSH-connection to the device — I wouldn’t have found out in 30 seconds: The device would suspend and kill a running SSH-session.

The openmoko device comes up as network interface usb0 on the machine you connect the USB to. The IP is 192.168.0.202, you should configure your usb0 network interface to something like 192.168.0.200.

I’m using the Debian package ipmasq on my laptop, so NAT to my internal network for the openmoko was working immediately, I could ping machines on my internal network.

So I held the touch-screen with the left-hand thumb and configured the network: The device comes up with an empty /etc/resolv.conf, you should insert a nameserver line with the IP of a reachable nameserver.

After having a running network (remember I’m still preventing the device from suspending and killing my ssh session with one finger on the display) I installed the package illume-config which adds a little toolbox-icon to the window-manager. With this I was able to finally disable the suspend via the config. After that I did an opkg upgrade of the device and the “Settings” program magically started working.

The first experiment with a phone-call failed, because the called party could not hear me. I had to install alsamixer and turn on the microphone and capture devices. Now calling and being called works fine.

I haven’t experimented too much until now — one of the major roadblocks is a broken input method. The on-screen keyboard is not really suitable for entering commands into an xterm. One of the next steps will be to install Debian on the device.

Advanced Routing With Several Providers


I’ve recently set up routing for two uplink providers. The advanced routing howto is a good guide for getting routing via several providers running. I’ve observed two points worth mentioning, though.

  • When using NAT and several different internal/DMZ networks the source address of packets (in my experiments) doesn’t work reliably for determining the routing table as in the example in the advanced routing howto. It is easier to tag connections with a connmark and copy this mark to the individual packets of the connection. This looks like the following (I’m using the naming from the advanced routing howto):

    iptables -t mangle -A PREROUTING -i $IF1 -p tcp
    -mstate –state NEW -j CONNMARK –set-mark 1/1
    iptables -t mangle -A PREROUTING -i $IF2 -p tcp
    -mstate –state NEW -j CONNMARK –set-mark 2/2
    # mark packets with connection mark
    # to be usable in routing
    iptables -t mangle -A PREROUTING -p tcp
    -j CONNMARK –restore-mark –mask 0x0F

    Then we can reuse that mark to determine the routing table to use:

    ip rule add fwmark 1 T1
    ip rule add fwmark 2 T2

    This can also be reused for routing some services via one and other services via the other interface. Just apply the correct connmark to the connection.
  • When using complex routing rules, source validation of the Linux Kernel can get into the way, thanks to Peter Holzer for pointing this out. There are special files in

    /proc/sys/net/ipv4/conf/*/rp_filter

    one for each interface and some to apply global defaults. Some Linux distributions automagically set these all to “1″. I’m currently turning all of them to 0 and routing is working now. You know that you might have this problem when packets from an external interface are dropped after PREROUTING and are never seen in the FORWARD chain of iptables. The Linux-Kernel documentation in Documentation/networking/ip-sysctl.txt say this about rp_filter:

    rp_filter – BOOLEAN

    1 – do source validation by reversed path, as specified in RFC1812 Recommended option for single homed hosts and stub network routers. Could cause troubles for complicated (not loop free) networks running a slow unreliable protocol (sort of RIP), or using static routes.

    0 – No source validation.

    conf/all/rp_filter must also be set to TRUE to do source validation on the interface

Telering Online Rechnung


Neulich hab ich meine Telering-Rechnung von meinem Mobiltelefon auf Online umgestellt, weil ich seit fast einem halben Jahr eh keine Papierrechnung von denen mehr bekomme (Anruf bei Hotline um abzuklären, warum die Papierrechnung nicht mehr kommt war nur Zeitverschwendung und im Kundenbereich kann man die Rechnung runterladen).

Letzten Freitag bekomm’ ich ein SMS, dass meine Telering-Rechung da ist — es gibt ja fast nix wichtigeres auf der Welt als eine Telering-Rechung, daher ist es unerlässlich, den Kunden auf allen verfügbaren Kanälen darauf aufmerksam zu machen, dass die Rechnung da ist (fehlt eigentlich nur, dass ich einen Anruf bekomme :-):

tele.ring Rechnungs-Info!
Ihre aktuelle Rechnung ist online. Abrufbar unter my.telering.at > Rechnung. LG Ihr tele.ring Team

Ich ärgere mich also über die Störung und versuche die Absendernummer 1554020000001 des SMS anzurufen — und — am anderen Ende ist eine Österreichische Wettervorhersage.

Also habe ich bei der Hotline die Rechnung wieder auf Papier zurückgestellt (online-Rechung heisst offensichtlich Email und SMS) — möglicherweise kommt sie ja jetzt wieder — nach einmal hin und her Umstellen auf Online und zurück.