Mittwoch, 15. Dezember 2010

itrackutil 0.1.3 available

After a recent update in Ubuntu 10.10 and 10.04 itrackutil.py exits with the the error message “USBError: Resource Busy” before the user is able to download GPS data from the device.
This version fixes the problem.

Developer information:

A previously unrelated kernel module (cdc_acm) suddenly started to grab the USB device.  cdc_acm  which usually supports USB modems now creates the device /dev/ttyACM0 as soon as the GPS mouse is plugged in.

If you read /dev/ttyACM0 you get the real-time GPS data in NEMA format.  This is an unusual use case. The normal data connection is over Bluetooth.

However, the creation of this device file blocks all other USB access to the GPS mouse; in this case the direct USB communication which itrackutil.py uses to access the data stored within the unit's memory.

Fortunately there is an USB API call for this situation: detachKernelDriver.
This function does, what it says it does.  You have to call it after opening the device. Root privileges are not necessary.

The call will fail, if there is no kernel driver to detach. You have to catch this exceptions:

... determine device, interface, and configuration ...

try:
    handle = device.open()
    handle.detachKernelDriver(interface)
except usb.USBError, err:
    if str(err).find('could not detach kernel driver from interface') >= 0:
        pass
    else:
        raise usb.USBError,err       # any other USB error

handle.setConfiguration(configuration)


The companion API call attachKernelDriver is not available via PyUSB 0.1. But this is only a minor problem, because as soon as you unplug the unit and reconnect it, a new USB device file is created (with the kernel driver attached).

Samstag, 13. November 2010

WinTV-HVR-1900 under Ubuntu 10.04 and 10.10



A few weeks ago I bought a Hauppauge WinTV-HVR-1900 (USB id 2040:7300) which I wanted to use with a (32 bit) Ubuntu 10.04 and 10.10 system.
 
Quick installation summary:
  • Does it work out of the box: No
  • Does it work at all: Yes
  • If you are able to update to Ubuntu 10.10, do it.
This post only describes how to get the basic functionality working (i.e. display/record a signal on the composite video input).
 
The HVR 1900 is a small box which is connected via a USB2 port (USB1 is not supported for bandwidth reasons). There are inputs for composite video (e.g. VCR or set-top box) an antenna input and a S-VHS input. The device comes with a UK power supply (with a UK mains plug) and a bulky mains plug adapter for continental Europe.
 
In order to get the digitizer running, this device needs firmware.  Ubuntu comes with a selection of firmware images for various Hauppauge systems, but none was suitable for this device.
 
The firmware is included on the Windows driver disk you get with the device, but which files do you need?  Fortunately there is a perl script available that scans the CD and extracts the files you need based on a bunch of MD5 sums stored in that script.  Perl is installed by default on a Ubuntu system, so slide in the CD, open a terminal and enter
 
perl fwextract.pl /media/XXXXXXXXXX
 
(where XXXXX is the CD title)
 
In my case the following files were found:
  • v4l-cx2341x-enc.fw
  • v4l-cx25840.fw
  • v4l-pvrusb2-29xxx-01.fw
  • v4l-pvrusb2-73xxx-01.fw
 
For the next steps you need root privileges:
 
  • Change the ownership of those files to root (for security reasons)
    sudo chown root:root *fw 
  • Copy the extracted files to /lib/firmware
    sudo cp *fw /lib/firmware
 If you're running Ubuntu 10.10, that's all you have to do.
 
Keep an eye on the system log when you now plug the digitizer into the USB port.
tail -f /var/log/syslog
 
Among other messages, it should confirm that the firmware was uploaded successfully.
 
...
cx25840 5-0044: firmware: requesting v4l-cx25840.fw
cx25840 5-0044: loaded v4l-cx25840.fw firmware (16382 bytes)
...

 
Utilities for controlling the device from the command line can be found in the package ivtv-utils (from the Ubuntu repo).
 
v4l2-ctl --set-input 1
 switches to the composite video input
 
v4l2-ctl --set-ctrl=brightness=128,hue=0,contrast=68,volume=54000
 sets basic parameters for the digitizer.
 
Call v4l2-ctl without parameters for more help, and you will definitively want to try the switch -L
 
Recording is as simple as:
cp /dev/video0 video.mp2
 
This works most of the time.  Approx. 5% of the recordings contain a distorted audio stream. This distortion is present for the whole length of the recording and usually ends the next time the device /dev/video0 is opened. 
 
If the audio is ok at the beginning, it stays that way.  This looks like an initialization problem when the device is opened.  I haven't found a fix, yet.
 
Now to the more difficult part:

Getting the device to work under Ubuntu 10.04.
 
As mentioned before, many Hauppauge devices need firmware, which is uploaded to the unit when you plug it into the USB port.  Older hardware only needed 8192 bytes of firmware.  The firmware for this device however is 16382 bytes long (see the above firmware upload message from the log).  The device driver controlling the HVR-1900 (pvrusb2) that comes with kernel 2.6.32 and earlier is only capable of transferring 8192 bytes. And Ubuntu 4.10 LTS uses... 2.6.32.
 
Newer versions of the pvrusb2 driver can also upload the larger firmware.  For older kernels (like the one used in Ubuntu 4.10), you have to compile the updated driver yourself.
 
Compiling a kernel is usually a simple task, because the kernel source code already contains all dependencies. But this time, there were complications.
 
You need:
  •  the kernel source
  •  the tools to compile the kernel
  •  and the source of the updated driver
The easiest way to get the Ubuntu Linux source is by installing a package named "linux-source". It will store the source code as an archive in /usr/src/linux-source-2.6.32.tar.bz2 
 
You have to unpack it - make sure that you have plenty of disk space available:
 
cd /usr/src
tar xvfj linux-source-2.6.32.tar.bz2

 
Then run the following commands
 
cd linux-source-2.6.32
make oldconfig
make prepare
 

This will "regenerate" the .config file used by your distribution's kernel.  This file is needed during the kernel compilation.
 
Now we have to download the source code of the current pvrusb2 driver which can be found here. Unpack it and copy the content of the directory driver to /usr/src/linux-source-2.6.32/drivers/media/video/pvrusb2/ overriding the current files with the same name.
 
(Please note: the pvrusb2 documentation is describing a different approach, that did not work for me (modprobe rejected the module))
 
The next step would be:
 
make modules
 
But due to a totally unrelated bug  the compilation will fail, while trying to compile the "omnibook" files.
 
Download the patch for this bug from here and apply it
 
cd /usr/src
patch -p0 _name_of_the_path_file_

 
Now it's time to compile the modules:
 
cd /usr/src/linux-source-2.6.32
make modules

 
This step is very time consuming. If you have a multi core processor use the -j# option (where # is the number of cores you have).
 
Copy the new module from
/usr/src/linux-source-2.6.32/drivers/media/video/pvrusb2/pvrusb2.ko
to
/lib/modules/`uname -r`/kernel/drivers/media/video/pvrusb2/pvrusb2.ko
 
(where `uname -r` (backticks!) will be replaced by the name of your current kernel)
 
Keep in mind that you have to repeat that process after each kernel update.
 
After the next reboot the new module should be active. If you can't wait, unload the old one and load the new module manually:
 
rmmod pvrusb2
modprobe pvrusb2
 

Again, check /var/log/syslog for any problems.
 
Links:
  • http://www.isely.net/pvrusb2
  • http://www.isely.net/pipermail/pvrusb2/
  • https://help.ubuntu.com/community/Kernel/Compile
  • http://www.isely.net/downloads/fwextract.pl

Mittwoch, 20. Oktober 2010

ColorCube on a 64 bit machine


After a recent interview with Quentin Bolsee, the lead developer of the game ColorCube, I  downloaded the demo version of his game.  ColorCube is a simple nice puzzle game that can keep you occupied for hours.

But I had to find out that the program did not start on my main machine.

The command

ldd Launcher

quickly revealed that it a 32 bit application, and various libraries were missing on my 64 bit system.

The package ia32-libs which provide 32 libraries for 64 bit systems does understandably not contain all libraries that may be installed on a 32 bit system.  A simple work-around is to copy these files from a 32 bit set-up (/usr/lib) to the 64 bit system (/usr/lib32).

Don't forget to set the file owner to root on the target system., and keep in mind that those libraries will not be updated.

In order go get ColorCube running, I needed to copy the following libraries:

libHalf.so.6
libIlmImf.so.6
libIlmThread.so.6
libspeex.so.1
libtheora.so.0
libIex.so.6
libImath.so.6
libraw1394.so.11
libusb-1.0.so.0


Happy gaming...





Mittwoch, 11. August 2010

Lift + Scala, Installation + First contact

I have installed Lift and Scala on a Linux computer running the current Ubuntu version 10.04. Depending on your distribution, the commands may be different.

What you need is:
  • maven2 - a Java software project management and comprehension tool
  • jetty - a Java servlet engine
  • Java
Note that this is not the only possible configuration. There are other project management tools like SBT and other servlet engines, e.g. Tomcat. However, the documentation I've seen mostly describes maven and jetty.

Installation of Scala

Please note: The following step will install Scala. It also lets you run Scala commands interactively from the command line. This is a very good learning tool, especially for beginners.

This is a modified version of the instructions given by the London Scala User Group Dojo:

  • Warning: Do not use Scala from the Ubuntu (10.04) repositories. The repo contains an older 2.7 variant - we want 2.8!
  • Create a folder that will hold one or more versions of Scala:
    sudo mkdir /opt/scala
  • Change that folders ownership to your username:
    sudo chown -R username.username /opt/scala
  • From http://www.scala-lang.org/downloads download Scala final for Unix, Mac OS X, Cygwin. This is a gziped tar archive file.
  • Open the dowloaded file (Archive manager - file-roller) and extract to /opt/scala/
  • Create a sybolic link (future proof the install):
    ln -s /opt/scala/scala-2.8.0.final /opt/scala/current
  • Define environment variable SCALA_HOME by editing ~/.bashrc and adding the line:
    export SCALA_HOME=/opt/scala/current
  • Add the Scala executables to your path by editing ~/.bashrc and adding the line:
    export PATH=$PATH:$SCALA_HOME/bin
  • Open a new terminal or load the changes in your ~/.bashrc file using the command:
    source ~/.bashrc
  • Test scala is working using the following command:
    scala -version or scalac -version
    You should see the following as output:
    Scala code runner version 2.8.0.final -- Copyright 2002-2010, LAMP/EPFL
    Scala compiler version 2.8.0.final -- Copyright 2002-2010, LAMP/EPFL

The version of Scala used for compiling the web app is stored in the maven repos and is at the moment (Juli 2010) at version 2.8.0.RC7. It will be downloaded and executed during the build process.

Installation of Java

Ubuntu comes with OpenJDK as standard. You might want to download the official Java from Sun... I mean Oracle:
  • Enable the partner repositories in Synaptic (or uncomment them in /etc/apt/sources.list) and reload the indices:
    sudo apt-get update
  • Download Java
    sudo apt-get install sun-java6-jdk sun-java6-plugin
  • Switch to the Oracle version:
    sudo update-alternatives --config java
    sudo update-alternatives --config javac

Installation of maven2 and jetty

sudo apt-get install maven2 jetty


Your first lift application:

Go into an empty directory an issue the following maven2 command:

mvn archetype:generate \
-DarchetypeGroupId=net.liftweb \
-DarchetypeArtifactId=lift-archetype-blank \
-DarchetypeVersion=2.0-scala280-SNAPSHOT \
-DarchetypeRepository=http://scala-tools.org/repo-snapshots \
-DremoteRepositories=http://scala-tools.org/repo-snapshots \
-DgroupId=com.example  \
-DartifactId=lift.test \
-Dversion=0.1 \
-DscalaVersion=2.8.0.RC7 

An archetype is a project template. lift-archetype-blank is a simple example Lift application, which is downloaded from http://scala-tools.org/repo-snapshots. You can browse this repository at http://scala-tools.org/repo-snapshots/net/liftweb
If you use http://scala-tools.org/repo-releases instead you get older more stable builds. repo-snapshots contains the nightly builds.
  • The artifactId (lift.test) is the name of the top level directory for this project (your choice).
  • The groupId is mapped (Java style: com.example becomes com/example) to the ./src/main/scala directory (also your choice).
  • version refers to the version of YOUR software.
  • scalaVersion of Scala in the maven repo.
After the download the project tree looks like this


This might look scary at first. But there are only 10 files.
./pom.xml
./src/main/scala/bootstrap/liftweb/Boot.scala
./src/main/scala/com/example/snippet/HelloWorld.scala
./src/main/webapp/index.html
./src/main/webapp/templates-hidden/default.html

./src/main/webapp/WEB-INF/web.xml
./src/packageLinkDefs.properties
./src/test/scala/com/example/AppTest.scala
./src/test/scala/LiftConsole.scala
./src/test/scala/RunWebApp.scala 

I'm not sure yet about the last group. My guess is they are used for unit testing and packaging of the WAR files for later deployment.

As for the first group:
  • pom.xml:
    This is the maven configuration file.
    It contains (among others) the URL of the repositories and the dependencies which have to be resolved during the build process. You will rarely edit this file. However, if you need modules that are not within the “standard” scope (e.g. a connector to MySQL servers), you have to edit this file in order to get them drawn into your project.
  • Boot.scala (in ./src/main/scala/bootstrap/liftweb/):
    This file contains code that is run once when the application is started.
    It is used to set-up menus, database connections, etc. You will have to edit this Scala code frequently when you want to use and configure these features.
  • index.html (in ./src/main/webapp/):
    The default template
    This is the template that is evaluated when you access it via the application server without any special file name (e.g. http://localhost:8080/). You will most likely create other templates.
    This particular template refers back to
  • default.html (in ./src/main/webapp/templates-hidden/default.html).
    This is also a template, but one that you will rarely change. It defines the “frame” in which your application runs, i.e. header, footer, menu bar, the html HEAD section (page title, meta tags, CSS definitions, etc.).
    Not all of its content is static. This file may contain Lift tags, most commonly the ones for displaying the menu, to change the page title, and to display feedback to the user (error messages, notices, warnings).
    You may create and use more of these “frame” templates, but in most cases you only need one.
  • HelloWorld.scala (in ./src/main/scala/com/example/snippet/):
    a so called snippet.
    These files contain the Scala code which fills the in the templates (e.g. index.html). This is where most of your coding will happen. You will create more than one snippet file.
Some folders are currently empty:
model, view, comet (in ./src/main/scala/com/example/).

In the example code I have seen so far, Scala code that defines persistent data structures (e.g. for a database) is stored here.

Bringing your application to life

In order to start the application change into the top directory (lift.web) and type
mvn jetty:run

After maven has finished downloading all dependencies and building the application, you can access the web application in your browser via http://localhost:8080

Montag, 9. August 2010

Lift + Scala, Introduction

A recent show of Floss Weekly made me curious about Lift, a web framework using Scala.  

“Scala is a general purpose programming language designed to express common programming patterns in a concise, elegant, and type-safe way.” so they promise  on the Scala website.

The Lift project leader praises his product as “a concise language, frame work with security features, very performant...”

A first glance

Lift, like any framework that you haven't written yourself, will take some time getting familiar with, and Scala, well, it's just another computer language... or so I thought.

Lift

Perhaps the most important feature of Lift is its template system.  These templates are strictly XML based text files without any programming logic.  Tags within the template link to functions in your Scala code that generates some output.  This output (also XML) then replaces the tag.  After a few more processing steps the result is returned to the enquiring web browser, your page gets rendered, end of story.  Yes, there are lots of support features within the framework – like html form generation, database connectivity, page access control – but this is the basic principle of Lift.

Scala

The designers of Scala cherry-picked the best features and concepts from other programming languages, some object-oriented stuff but they also borrowed heavily from functional programming. Its mantra: “everything is an object” and “if it's worth saying, say it with a function”.

Scala's smart compiler can in most cases infer types of variables, so you don't have to declare it manually.  The language has lots of these simplyfications, dramatical reducing boiler plate code.  However, you have to be familiar with these in order to be able to revert the expression back to its more verbose form, otherwise you will scratch your head when you encounter the “Scala smiley”:

 ( _ + _ )

Some language constructs help you avoiding Null pointer dereferences, or to catch all possible cases in a matching construct.  And being a statically typed language  the Scala compiler will be very stubborn if your types don't match.

You can write very elegant code – even though I wouldn't call deeply nested function calls simple to read, at least not yet.

Treacherous simplicity

Letting the compiler infer types looks like a good idea.  On second sight, it also means that you need a good memory or at least a helpful IDE.

Simplifying
   val a: Int = 1

to
   val a = 1

is simple and easy to understand. (The literal 1 is an integer, i.e. “a” must be integer as well). But:

val a = function_i_wrote_ealier_and_dont_remember_the_return_type()
val b = another_cool_function_from_the_web_framework(User => go look)

does work just as well. And now you either know the types or you have to look it up.

The possibility to drop dots and brackets in some situation lets you further “simplify” things:
   a.+(b)

becomes a much more friendlier
   a + b
(+ is a valid function name in Scala).

But
   a :: b

does not mean
   a.::(b)

but
   b.::(a)


(“Operators” that end with “:” bind from right to left).

Another nice feature: When defining a class how often have you assigned the values from the constructor parameter list to class variables for later use? It's usually the first thing you do.  In Scala this is done automatically.  Why hasn't somebody invented this earlier? 

Documentation + support

There is documentation available for Lift and Scala on the web.  While perhaps not exactly light reading, they will get you started.

For Scala http://programming-scala.labs.oreilly.com/index.html from O'Reilly is a good start, and on the Scala website there is http://www.scala-lang.org/docu/files/ScalaByExample.pdf.  Both publications expect that you have done some programming before.

For Lift you should check out master.pdf from http://groups.google.com/group/the-lift-book/files. More information is available at the Lift Wiki and a subscription to the Lift newsgroup is also recommended.

Montag, 28. Juni 2010

Update with caution - Firefox 3.6.6

The recent update to Firefox 3.6.6 seems to cause more problems than usual.

Over here, a Mac was the first to update - and Firefox did not re-start.  Having discovered the safe-mode option recently, I used it on the Mac:

/Applications/Firefox.app/Contents/MacOS/firefox-bin -safe-mode

After disabling all add-ons, Firefox 3.6.6 did start normally.

On my Ubuntu machine, Firefox is still on version 3.6.3.   So I decided to test FF 3.6.6 before the Ubuntu updater pushes the update.  I downloaded the Linux version of 3.6.6 from Mozilla and installed it in a separate directory. 

Multiple versions of Firefox can coexist on the same machine, but only one can run at any given time.  I.e. you have to close ALL Firefox windows of one version before starting the other.

Strangely enough, the new version worked even with the add-ons that crashed Firefox on the Mac.  But there were other issues:
  • no graphics on Google Analytics
  • no address resolution of a web server on the LAN (worked on FF 3.6.3, might be a 64 bit issue - ping is ok)
I think, I'll skip this one.

If the new versions has already been installed...

If you hover your mouse over the appropriate download button on the Mozillas website, you see a link like this one (perhaps with different o/s and language settings) in the status bar:

http://download.mozilla.org/?product=firefox-3.6.6&os=osx&lang=de

You can copy the link, modify the version number to get the older Firefox version.

[Update, June 29th]
Firefox 3.6.6 (32 bit and 64 bit) from the Ubuntu repositories run without problems.

Samstag, 26. Juni 2010

Integrating a re-branded Huawai UMTS modem into Ubuntu 10.04

The Huawai E160 is a popular UMTS stick and works with Ubuntu Lucid Lynx out-of-the-box.

It is also commonly used by European phone companies in their mobile internet starter packs.  Unfortunately these sticks are usually sim-locked to the phone company and some identify themselves with a USB id unknown to current Ubuntu setup.

When you plug the stick into the computer, all you see is a small flash drive icon containing the Windows and sometimes Macintosh drivers.  On these systems the drivers switches the stick from mass storage device mode into modem mode after the initial phase.

The Linux utility for this task is called modem-modeswitch, and can be found in /lib/udev.  The actual task is to automate the execution of this utility when the UMTS stick is plugged in.

The UMTS stick in this example is/was sold by the Belgian phone company Mobistar.  When you query the USB IDs:

sudo lsusb

it is identified as

12d1:1446 Huawei Technologies Co., Ltd. 


The two numbers at the beginning of the line are the vendor ID and product ID of the stick in the current mode.

To check if the modem switch works as expected, call the utility manually:

sudo /lib/udev/modem-modeswitch -v 0x12d1 -p 0x1446 -t option-zerocd

Wait a few seconds and check the USB IDs again.  The entry should now read:

12d1:1003 Huawei Technologies Co., Ltd. E220 HSDPA Modem / E270 HSDPA/HSUPA Modem


If nothing happens, David Santinoli suggests in a related document to unmount the device containing the drivers before attempting the switch.

You can automate the process by creating the file 62-huawai.rules in /lib/udev/rules.d:

ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1446", RUN+="modem-modeswitch -v 0x%s{idVendor} -p 0x%s{idProduct} -t option-zerocd"

(The file name is arbitrary, as long as it starts with “62-” and ends with “.rules”.) The rule itself is based on similar entries in 61-option-modem-modeswitch.rules.

Next time you boot your computer, the rule becomes active, and the modem should be recognized automatically.

Montag, 14. Juni 2010

Firefox - Ausfall der rechten Maustaste

In den letzten Wochen ist es bei mir häufiger vorgekommen, dass Firefox 3.5 (unter Ubuntu 10.04) nicht mehr auf die rechte Maustaste reagierte. Auf dem Desktop und in den übrigen Programmen funktionierte sie weiterhin, sodass ein Problem mit der Maus ausgeschlossen werden konnte.

Der eigentliche Grund des Problems ist weiterhin unklar. Mit dem folgenden Trick kann man Firefox jedoch in den Normalzustand zurücksetzen:

Hierzu beendet man Firefox vollständig und ruft es von der Kommandozeile mit

firefox -safe-mode

auf. Daraufhin erscheint der folgende Bildschirm:



Im Safe-Mode startet Firefox - ähnlich wie der Safe-Mode bei Windows - ohne Erweiterungen.

Wie man sieht kann man fast alles zurücksetzen, was man in den letzten Jahren in mühsamer Kleinarbeit zusammengetragen hat.

"Reset toolbars and controls" scheint die Option mit dem geringsten "Lösch-Potenzial" zu sein, und in meinem Fall reichte sie auch aus. Nach "Make Changes and Restart" reagierte Firefox wieder auf die rechte Maustaste.

Dienstag, 25. Mai 2010

Touch Me, Tux - die Zweite

Im Zuge der in einigen Tagen beginnenden Fußball-WM 2010 verkaufte Aldi-Süd letzte Wochen den „TEVION® Tragbarer 11 cm/4,3'' Touch Multimediaplayer“ (MD 82700) mit eingebautem DVB-T-Empfänger. So können sich die Fußballfans per „Überall-Fernsehen“ auf dem Laufenden halten - wenigstens „überall“ dort, wo es empfangbar ist.

Im Lieferumfang befinden sich neben dem Netzteil, ein USB-Kabel, ein Ohrhörer und eine kleine DVB-T-Magnetfußantenne.

Daneben gibt der Player Videos, Musik und Fotos wieder. Und auch Text kann man sich anzeigen lassen; natürlich kein Vergleich zu Kindle und Co – weshalb das Feature wahrscheinlich nicht einmal beworben wurde.

Das Gerät meldet sich unter Linux als USB-Massenspeicher (MD 82700) an. Je nachdem, ob eine zusätzlich Micro-SD Karte eingelegt ist, erscheinen ein (intern: 4 GB) bzw. zwei USB-Laufwerke. Bilder und Video lassen sich auch mit gängigen Werkzeugen unter Linux so codieren, dass sie vom Player wiedergegeben werden.

Als Wiedergabeformate werden JPEG, MP3, MPEG4, RM, RMVB, Divx und Xvid beworben. Zu RM und RMVB kann ich nichts sagen, da ich unter Linux keine Encoder dafür laufen habe.

Die Angabe von MPEG4 ist zwar nicht falsch, aber vielleicht etwas missverständlich. MPEG4 ist ähnlich wie AVI ein Container-Format. Es sagt nichts über die darin verwendeten Codecs aus.

Um normale Dateien zu  komprimieren gibt unterschiedliche Algorithmen (ZIP, RAR, LZH, usw.). Ein sehr bekannt Algorithmus für Audio ist MP3, aber er ist halt nicht der einzige. Im Open-Souce-Bereich ist auch Ogg Vorbis verbreitet, Mac-User kennen AAC usw. Und auch bei den Videocodecs sind mittlerweile nicht nur Eingeweihten mehrere Codecs bekannt: DivX (und sein Open-Source-Pendant Xvid) sowie MPEG2 von den DVDs.

Häufig genutzte Quellen für MP4-Dateien sind heutzutage Video-Portale wie Youtube und Vimeo. Die dort erhältlichen Videos werden mit dem sehr effektiven Codec H.264 für Video und häufig mit AAC für Audio komprimiert. Diese beiden Codecs versteht das Gerät allerdings nicht. Solche Dateien können nicht direkt wiedergegeben werden und müssen auf dem Computer umcodiert werden.

Wenn man einmal vom DVB-T absieht, so erinnert der Player sehr an das Technaxx-Gerät, mit dem dieses Blog vor über einem Jahr begann. Die verfügbaren Formate, Aufbau und Inhalt der Menüs, exotische Funktionen wie Liedtext-Wiedergabe mit .lirc-Dateien, ähneln sehr der Software im Technaxx-Player. Selbst der vor einem Jahr genannte Konvertier-Befehl kann so (und in leicht abgewandelter Form) verwendet werden.

Von der Auflösung her unterscheiden sich der Technaxx- (320 x 240) und der Medion-Player (480 x 272) nicht sonderlich. Die höhere Pixelzahl ist fast ausschließlich dem Wechsel vom 4:3- zum 16:9-Format zu verdanken; aber natürlich ist der Bildschirm jetzt deutlich größer.

Der Wiedergabe-Chip ist leistungsstärker geworden, so dass viele Einschränkungen weggefallen sind: Es werden höhere Bildfrequenzen (Technaxx: max. 20 Bilder pro Sekunde) und höhere Bitraten für Video und Audio wiedergegeben. Auch B-Frames werden nun unterstützt, die eine höhere Komprimierung erlauben.

Die alten für den Technaxx kodierten Dateien lassen sich daher weiter abspielen. Und da diverse Einschränkungen wegfallen, lassen sich mit Avidemux erstellte Dateien nun direkt verwenden.

Erfolgreich getestete Formate:

Container-Formate: AVI, MP4
Videocodecs: DivX, Xvid
Audiocodecs: MP2, MP3, AC3
Videofrequenz (Bilder/Sekunde): 20, 25
Bildformate: JPEG, BMP

Hier ein Konvertierbefehl im Bausatz

Dateinamen, Ausgabeformat: AVI
mencoder -noodml QUELLDATEI -of avi -o ZIELDATEI

Videocodec XVID, Bitrate
-ovc xvid -xvidencopts bitrate=VIDEOBITRATE:quant_type=h263:me_quality=6
VIDEOBITRATE: je nach Qualität, typische Werte 800 bis 1000

Audiocodec
-oac AUDIOCODEC
AUDIOCODEC: mp3lame, mp2, ac3

Beispiel:
mencoder -noodml ein.mp4 -of avi -o aus.avi -ovc xvid -xvidencopts bitrate=1000:quant_type=h263:me_quality=6 -oac mp3lame



Mittwoch, 19. Mai 2010

The wow factor book

Yesterday, a young man in Australia became victim of his own success.

Andrew Price of blenderguru.com fame had demonstrated in the past that he can produce good and easy to understand blender text and video tutorials.

He peaked the community's interest when he announced an e-book -  “the wow-factor” - about the compositor of Blender 2.5, something that hasn't got a lot of coverage so far.

During the last weeks he released a sample chapter of his book and produced a promotional video worthy of a shopping channel.  Apart from detailing the content of the e-book, it listed all the bonuses which come with it, and culminated in the display of the e-book itself and all the bonuses as CDs and booklets which, of course, all exist - in good Blender fashion - only virtually.

One day before the release he offered a chance to win a free copy of the e-book.  It got 700+ entries which should have been a warning about what was going to hit him.

With only a few hours to go, his website become slower and slower, and when the first message "error 500" appeared, it was clear that the demand crashed his server.  The move to a more powerful home took another 3+ hours which deprived a few of his costumers of the chance to be among the first hundred buyers eligible for “the vault” - the collection of source material which made up the book.

Before going to bed myself, I skimmed the e-book.  It delivers what was promised: an overview of glares, blurs and optical effects - many of which most of us have never heard of - and how to create them in Blender. 

The bonuses provide additional information which are not available in this completeness at this time anywhere else.  The “node encyclopaedia”  for example will save you hours of gathering this information and will hopefully become part of the regular Blender documentation once the final 2.5 version is released, which can still take some time.

The reason that the compositor is not the most prominent feature in most other Blender tutorials is, that it is one of the last steps of creating something in Blender used to polish your render.  This means that you must already have something to work with – a fact that has been taken care of by two video tutorials showing how to build a scene in which to use the effects.  Unfortunately they are only available in a time limited fashion.

All in all it seems to provide a lot of useful information which I can hopefully learn during the coming weeks while reading, watching and listening to the provided material.

I wonder if there were free bonus steak knives mentioned in the commercial... .blend files would suffice. :-)

Freitag, 7. Mai 2010

dbus tutorial - part 3

The last part started with the basic structure of the dbus part of the CD file listing utility and then showed the particular problems with the HAL implementation.

DeviceKit.Disks has to overcome similar problems, but due to the different concepts behind DeviceKit they have to be solved slightly differently.

DeviceKit.Disks

Like HAL, DeviceKit.Disks is another daemon handling devices and is offering similar services under different names. HAL is a jack of all trades, providing information about nearly everything in your system. This lead to its downfall, because the code base became huge and unmaintainable.  DeviceKit on the other hand is split into individual more specialised daemons.  DeviceKit.Disks is strictly focussed on disks and drives.

Differences to HAL from a programmers point of view:
  • As already seen: A different function is used to install the callbacks.
  • The string given to the callback function (e.g. /org/freedesktop/DeviceKit/Disks/devices/sr0)  is the name of a Devkit device. It points to a hardware device (e.g. the CDROM drive) not a volume (the inserted medium).  And because the string already points to the hardware device we don't have to check for any parent object.
  • Being a fixed drive, we also don't need the device_added_callback or device_removed_callback, because the physical CDROM device is not likely to be removed during the lifetime of the program and only changing the medium does not trigger these callbacks. (Note: A USB stick where the physical device itself is being unplugged does trigger these callbacks.).
  • Which leaves the device_changed_callback. However, unlike HAL, there is no indication which property has changed when it is being triggered. We have to track the appropriate properties ourselves.
Initialization
(See part 2)

import gobject
import dbus
...
gobject.threads_init()
dbus.glib.threads_init()


Adding the callback
(See part 1)

bus = dbus.SystemBus()
devkit_object = bus.get_object("org.freedesktop.DeviceKit.Disks",
    "/org/freedesktop/DeviceKit/Disks")
devkit_disks = dbus.Interface(devkit_object, 'org.freedesktop.DeviceKit.Disks')
devkit_disks.connect_to_signal('DeviceChanged', device_changed_callback)

...

def device_changed_callback(device):
    print 'Device %s was changed' % (device)


Device properties in Devicekit.Disks

DeviceKit.Disks devices implement an interface named Properties which gives access to the device properties:

device_object = bus.get_object("org.freedesktop.DeviceKit.Disks", udi)
device_prop = dbus.Interface(device_object, "org.freedesktop.DBus.Properties")
property = device_prop.Get("org.freedesktop.DeviceKit.Disks.Device","name_of_property")

# or

all_properties = device_prop.GetAll("org.freedesktop.DeviceKit.Disks.Device")


Interesting properties are:
  • DriveMediaCompatibility
    description: hardware compatibility
    typical values: optical_cd, optical_cd_r, optical_cd_rw, optical_dvd, optical_dvd_r,  optical_dvd_ram
  • DeviceIsOpticalDisc
    typical values: 0/1
    0: disk tray empty
    1: optical media has been found
  • DeviceIsMounted
    typical values: 0/1
    0: nothing mounted yet
    1: valid DeviceMountPaths
  • IdLabel
    description: label of CD/DVD
  • DeviceMountPaths
    descirption: mount point, if a CD/DVD has been mounted
  • OpticalDiscIsBlank
    typical values: 0/1
    0: media in the drive is not blank
    1: media in the drive is blank
  • DeviceIsRemovable
    typical values: 0/1
    1: device can contain removable media (-> Eject should work)
See also: http://hal.freedesktop.org/docs/DeviceKit/

You can get a quick overview with human readable property names with

devkit-disks --dump | more

How to filter out events that are not CD related

The most promising way is to check DriveMediaCompatibility for the value optical_cd or optical_dvd.

device_object = bus.get_object("org.freedesktop.DeviceKit.Disks", udi)
device_prop = dbus.Interface(device_object, "org.freedesktop.DBus.Properties")
md = device_prop.Get("org.freedesktop.DeviceKit.Disks.Device","DriveMediaCompatibility")
print "is CD-ROM:", (u"optical_cd" in md) or (u"optical_dvd" in md)


If you observe the events (using the dbus-monitor) when inserting or ejecting a CD, the following patterns emerge:
(I haven't found any authoritative documentation yet, but the steps seem logical):
  • When the CDROM tray is empty:
    DeviceIsOpticalDisc == 0
  • Blank medium inserted:
    DeviceIsOpticalDisc == 1
    OpticalDiscIsBlank == 1
  • After ejecting the blank medium:
    DeviceIsOpticalDisc == 0

  • Insert a medium containing data
    • step 1 (medium gets recognized):
      DeviceIsOpticalDisc == 1
      OpticalDiscIsBlank == 0
      DeviceIsMounted == 0
    • step 2 (medium gets auto mounted):
      DeviceIsOpticalDisc == 1
      OpticalDiscIsBlank == 0
      DeviceIsMounted == 1
  • eject medium:
    • step 1 (auto umount)
      DeviceIsOpticalDisc == 1
      OpticalDiscIsBlank == 0
      DeviceIsMounted == 0
    • step 2 (eject)
      DeviceIsOpticalDisc == 0
      OpticalDiscIsBlank == 0
      DeviceIsMounted == 0

  • If DeviceIsOpticalDisc is being set to 1, the property IdLabel becomes valid.
  • If DeviceIsMounted is being set to 1, the property DeviceMountPaths becomes valid.
When to read the file list

As DeviceKit.Disks does not provide the information which property was modified, we have to track the state of DeviceIsMounted ourselves and read the files below the mount point(s) when DeviceIsMounted changes from 0 to 1.

Eject via software

This function is located in the interface org.freedesktop.DeviceKit.Disks.Device. Note that a volume must be unmounted first before it can be ejected (see property DeviceIsMounted).

system_bus = dbus.SystemBus()
device_object = system_bus.get_object("org.freedesktop.DeviceKit.Disks", udi)

# get properties
device_prop = dbus.Interface(device_object, "org.freedesktop.DBus.Properties")
all_properties = device_prop.GetAll("org.freedesktop.DeviceKit.Disks.Device")

# call unmount/eject depending on the device state
disk_dev_func = dbus.Interface(device_object, "org.freedesktop.DeviceKit.Disks.Device")
if all_properties['DeviceIsMounted'] == 1:
    disk_dev_func.FilesystemUnmount('')
if all_properties['DeviceIsOpticalDisc'] == 1:
    disk_dev_func.DriveEject('')


With this, we have all the building blocks for DeviceKit.disks implementation of the CD file listing utility

Mittwoch, 28. April 2010

dbus tutorial - part 2

Implementation overview

The first part introduced the dbus components and how to access them using Python.

The goal is to write a program that lists and stores the names of the files on a CD after it has been inserted.  The basic steps are:
  1. Initialize dbus
  2. Wait for the notification when a CD is inserted into the drive.
  3. Wait for the notification when the volume is mounted by the (Gnome) automounter
  4. Read the file list below that mount point and store the info.
  5. Then perhaps eject the CD.
  6. Go back to step 2

Initialize dbus: Starting dbus threads

In order to get the dbus communication running in the python application, the following threads have to be started before you connect to any bus:

import gobject
import dbus
import dbus.glib
...
gobject.threads_init()
dbus.glib.threads_init()


This piece of code uses Python threads in the background. 


HAL implementation specifics

In the first part we've seen how callbacks are hooked into the system:

bus = dbus.SystemBus()
bus.add_signal_receiver(device_added_callback,
                                 "DeviceAdded",
                                 "org.freedesktop.Hal.Manager",
                                 "org.freedesktop.Hal",
                                 "/org/freedesktop/Hal/Manager")
bus.add_signal_receiver(device_removed_callback,
                                 "DeviceRemoved",
                                 "org.freedesktop.Hal.Manager",
                                 "org.freedesktop.Hal",
                                 "/org/freedesktop/Hal/Manager")


When a CD is inserted DeviceAdded receives a string like this:

/org/freedesktop/Hal/devices/volume_label_backupcd1________

When the CD is ejected, DeviceRemoved is executed, receiving the same information.  I'll refer to this string as udi in the following code.

This string refers to an HAL object, and describes a volume i.e. the medium you inserted, not the actual hardware (i.e. the CDROM drive).  To get more information about this volume you have to get the HAL object via bus.get_object (as described before):

d_object = bus.get_object('org.freedesktop.Hal',udi)

Objects starting with /org/freedesktop/Hal/devices/... implement the interface org.freedesktop.Hal.Device, which in turn exposes (among others) the function GetAllProperties which returns a dictionary that contains further useful information:

d_interface = dbus.Interface(d_object,'org.freedesktop.Hal.Device')
properties = d_interface.GetAllProperties()


Interesting keys in this dictionary are:
  • volume.label
    description: CD label
    typical value: empty, backup123
  • volume.disc.has_data
    description: data disk
    typical value: 0, 1
  • volume.disc.is_blank
    description: blank media
    typical value: 0, 1
  • volume.mount_point
    description: CD mount point
    typical value: /media/backup123
  • block.device
    description: linux device descriptor
    typical value: /dev/sr0
  • storage.drive_type
    typical value: cdrom
See also HAL specification

To get a quick overview, type

lshal | more

in a shell.  (You will need the more command.)

The interface org.freedesktop.Hal.Device (implemented by all .../Hal/devices/ ) also contains the signal PropertyModified - which will be fired when properties change (in our example: the info volume.mount_point is empty when the device is added.  It becomes available later when the auto-mounter of the desktop framework has mounted the device.).  You can add a callback for this signal:

def device_added_hook(udi):
    ....
    bus.add_signal_receiver(property_modified_callback,
           "PropertyModified",
           "org.freedesktop.Hal.Device",
           "org.freedesktop.Hal",
           udi)

def property_modified_callback(numupdates,updates):
    ...


numupdates are the number of entries in a list of updates.  An "update" is a tuple with the following signature: (key_name, was_added, was_removed)

If a CD/DVD was mounted, the list of updates contains (among others) the following tuples:

('volume.mount_point', False, False)
('volume.is_mounted', False, False)


This means that the property was neither added (1st False) nor removed (2nd False), it was merely modified.  We don't get any information about the new value of the property and more importantly we don't get any information about the object (i.e. the device) that triggered it.

For this reason the method add_signal_receiver can be extended:

...
    bus.add_signal_receiver(property_modified_callback,
           "PropertyModified",
           "org.freedesktop.Hal.Device",
           "org.freedesktop.Hal",
           udi,
           path_keyword = "sending_device" )


The parameter path_keyword defines the name of an additional parameter (in this example sending_device) for the property_modified_callback which will contain the “path” - or in my parlance “the object” - that triggered the signal.  Now the property_modified_callback looks like this:

def property_modified_callback(numupdates, updates, sending_device = None):
    ...



Apart from path_keyword, add_signal_receiver can define even more additional parameters for the callback function:

  • sender_keyword - for the connection name (usually in the internal numeric format)
  • destination_keyword - None for broadcasts
  • interface_keyword - interface name
  • member_keyword - signal name
  • path_keyword - object name
each followed by a string containing the name of the parameter in the callback function.  The variable will contains the appropriate information.

HAL implementation: Filter out events that are not CD related

DeviceAdded is called for every new device in the system (network devices, bluetooth devices, etc.), and the property_modified_callback is invoked if any property of any device changes.

In order to filter out the CD related calls, we have to check the properties for suitable keys.

First, we have to ensure that the object describes a volume.  For this we have to check if the property block.is_volume is present, and if so, that it is set to True.
The object will then have a property named info.parent, pointing back to the physical drive.

After retrieving the properties of that parent object, we first check block.is_volume, which has to be set to False, and then obtain the value of storage.drive_type, which is set to "cdrom", if the device is an optical drive.

...
# get object of the device that triggered the property_modified_callback
d_object = self.system_bus.get_object('org.freedesktop.Hal',sending_device)
d_interface = dbus.Interface(d_object,'org.freedesktop.Hal.Device')

# get their properties
d_properties = d_interface.GetAllProperties()

if not d_properties.has_key("block.is_volume"): return
if not d_properties["block.is_volume"]: return

parent_device = d_properties["info.parent"]
p_object = system_bus.get_object('org.freedesktop.Hal',parent_device)
p_interface = dbus.Interface(p_object,'org.freedesktop.Hal.Device')
p_properties = p_interface.GetAllProperties()
if not p_properties["block.is_volume"]:
   if p_properties["storage.drive_type"] == "cdrom":
       # further code here



Another approach is to get the list of all optical drives when the utility is launched and check the parent udi against this list:

system_bus = dbus.SystemBus()
hal_object = system_bus.get_object('org.freedesktop.Hal', '/org/freedesktop/Hal/Manager')
hal_manager = dbus.Interface(hal_object, 'org.freedesktop.Hal.Manager')
...
installed_optical_drives = hal_manager.FindDeviceStringMatch("storage.drive_type","cdrom")
...
if parent in installed_optical_drives:
   ...


Mount point is empty
At the time when the device is added volume.mount_point is empty.  That's why the signals DeviceAdded and DeviceRemoved are not important in our application.  You might want to use them anyway to display the state of your drive (e.g. disk inserted or nor) in the GUI.

The import part is the property_modified_callback.  After the checks described above we know the label of the CD and its mount point.  With this information we can obtain a file list and store it in any form we want.



The next part will show how DeviceKit.Disks handles these problems.

Freitag, 23. April 2010

dbus tutorial - part 1

Basic dbus concepts

What is dbus?

dbus is part of most modern Linux distros.  It handles interprocess communication, either between desktop applications or between systems daemons and applications (e.g. a desktop framework like Gnome or KDE, or user applications).


Overview

The goal of this series of postings is the creation of a small desktop example application written in Python which reads the name of the files on a CD or DVD after the media has been inserted, and to store these names together with the CD label in a file.  The graphical user interface will be based on wxWidgets. 

The first part contains an introduction to the basic dbus components.
The second part discusses the implementation using the Hardware Abstraction Layer (HAL).
The following part shows the differences in implementation between HAL to the DeviceKit.Disks.


Prerequisites

Python: which is part of any current Linux distribution. (I'm using Python 2.6).
python-dbus: the dbus bindings for Python
python-wxgtk2.8: wxWidgets and its Python bindings (for the GUI)

Useful additions


python-wxglade: GUI builder for wxWidgets, creates Python source code (and C source code...)

d-feet: graphical display of dbus components

dbus components

In our example dbus is used to catch the notifications sent by the kernel when a CD or DVD has been inserted, as well as the notification when Gnome has mounted this medium. (There were times when you had to do this manually.)

In some places I will differ from the official dbus designations for these components to make their distinction easier.  In some cases different components share the same name.  This makes their close relation quite obvious, but it becomes difficult to determine if a given name refers to a connection or an interface, for example.


Buses

In dbus “buses” are at the root of a hierarchy.  In normal applications you encounter mostly the following two buses:

    bus = dbus.SessionBus()

for communication between desktop applications, and

    bus = dbus.SystemBus()

for communication with system programs and daemons like the NetworkManager, the ModemManager, the Hardware Abstraction Layer daemon (HAL) or DeviceKit, to name but a few.

When you insert a disc, a notification is routed via HAL or DeviceKit, depending on which daemon is installed.

Note: Ubuntu Karmic uses HAL and DeviceKit simultaneously.  However, the Hardware Abstraction Layer is being phased out from most Linux distributions, and the upcoming version of Ubuntu 10.04 (Lucid Lynx) will drop it completely.



Connections


“Connections” are the layer below the buses.  You can use a "connection" to “connect” to a specific daemon or application.  Please note the dotted notation:
The NetworkManager is available via a connection named org.freedesktop.NetworkManger

The connection org.freedesktop.Hal will connect you to the HAL daemon. 
The "disks" part of DeviceKit is available via the connection named org.freedesktop.DeviceKit.Disks.


Objects

These programs (NetworkManager, HAL, DeviceKit.Disks, etc.) will offer their services via one or more "objects".  Object names contain slashes and look like file paths, which might be the reason that they are sometimes called "paths". 

Examples:
/org/freedesktop/Hal/devices
/org/freedesktop/Hal/Manager
/org/freedesktop/Hal/devices/volume_label_backupcd1________
/org/freedesktop/DeviceKit/Disks/devices/sr0


Interfaces

Objects export methods and and signals grouped into one or more "interfaces".  The names of these interfaces again contain dots, e.g. org.freedesktop.Hal.Manager or org.freedesktop.DeviceKit.Disks.Device


Methods

Methods are functions you can invoke.  One method of the org.freedesktop.Hal.Manager interface for example is DeviceExists.  The interface org.freedesktop.DeviceKit.Disks implements e.g. EnumerateDevices, etc.


Signals

An interface may also export "signals".  Signals of the org.freedesktop.Hal.Manager interface that we are going to use are DeviceAdded and DeviceRemoved, which are triggered  when you put a new CD into the drive or eject it, but also if any other device is added (an USB stick, a new network interface, etc.), as well as the signal PropertiesModified.



Introspect

One interface that is implemented by all objects is org.freedesktop.DBus.Introspectable which offers one method: Introspect()
This function returns a description of the object's interfaces, i.e. what methods and signals are available and what parameters they use.  The above mentioned utility d-feet uses this method to display the information in a nice graphical way.  (Note: In d-feet a "Connection" is called "Bus Name").


If you want to see the dbus messaging at work (for the SystemBus) open a shell and start:

dbus-monitor --system


Summary

  • bus: top level (SessionBus or SystemBus)

  • connection: from the bus to a daemon; names with dots

  • object: logical part within that daemon; names with slashes

  • interface: one or more within an object (same interface on different objects means same API (methods and signals)); names with dots

  • methods and signals (none or more within an object)



Examples

How to call a method (HAL)

In order to call a method like DeviceExists, you have to know, that this particular function is
  1. part of the interface org.freedesktop.Hal.Manager

  2. that this interface is implemented by the object named /org/freedesktop/Hal/Manager

  3. which in turn can be reached via the connection org.freedesktop.Hal

  4. on the SystemBus


In Python:

# (4)
bus = dbus.SystemBus()
# (3 + 2)
object = bus.get_object("org.freedesktop.Hal","/org/freedesktop/Hal/Manager")
# (1)
interface = dbus.Interface(object,"org.freedesktop.Hal.Manager")
#
result = interface.DeviceExists(...)

As mentioned earlier, you have to know which parameter of bus.get_object and dbus.Interface is the object name, the connection name, and the interface name.  The names themselves are usually not a great help.


Signal callbacks (HAL)

In order to make dbus call a method in your program when a signal is triggered you have to add a signal receiver:

bus.add_signal_receiver(
   handler_name_in_your_program,
   "signal_name",
   "interface_name",
   "connection_name",
   "object_name")


The handler method looks like this:

def handler(...):
   ...

The parameters used when this handler is executed (the so called "signature") differ from signal to signal.  (This info can be obtained via the Introspect interface.)  Here the example for the methods DeviceAdded and DeviceRemoved:


bus = dbus.SystemBus()
bus.add_signal_receiver(device_added_callback,
                                 "DeviceAdded",
                                 "org.freedesktop.Hal.Manager",
                                 "org.freedesktop.Hal",
                                 "/org/freedesktop/Hal/Manager")
bus.add_signal_receiver(device_removed_callback,
                                 "DeviceRemoved",
                                 "org.freedesktop.Hal.Manager",
                                 "org.freedesktop.Hal",
                                 "/org/freedesktop/Hal/Manager")

....

def device_added_callback(udi):
    print udi

def device_removed_callback(udi):
   print udi


(More on add_signal_receiver in the next post)


How to call a function (DeviceKit.Disks)

The fundamental dbus principles described in the HAL example still apply:

# (4)
bus = dbus.SystemBus()
# (3 + 2)
devkit_object = bus.get_object("org.freedesktop.DeviceKit.Disks",
                       "/org/freedesktop/DeviceKit/Disks")
# (1)
devkit_disks = dbus.Interface(devkit_object, 'org.freedesktop.DeviceKit.Disks')
#
all_devices = devkit_disks.EnumerateDevices()


Note: This time the connection/object/interface names are nearly identical.  Keep in mind which parameter describes what


Signal callbacks (DeviceKit.Disks)
Even tough a few handler names are identical to HAL and their functions are similar, their parameters are different.  Also note that the way DeviceKit.Disks adds callbacks is different:


devkit_disks.connect_to_signal('DeviceAdded', device_added_callback)
devkit_disks.connect_to_signal('DeviceRemoved', device_removed_callback)
devkit_disks.connect_to_signal('DeviceChanged', device_changed_callback)

def device_added_callback(device):
    # not really needed
    print 'Device %s was added' % (device)

def device_removed_callback(device):
    # not really needed
    print 'Device %s was removed' % (device)
 
def device_changed_callback(device):
    print 'Device %s was changed' % (device)



 
Other daemons

There are other interesting daemons, like the ModemManager, which not only can control modems, but also allows access to your mobile phone, SMS etc.

Samstag, 10. April 2010

Ein Tag ohne E-Mail

Nach einem Sicherheitsupdate in Ubuntu Karmic meldete sich Thunderbird beim Start mit:

Die Sicherheitskomponente der Anwendung konnte nicht
initialisiert werden. Der wahrscheinlichste Grund dafür sind
Probleme mit Dateien im Profil-Ordner Ihrer Anwendung.
Bitte stellen Sie sicher, dass der Ordner keine Lese- und
Schreibbeschränkung hat und Ihre Festplatte nicht voll oder
fast voll ist. Es wird empfohlen, dass Sie die Anwendung
jetzt beenden und das Problem beheben. Wenn Sie diese Sitzung
weiter verwenden, können Sie unkorrektes Verhalten der Anwendung
beim Zugriff auf Sicherheitsfunktionen feststellen.
und sämtliche mit SSL gesicherten Verbindungen zu POP- und SMTP-Servern schlugen fehl... und das sind bei mir alle.

I hate it when this happens.


Gegenmaßnahmen, die ich bei einer ersten Google-Suche nach dieser Fehlermeldung gefunden hatte (Neuinstallation von Thunderbird, Löschen von cert8.db, Anlegen eines neuen Profils) waren jedoch wirkungslos.

Beim Sicherheitsupdate wurde unter anderem die Bibliothek libnss aktualisiert, die für Verschlüsselung zuständig ist.

Ein Eintrag im Ubuntu-Form bestätigte diesen Verdacht. In meinem Fall reichte es, die veraltete Bibliothek libnss3-0d in Synaptic zu deinstallieren.

Samstag, 13. März 2010

T60: Die Tastatur, die Henne und das Ei

Seit einigen Wochen habe ich einen neuen Laptop...

Naja, ein Gebrauchtgerät - Lenovo T60 - erworben beim Gebraucht-Laptop-Händler meines Vertrauens, bei dem ich über die Jahre schon einige Geräte der jeweils vorletzten Generation erworben habe.

Wie bei früheren Laptops, so hatte auch dieser eine ausländische Tastatur. Der Laptop kam mit Etiketten zum Überkleben der Tasten. Das war bei früheren Käufen auch so gewesen und die Etiketten halten immer noch.

Unterdessen läuft Ubuntu Karmic mit Gnome auf dem Rechner. Die diversen Funktionstasten werden unterstützt (laut, leise, heller, dunker) und auch Blender ist dank der Kraft der zwei Kerne halbwegs flott.

Etwas gestutzt hatte ich dann gestern, als ich auf der Kommandozeile eine etwas längere Ausgabe mit | less seitenweise anzeigen wollte. Nirgendwo war der senkrechts Strich zu finden.

Sollten die Aufkleber doch nicht so vollständig gewesen sein? Nachdem ich alle Tasten mit gedrückter Alt-Gr-Taste durchprobiert hatte stand fest: kein senkrechter Strich. Nun gut, dann eben eine Umleitung in eine Datei - aber auch das Größerzeichen war nirgends zu finden.

Fehlt also eine Taste?

Die Antwort ist: ja. Nach ein wenig googlen fand ich auf Notebookcheck ein Bild des Laptops mit aufgeklappter Tastatur. Die dort gezeigte Tastatur (oben rechts) hat im Gegensatz zu meiner eine schmalere linke Shift-Taste. In dem freiwerdenden Zwischenraum liegt normalerweise: < > |

Wahrscheinlich hat Sprache, für die die Tastatur eigentlich ausgelegt ist, weniger Sonderzeichen, braucht weniger Tasten und das < > befinden sich irgendwo unter den Tasten Ä Ö oder Ü.


Was also tun? Ohne "größer" und "kleiner" ist das Programmieren recht umständlich. Und wie häufig man auf der Kommandoebene die Pipe benutzt merkt man erst dann, wenn es nicht mehr geht...

Umdefinieren der Tastatur mit Xmodmap

Im Ubuntu-Wiki gibt es hierzu einen ausführlichen Eintrag.

Erster Schritt: Auslesen der aktuellen Zuweisung.

Hierzu muss im Home-Verzeichnis der Befehl

xmodmap -pke > .Xmodmap

eingegeben werden, was bei fehlendem ">" ein echtes Henne- und Ei-Problem ist. (Ich habe schließlich auf einem anderen Rechner (mit voller Tastatur) ein einzeiliges Skript geschrieben und auf den Laptop kopiert).

Sucht man in .Xmodmap nach "greater", so findet man zwar:

keycode 94 = less greater less greater bar brokenbar bar

Versucht man aber - nach Aufruf des Programms xev - die Taste mit dem Keycode 94 zu finden, so wird man nicht fündig. Ich habe mich schließlich für die Tasten "Blättern" (links und rechts über "Cursor links" und "Cursor rechts", Keycode 166 bzw. 167) entschieden und die Belegung dort wie folgt geändert:

keycode 166 = less bar XF86Back NoSymbol XF86Back
keycode 167 = greater NoSymbol XF86Forward NoSymbol XF86Forward

Nachdem Aufruf

xmodmap .Xmodmap

sind die fehlenden Zeichen nun zugänglich.

Spezielle Behandlung von ~/.Xmodmap

Nach einer einmaligen Nachfrage beim nächsten Einloggen wird die geänderte Tastaturbelegung unter X dauerhaft aktiv.


Montag, 1. März 2010

Hugin - Probleme unter Windows

Hugin ist ein Open-Source-Projekt dessen Software u.a. dazu eingesetzt werden kann mehrere Einzelbilder zu einem Panorama zu kombinieren, ein Vorgang, der als "Stiching" bezeichnet wird.

Damit die Aufnahmen nahtlos ineinander übergehen müssen sog. Kontrollpunkte gesetzt werden. Der Kontrollpunkt in Bild A und der zugehörige Kontrollpunkt in Bild B bezeichnen den gleichen Ort in der realen Welt.

Man kann diese Kontrollpunkte von Hand setzen, aber auch dafür gibt es mittlerweile Hilfsprogramme. Ein bei Hugin-Usern sehr beliebtes (weil schnelles) Programm ist autopano-sift-c. Es sucht in den Bildern nach markanten Punkten und versucht diese zuzuordnen.

Im nächsten Schritt beginnt Hugin anhand dieser Daten die Bilder passend zu verzerren, zu verschieben und zu überblenden.

Die Probleme


Hugin ist mittlerweile auf diverse Plattformen portiert - so auch Windows - von wo mich der Hilferuf erreichte, der zu diesem Posting führte. Es waren mehrere Probleme aufgetreten, die das Programm unbrauchbar machten.

Hugin wird bei SourceForge gehostet. Die zurzeit (März 2010) dort verfügbare Windows-Version ist schon 2 Monate alt.

Unterdessen sind compilierte neuere Builds aus dem Hugin Subversion Repository aus anderen Quellen verfügbar und mein Bekannter hatte das neuste Build installiert (als User von Blender 2.5 kann ich das nachfühlen).
Diese Builds führen jedoch beim Laden der von ihm verwendeten TIFF-Dateien zu einem "TIFF library error". Ein Downgrade auf die ältere SourceForge-Version beseitigte das Problem.

Auch beim Suchen der Kontrollpunkte ist die neuere Variante (Autopano-SIFT-C version 2.5.2 23July2009) nicht die bessere.

Das Fehlerbild hier: Hugin meldet, dass keine Kontrollpunkte gefunden wurden.

Ruft man das Programm über die Kommandozeile auf, erkennt man, dass zwar einige Punkte gefunden werden (einige Hundert), normal sind jedoch 1000 und mehr. So verwundert es nicht, dass beim Abgleich, welche markanten Punkte aus Bild A zu denen in Bild B passen könnten, zum Schluß keiner übrig bleibt.

Abhilfe schafft hier, wie von Bart van Andel in einem Google-Groups-Thread beschrieben, die ältere Version 2.5.1 (Download Link siehe erwähnter Thread). Das Einbinden der neuen Version erfolgt über "Datei - Einstellungen - Kontrollpunkt-Detektoren".

Fazit

Sollte eines der oben erwähnten Probleme auftreten, so scheint zurzeit die folgende Kombination am stabilsten zu laufen:

Hugin_2009.4 von SourceForge und Autopano-SIFT-C 2.5.1.

Samstag, 20. Februar 2010

Blender 2.5 alpha 1 verfügbar


Seit heute ist Blender 2.5 alpha 1 verfügbar.

Dieses offizielle Release läuft auch unter Ubuntu Hardy - der (noch) aktuellen LTS-Version von Ubuntu.

Bei den aktuelleren Blender Builds auf GraphicAll.org war das seit dem Übergang von Alpha 0 auf Alpha 1 leider nicht mehr der Fall.

Freitag, 1. Januar 2010

Python: cStringIO vs. StringIO

If a function expects a file handle as an input parameter, but the data you want to process is stored in a string variable, you could store its content in a temporary file on disk, then open that file and use its file handle for the above mentioned function.

A nicer way to do this is the python function StringIO in the StringIO library. It takes the string as an argument and returns a file handle, from which the function can read(). The conversion happens in memory, i.e. no tedious creation of temporary files.

Depending on how often you need this functionality and how large the data is, the StringIO.StringIO - which is programmed purely in Python - may be too slow.

The library cStringIO offers a function with the same name with the same functionality carried out by a faster C-implementation. This function should be a drop-in replacement for the Python version.

However, since more and more strings are stored in unicode this function has an unexpected side effect. This side effect is detailed in the library description, if you look close enough.

cStringIO.StringIO does not return the original encoded text, but the "representation of the Unicode string", which may differ from machine to machine:

>>>import StringIO
>>> a = StringIO.StringIO(u"test")
>>> a.read()
u'test'

>>>import cStringIO
>>> a = cStringIO.StringIO(u"test")
>>> a.read()
't\x00\x00\x00e\x00\x00\x00s\x00\x00\x00t\x00\x00\x00'


A patch to fix this was proposed but rejected due to backwards compatibility.

So be aware...