niedziela, 19 grudnia 2010

OpenWRT + Lighttpd + Fastcgi + Django


Here's something I was fighting with for about 3 days. At first I wanted to use virtualenv too, but it all resulted in a headache. I'm a novice in these matters, so forgive me.

Recently I bought a router TP-Link WR-1043ND. Not the best choice now, I'm aware: TP-Link MR3420 has higher quality to price ratio. Anyway, my router got upgraded to OpenWRT, version Backfire 10.3-RC4, thanks to great work of Cezary Jackiewicz aka Obsy.


Opkg packages

First packages that we can install with OpenWRT package manager:

  • lighttpd, lighttpd-mod-alias, lighttpd-mod-rewrite, lighttpd-mod-fcgi - packages needed for http server called lighty
  • pysqlite, libsqlite3 - the database
  • python wasn't installed at first, so we'll need this too
opkg install lighttpd lighttpd-mod-alias lighttpd-mod-rewrite lighttpd-mod-fcgi
opkg python libsqlite3 pysqlite

Python packages

These will be installed from Python Package Index (PyPI). We will need:

  • setuptools - Go to, search for setuptools, follow the instructions.
  • pip - We should be able to call: easy_install pip to obtain it.
  • django - With pip in place getting django is as easy as pip install django. Pip, contrary to easy_install, has a nice uninstall option.
  • flup - For FastCGI related stuff
There we go. It's all installed.


3 ways of doing this

First of all, let me briefly explain how FastCGI works. Actually this might not be a good idea to believe me, because, as I said, I'm a layman in this matters. There are 3 entities in this process: the browser, the server (Lighttpd), the FastCGI process (Django).
First step is forwarding the http request for a webpage to FastCGI process:
Browser => Lighttpd => Django FCGI
Request is processed and Django returns html source code of a webpage. Shove it back to your browser and render it.
Browser <= Lighttpd <= Django FCGI
    I came to conclusion that there are 3 ways of setting this up.
  1. By bin-path
  2. By host and port
  3. By socket

My app's directory: /www/apps/homepage. It doesn't have to be anything fancy. It's ok to use brand new project created with startproject homepage.


This method is my favourite so far. We tell lighttpd where to find executable file .fcgi and it starts FCGI processes by itself. All we need to take care of now is that the server is started after reboot. Here are the details:

  • Contents of .fcgi file. It sits at the django project's directory.
    #!/usr/bin/env python
    import sys, os
    # Add a custom Python path.
    sys.path.insert(0, "/www/apps")
    # Set the DJANGO_SETTINGS_MODULE environment variable.
    os.environ['DJANGO_SETTINGS_MODULE'] = "homepage.settings"
    from django.core.servers.fastcgi import runfastcgi
    # maxspare=2 is minimum from what i saw
    runfastcgi(method="threaded", daemonize="false", maxspare=2)
  • Lighttpd config file from /etc/lighttpd/lighttpd.conf. It is edited version of default config file. I just omitted most of commented out lines.
    # lighttpd configuration file
    ## modules to load
    # all other module should only be loaded if really neccesary
    # - saves some time
    # - saves memory
    server.modules = ( 
    # "mod_redirect", 
    # "mod_auth", 
    # "mod_status", 
    # "mod_setenv",
    # "mod_proxy",
    # "mod_simple_vhost",
    # "mod_cgi",
    # "mod_ssi",
    # "mod_usertrack",
    # "mod_expire",
    # "mod_webdav"
    # force use of the "write" backend (closes: #2401) = "write"
    ## a static document-root, for virtual-hosting take look at the 
    ## server.virtual-* options
    server.document-root = "/www/public"
    ## where to send error-messages to
    server.errorlog = "/var/log/lighttpd/error.log"
    ## files to check for if .../ is requested
    index-file.names = ( "index.html", "default.html", "index.htm", "default.htm" )
    ## mimetype mapping
    mimetype.assign = (  
     ".pdf"   => "application/pdf",
     ".class" => "application/octet-stream",
     ".pac"   => "application/x-ns-proxy-autoconfig",
     ".swf"   => "application/x-shockwave-flash",
     ".wav"   => "audio/x-wav",
     ".gif"   => "image/gif",
     ".jpg"   => "image/jpeg",
     ".jpeg"  => "image/jpeg",
     ".png"   => "image/png",
     ".css"   => "text/css",
     ".html"  => "text/html",
     ".htm"   => "text/html",
     ".js"    => "text/javascript",
     ".txt"   => "text/plain",
     ".dtd"   => "text/xml",
     ".xml"   => "text/xml"
    $HTTP["url"] =~ "\.pdf$" {
     server.range-requests = "disable"
    # which extensions should not be handle via static-file transfer
    # .php, .pl, .fcgi are most often handled by mod_fastcgi or mod_cgi
    static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
    ## to help the rc.scripts = "/var/run/"
    #### fastcgi module
    ## read fastcgi.txt for more info
    # this line may help with finding what's wrong, check out errorlog file
    # fastcgi.debug=1
    fastcgi.server = (
     "/homepage.fcgi" => (
      "main" => (
       "host" => "",
       "port" => 3033,
       "check-local" => "disable",
       "max-procs" => 1,
       "bin-path" => "/www/apps/homepage/homepage.fcgi"
    alias.url = (
                    "/media" => "/www/apps/homepage/media",
    url.rewrite-once = (
                    "^(/media.*)$" => "$1",
                    "^/favicon\.ico$" => "/media/favicon.ico",
                    "^(/.*)$" => "/homepage.fcgi$1",


You don't need .fcgi file in this method. Remove line with "bin-path" in fastcgi.server section of lighttpd config. Now you need to make sure that you run this at every boot (maybe you can use start-stop-daemon tool for this):

/www/apps/homepage/ runfcgi method=threaded host="" port=3033
This will start FastCGI threads. Lighttpd will expect them to be there when he needs a page. Otherwise you'll get 503 or 500. This method is said to be easier because there is no need to set permissions on TCP socket.


In this method FCGI process and HTTP Server communicate through a socket (aka named pipe). Proper permissions must be in place. FCGI file is also not needed here. You must make sure that you run similar command as in the second method:

/www/apps/homepage/ runfcgi method=threaded socket=/www/apps/homepage/homepage.socket
Lines in fastcgi.server with port and host get removed. Instead add
"socket" => "/www/apps/homepage/homepage.socket"


I use a lot of bad practices here:

  • do everything as root
  • not using virtualenv
  • keeping my app in /www (but I changed my document-root, so maybe I'm ok?)
This is an example of work done by someone who came from "no idea" to "it started working" and all this happens on a router that won't be under a lot of load or work in a cloud of virtual machines. Certainly it's not state of the art, but gets the job done.

There's quite a lot of this kind of tutorials, but to someone without proper knowledge all these terms and blindly followed instructions are no good if something doesn't work as expected. I hope someone will find the wording I used useful. I hope will when I'll need to do everything all over again.

czwartek, 12 sierpnia 2010

Kernel log spammed with rt2500 errors

My wifi card kept spamming kernel log with messages like this: "phy0 -> rt2500pci_set_device_state: Error - Device failed to enter state 1 (-16)". The solution is easily found among launchpad bug reports. Power management needs to be turned off for the card. It's easy to do:

iwconfig wlan0 power off

To make it permanent edit /etc/rc.local adding this line before exit 0. Reboot and you're done! Confirm that with calling iwconfig:

lo        no wireless extensions.

eth0      no wireless extensions.

wlan0     IEEE 802.11bg  ESSID:"TP69"  
          Mode:Managed  Frequency:2.422 GHz  Access Point: 00:23:CD:15:F2:A0   
          Bit Rate=48 Mb/s   Tx-Power=20 dBm   
          Retry  long limit:7   RTS thr:off   Fragment thr:off
          Power Management:off
          Link Quality=60/70  Signal level=-50 dBm  
          Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0
          Tx excessive retries:0  Invalid misc:0   Missed beacon:0

wtorek, 1 czerwca 2010

First success with RTAI

Recently I've been trying to grok Real Time Application Interface (more on It certainly wasn't a walk in the park, but still far far easier than RTLinux. This time at least I had a clue what was going on. Following this tutorial worked for me:

Finally when everything is set up you can do: sudo start_rtai on command line. This starts RTAI.

Now for some programming. Here's a snippet:

/* led1.c, an LXRT LED blinker */

#include <rtai_lxrt.h>
#include <pthread.h>
#include <sys/mman.h>
#include <sys/io.h>

// delay in nanoseconds
#define TICKS 500000000 

        RT_TASK *task;
        int priority = 0, i;
        int stack_size = 4096;
        int msg_size = 0; // use default

        // get enough privilege to 
        // access the I/O ports.


        task = rt_task_init(nam2num("main"), priority, stack_size, msg_size);
        if(task == 0)
         printf("Task could not be initialized. Are you root?");

        for(i = 0; i < 10; i++) {
                outb(0xff, 0x378);
                outb(0x0, 0x378);
        // back to non-rt land!
        return 0;
It's a program that comes from this article with added troubleshooting comment.

To compile this program it's necessary to run:

CFLAGS=$(rtai-config --lxrt-cflags
LDFLAGS=$(rtai-config --lxrt-ldflags
gcc $(CFLAGS) $(LDFLAGS) main.c -o blinker
Where main.c is the name of the source file and blinker is the name of output executable.
To run it you should write sudo ./blinker. Sudo is needed because of the direct hardware access. You should see that the leds hooked up to lpt port are blinking.

poniedziałek, 17 maja 2010

LPT port access with C

I found this useful snippet on another blog.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/io.h>
#include <sys/types.h>
#include <fcntl.h>

#define BASEPORT 0x378 /* lp1 */

int main()
  unsigned char c = 0;
  int n, tem;

   printf("Hit enter to stop\n");

  if (ioperm(BASEPORT, 3, 1)) 

  tem = fcntl(0, F_GETFL, 0);
  fcntl (0, F_SETFL, (tem | O_NDELAY));
  while (1) {
    n = read(0, &c, 1);
    if (n > 0) break;

     outb(c, BASEPORT);
     usleep(c * 1000);

  fcntl(0, F_SETFL, tem);
  outb(0, BASEPORT);

  if (ioperm(BASEPORT, 3, 0)) 

poniedziałek, 22 marca 2010

piątek, 12 marca 2010

Don't code while designing

There's plenty of comments all over the Internet about "coding now, designing later" made by seasoned developer's. Right now I'm working with my colleagues on a project that needs to be written from scratch. Fighting the need to write something first I decided I won't do any implementation in advance.
My working environment is MS Visual Studio 2008. Recently I found there a feature which turned out very useful in my current situation: Class Diagram. I'm going to implement basic MVC framework as I understand it based on various tutorials I've read. It may not be 100% correct. Sorry.
  1. Create new project in a new solution.
  2. Right click on project's name in Solution Explorer and choose View Class Diagram.
  3. Rename file Class1.cs to Model.cs and change Class1 name to Model.
  4. Add 2 more classes dragging them from Toolbox and giving names: View and Controller.
  5. To add a method to a class right click on class box and choose Add->Method or go to Class Details window and add the new method there. If you don't see Class Details window, right click on a class and choose Class Details.
  6. View should have methods: AttachDataSource and Update.
  7. Controller should have methods: AttachModel, RequestAttachingView, RequestChangeState.
  8. Model should have methods: AttachView, ChangeState, ServeData, UpdateViews
  9. You don't want your classes to directly depend from each other, but use interfaces instead. To extract interface right click on class box, choose Refactor->Extract Interface... and choose methodes and properties that will form an interface.
  10. Extract IView interface from View with methods: AttachDataSource, Update.
  11. Extract IViewDataSource from Model with method ServeData.
  12. Extract IControllable from Model with methods: AttachView, ChangeState.
  13. Now add field viewDataSource to View of type IViewDataSource.
  14. Add field view to Model of type IView.
  15. Add field controlledModel to Controller of type IControllable.
  16. For some more readability you can right click on a field and choose Show as Association.
Your current state should be something like this:
Hosted by
Notice you didn't write anything in code yet. Next step will be implementation.

piątek, 5 marca 2010

Python i wykrycie beatu

W zasadzie nie wiem jak przetłumaczyć "beat" - uderzenie, rytm? Napisałem skrypt szukający beatów w pliku dźwiękowym. Jako materiał do analizy posłużyło pierwszy 10 sekund piosenki. Beat zdefiniowany jest jako skok chwilowej energii sygnału, co odbierane jest przez ucho jako głośniejszy dźwięk.
Więcej informacji tutaj:
__author__ = "daniel"
__date__ = "$2010-03-04 00:21:00$"

from import wavfile
import matplotlib.pyplot as pyplot
import numpy

if __name__ == "__main__":
# wczytanie pliku
fs, dane ="/home/daniel/Muzyka/steady10s.wav")
# laczenie dwoch kanalow w jeden
print dane.shape
dane = dane[:, 0] / 2.0 + dane[:, 1] / 2.0
# normalizacja
dane = dane / max(dane)
# obliczanie energii przenoszonej przez sygnal
dane = dane**2

# o tyle probek bedziemy skakac w czasie analizy
k = fs / 10
# dlugosc okna analizy
N = 2 ** 10
i = 0
# ilosc probek w pliku
length, = dane.shape
# const, ile razy wieksza musi byc wartosc energii sygnalu zeby uznany byl za beat
C = 2
srednia = []
# w ktorych momentach wykryto beat
beats = []
while i*k+N <= length:
# sprawdzamy ostatnie 42 usrednienia, czyli ~1s
if (sum(srednia[-42:])/42 * C < srednia[-1]):
#print "Beat @", i*k+N/2, "i:", i

srednia = numpy.array(srednia)
# skalowanie ybeats do 2-krotności średniej energii w danym punkcie (dla przejrzystosci)
ybeats = numpy.ones(shape=len(beats))
for i, b in enumerate(beats):
ybeats[i] *= srednia[b] * 2

# rysowanie wykresów (mocno podobne do matlaba)
pyplot.stem(beats, ybeats, 'k')
A oto wynik: Hosted by Szczęśliwym trafem Steady as she goes ma bardzo wyraźny rytm na początku, więc łatwo go wykryć. Kolejnym krokiem będzie analiza trudniejszego materiału.

Python i analiza dźwięku

Skrypt analizujący głośność dźwięku zapisanego w pliku wav napisany w Pythonie. Obliczana jest wartość średnia w oknie o długości N. Kolejne okna to k:k+N-1, 2*k:2*k+N-1, ... , gdy k < N to okna się nakładają. Na końcu z pomocą biblioteki matplotlib rysowany jest wykres głośności.
__author__ = "daniel"
__date__ = "$2010-03-04 00:21:00$"

from import wavfile
import matplotlib.pyplot as pyplot

if __name__ == "__main__":
# wczytanie pliku
fs, dane ="/home/daniel/Muzyka/labedzie.wav")
# laczenie dwoch kanalow w jeden
dane = dane[:, 0] / 2.0 + dane[:, 1] / 2.0
# normalizacja
dane = dane / max(dane)

# o tyle probek bedziemy skakac w czasie analizy
k = fs / 10
# dlugosc okna analizy
N = 2 ** 13
i = 0
# ilosc probek w pliku
length, = dane.shape
srednia = []

while i * k + N < length: srednia.append(abs(dane[i*k:i*k+N-1].mean())) i+=1 pyplot.plot(srednia) pyplot.title("Wykres glosnosci")

poniedziałek, 1 marca 2010

Kompilacja kernela 2.6.9 na RedHat 8.0

RedHat 8.0 zainstalowałem z 5 płyt CD z których w czasie instalacji potrzebne są chyba tylko 2 pierwsze.
W trakcie instalacji pozaznaczałem, że chcę mieć zainstalowane narzędzia programistyczne (m. in. kernel development).

Po ściągnięciu i rozpakowaniu kernela podawałem kolejno komendy:
make mrproper
make menuconfig (tu trzeba pamiętać, żeby obsługa ext3fs była wbudowana w kernel, a nie jako moduł, ponieważ partycja boot jest w ext3)
make dep
make clean
make bzImage
make modules
make modules_install (jako root, i nie "make module_install"!!!)

/sbin/mkinitrd /boot/initrd-2.6.9 2.6.9

cp arch/i386/boot/bzImage /boot/vmlinuz-2.6.9
cp /boot/
ln -s /boot/ /boot/

W pliku /boot/grub/grub.conf należy dodać wpis:
title Red Hat Linux (2.6.9)
root (hd0,0)
kernel /vmlinuz-2.6.9 ro root=LABEL=/
initrd /initrd-2.6.9.img

>> depmod can't open /lib/modules/2.4.18-14/modules.dep for writing
>> Warning: you may have to install module-init-tools
Rozwiązanie jest takie jak w warning - zainstalować module-init-tools. Przeprowadzi przez to ten poradnik: w krokach 2:4.

Grub: nie można znaleźć pliku, error 15. Czy na pewno przekopiowany jest bzImage i ? Ścieżka powinna zaczynać się od /, a nie od /boot/ - patrz NOTICE w grub.conf.
Błąd "pivotroot: pivot_root(/sysroot,/sysroot/initrd) failed" oznacza, że obsługa ext3fs nie jest wbudowana w kernel. Trzeba ją dodać z pomocą "y" w kroku z make menuconfig.

Teraz pozostaje tylko restart i użycie nowego kernela. Mi podczas wstawania systemu wyskoczyła tylko niepokojąca mnie informacja o jakichś problemach z eth0, ale do projektu nie będzie mi to potrzebne najprawdopodobniej, więc na razie się nie martwię.

sobota, 23 stycznia 2010

Wyszukiwanie tekstu w plikach za pomocą konsoli

Stanąwszy dzisiaj w obliczu potrzeby wyszukania pewnego tekstu w plikach tekstowych, które znajdują się w biężącym katalogu lub w którymś z jego podkatalogów poszperałem trochę w pomocy i wynalazłem taką kombinację:
cat $(find . -name "*.txt" -print) | grep -H -i tekst
Od początku:
find . -name "*.txt" -print - wyszukuje wszystkie pliki w katalogu bieżacym (.) lub głębiej o nazwie pasującej do *.txt i wyświetla na ekranie (-print)
$(find . -name "*.txt" -print) - otoczenie nawiasami ochronnymi aby wynik find "wkleił" się jako argument polecenia cat. Taki sam efekt można uzyskać przy pomocy otoczenia ` ` (znak nad tabem).
cat $(find . -name "*.txt" -print) - wypisuje zawartość plików podanych przez find
cat $(find . -name "*.txt" -print) | grep -H -i tekst - wyjście cat jest podawane do grepa, który wyszukuje w nim tekstu "tekst" będąc niewrażliwym na wielkość liter (-i) oraz dodając nazwę pliku dla każdej linii w której znajduje się trafienie (-H).

niedziela, 17 stycznia 2010

Głośniki w laptopie i słuchawki/głośniki

Okazuje się, że Karmic Koala również ma problem z przełączaniem się pomiędzy głośnikami laptopa i słuchawkami czy głośnikami. Po włożeniu wtyczki grają oba zestawy. Oto co dostaję po wykonaniu lspci | grep -i audio:
00:1b.0 Audio device: Intel Corporation 82801H (ICH8 Family) HD Audio Controller (rev 03)
Natomiast mikser alsa pokazał mi, że mam jakąś kartę Realtek. Rozwiązaniem okazało się dodanie w pliku /etc/modprobe.d/alsa-base.conf linijki: options snd-hda-intel model=auto. Po restarcie komputera wszystko działa już jak należy.

piątek, 1 stycznia 2010

Kompilacja kernela RTLinux

Jakiś czas żyłem w przekonaniu, że dostępna w repozytorium paczka linux-image-rt zawiera to samo jądro które jest podstawą RTLinuxa strona domowa RTLinux. Zatem aby skompilować jądro z patchem RTLinuxa będę musiał włożyć w to więcej wysiłku.
Zacząłem od ściągnięcia patcha RTLinux ze strony domowej, a następnie kodu źródłowego kernela z Dopiero po jakimś czasie zorientowałem się, że nie mogę używać kodu ostatniego kernela, bo nie ma dostępnego dla niego patcha. Musiałem więc ściągnąć kernel w wersji 2.6.9. Dalsze postępowanie wyglądało następująco:
Skopiowałem plik rtlinux-3.2-wr.tar.bz2 do katalogu /usr/src.
Rozpakowałem go poleceniem tar xjf rtlinux-3.2-wr.tar.bz2
Wszedłem do katalogu rtlinux-3.2-wr
Skopiowałem tu plik linux-2.6.9.tar.bz2 i rozpakowałem.
Utworzyłem dowiązanie symboliczne: ln -fs linux-2.6.9 linux
Wszedłem przez link linux do katalogu z rozpakowanymi źródłami kernela.
Teraz należy zaaplikować patch, który znajduje się tutaj. Inaczej otrzymamy błędy kompilacji w postaci:
{standard input}: Assembler messages:
{standard input}:607: Error: suffix or operands invalid for `mov'
{standard input}:630: Error: suffix or operands invalid for `mov'
{standard input}:1144: Error: suffix or operands invalid for `mov'
{standard input}:1145: Error: suffix or operands invalid for `mov'
{standard input}:1146: Error: suffix or operands invalid for `mov'
{standard input}:1147: Error: suffix or operands invalid for `mov'
make[1]: *** [arch/x86_64/kernel/process.o] Error 1
make: *** [arch/x86_64/kernel] Error 2
Rozwiązanie przyszło stąd. Zatem należy wykonać: patch -p1 < /sciezka/do/patcha/linux-2.6-seg-5.patch
Następnie zaaplikować patch RTLinuksa: patch -p1 < ../patches/kernel_patch-2.6.9-rtl3.2-rc1
Po tym wszystkim należe skonfigurować opcje kernela za pomocą jednego z poleceń: make menuconfig, make xconfig, make gconfig. Pojawi się menu w którym można wybrać czy dana opcja ma być wkompilowana w jądro czy doinstalowywana jako moduł lub całkowicie usunięta.
Teraz postępując dalej wg tej instrukcji:
Dostałem błąd o ponownie definiowanych makrach fake_stake_cośtam i unfake_stake_itd. Jak dowiedziałem się na jakimś forum należy otworzyć plik w którym makra są ponownie definiowane i po prostu je usunąć. Niestety zgubił mi się już link, gdzie to przeczytałem.

W tej chwili otrzymuję błędy o niepełnym typie tablicy.
In file included from fs/compat_ioctl.c:69,
from arch/x86_64/ia32/ia32_ioctl.c:14:
include/linux/i2c.h:58: error: array type has incomplete element type
include/linux/i2c.h:205: error: array type has incomplete element type
make[2]: *** [arch/x86_64/ia32/ia32_ioctl.o] Błąd 1
make[1]: *** [arch/x86_64/ia32] Błąd 2
make[1]: Opuszczenie katalogu `/usr/src/rtlinux-3.2-wr/linux-2.6.9'
make: *** [debian/stamp/build/kernel] Błąd 2
Powodowane jest to tym, że w czasach kernela 2.6.9 używało się starszych narzędzi kompilacji, które najwyraźniej były bardziej pobłażliwe niż obecne.
Zamieniłem linię 58 w incude/linux/i2c.h:
extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],int num);
extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msg,int num);
int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg msgs[],
int num);
int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs,
int num);
W pliku /include/linux/fb.h linia 751:
extern const struct fb_videomode vesa_modes[];
extern const struct fb_videomode *vesa_modes;

Teraz zatrzymałem się z błędem:
/usr/bin/ld: arch/x86_64/ia32/ Not enough room for program headers, try linking with -N
/usr/bin/ld: final link failed: Bad value
collect2: ld returned 1 exit status
make[2]: *** [arch/x86_64/ia32/] Błąd 1
make[1]: *** [arch/x86_64/ia32] Błąd 2
make[1]: Opuszczenie katalogu `/usr/src/rtlinux-3.2-wr/linux-2.6.9'
make: *** [debian/stamp/build/kernel] Błąd 2