Friday, August 12, 2011

Cross Compiling Linphone(2)

It is time to compile the linphone. Command line argument list is quite long this case:

$ ./configure --prefix=$PREFIX --host=$HOSTTPL --with-gnu-ld \
        --disable-static --disable-glib --enable-gtk_ui=no \
        --enable-sdl --disable-x11 --disable-libv4l \
        --with-osip=$INSTALLDIR/usr/local \
        --with-readline=$INSTALLDIR/usr/local \
        SPEEX_CFLAGS="-I$INSTALLDIR/usr/local/include" \
        SPEEX_LIBS="-L$INCLUDEDIR/usr/local/lib -lspeex" \
        FFMPEG_CFLAGS="-I$INSTALLDIR/usr/local/include" \
        FFMPEG_LIBS="-L$INCLUDEDIR/usr/local/lib -lavcodec" \
        SWSCALE_CFLAGS="-I$INSTALLDIR/usr/local/include" \
        SWSCALE_LIBS="-L$INCLUDEDIR/usr/local/lib -lswscale" \
        SDL_CFLAGS="-I$INSTALLDIR/usr/local/include" \
        SDL_LIBS="-L$INCLUDEDIR/usr/local/lib -lSDL"

Still there are some Makefiles and a source file we have to fix before we build them.

mediastreamer2/tests/Makefile

Find the LIBS variable and change it as:

LIBS = -pthread -lpthread -lrt -lvorbisenc -lvorbis -logg -lspeexdsp


mediastreamer2/coreapi/Makefile

Find the LIBS variable and change it as:

LIBS = -losip2 -lspeex -lSDL -lvorbis -lvorbisenc -lspeexdsp -logg -lavutil


mediastreamer2/coreapi/help/Makefile

Find the LIBS variable and change it as:

LIBS = -leXosip2 -lspeex -lSDL -lvorbisenc -losipparser2 -losip2 -lvorbis \
        -lspeexdsp -logg

And find the helloworld_LADD variable and add $(EXOSIP_LIBS) as:

helloworld_LDADD = $(top_builddir)/coreapi/liblinphone.la \
        $(EXOSIP_LIBS) \
        $(MEDIASTREAMER_LIBS) \
        $(ORTP_LIBS)


mediastreamer2/console/Makefile

Find the LIBS variable and change it as:

LIBS = -leXosip2 -losip2 -lSDL -lvorbis -lvorbisenc -lspeexdsp -logg -losipparser2

And find linphonecsh_LDADD variable and change it as:

linphonecsh_LDADD = $(ORTP_LIBS) -L/home/user/linphone/install/usr/local/lib


mediastreamer2/src/videoout.c

This file contains some obsolete function calls such as ms_sws_freeContext, ms_sws_getContext and, so on. So it won't compile unless we fix them (replace them with correct function calls). Details are here:
https://bugs.gentoo.org/attachment.cgi?id=269363&action=diff
Finally, we are ready to build linphone. What you need is a good luck now.

$ make
$ make install DESTDIR=$INSTALLDIR

Cross Compiling Linphone(1)

In this post, we will cross compile linphone for ARM devices. When it comes to video capability, it will support video output via SDL but no web cam interface. Including camera support is not difficult as long as V4L library is prepared.

First gather the required sources:

  • libav-0.7.1
  • libeXosip2-3.5.0
  • libogg-1.3.0
  • libosip2-3.5.0
  • libvorbis-1..3.2
  • linphone-3.4.3
  • ncurses-5.9
  • readline-6.2
  • SDL-1.2.14
  • speex-1.2rc1

and extract them under a directory, say linphone. Then create a target output directory, say install. Your directory structure then will look like this:


To save tedious repetitive typing, prepare environmental variables

export PREFIX=/usr/local
export HOSTTPL=arm-none-linux-gnueabi
export INSTALLDIR=/home/user/linphone/install

These may vary on your situation. Most of the procedures for each library compilation basically consist of following three steps:

$ configure
$ make
$ make install

So we will just list the commands with arguments until the last step, which will requires some interventions. Before we start, we may need intltool package

$ sudo apt-get install intltool

Now, let's get started. We have a long way to go.

ncurses

We won't use gtk+ gui interface so we need this for better command line interface.

$ ./configure --prefix=$PREFIX --host=$HOSTTPL --with-shared --with-gnu-ld
$ make
$ make install DESTDIR=$INSTALLDIR

Before going further, there is one thing you have to remember. As it is directed by the INSTALLDIR variable, the outputs will reside on the directory:

/home/user/linphone/install/usr/local

Under that directory you can find lib subdirectory where all the resulting libraries will populate. You can also find libtool archive files (*.la) there. Because we are doing cross compilation, these files usually contains wrong information so it should be deleted as soon as it is created. If you meet compilation error with strange library reference (looking for a library in the wrong place), then you should check the *.la files there.

readline

$ ./configure --prefix=$PREFIX --host=$HOSTTPL --disable-static
$ make
$ make install DESTDIR=$INSTALLDIR


libosip2

$ ./configure --prefix=$PREFIX --host=$HOSTTPL --with-gnu-ld --disable-static
$ make
$ make install DESTDIR=$INSTALLDIR


libogg

$ ./configure --prefix=$PREFIX --host=$HOSTTPL --with-gnu-ld
$ make
$ make install DESTDIR=$INSTALLDIR


libeXosip2

$ ./configure --prefix=$PREFIX --host=$HOSTTPL --with-gnu-ld --disable-static \
        OSIP_CFLAGS="-I$INSTALLDIR//usr/local/include" \
        OSIP_LIBS="-L$INSTALLDIR/usr/local/lib -losip2 -losipparser2"
$ make
$ make install DESTDIR=$INSTALLDIR

It is the good time to check the target library for the "la" files and delete them.

speex

$ ./configure --prefix=$PREFIX --host=$HOSTTPL --with-gnu-ld --disable-static \
        --enable-fixed-point --enable-arm-asm --with-ogg="$INSTALLDIR/usr/local"
$ make
$ make install DESTDIR=$INSTALLDIR


libav

$ ./configure --prefix=$PREFIX --enable-cross-compile \
        --cross-prefix=arm-none-linux-gnueabi- \
        --arch=armv6 --target-os=linux \
        --disable-ffserver --disable-ffplay --disable-ffprobe
$ make
$ make install DESTDIR=$INSTALLDIR

There are a bunch of --enable-xxx and --disable-xxx options are there. You can spend some time to fine tune the options to minimize the size of the output.

SDL

$ ./configure --prefix=$PREFIX --host=$HOSTTPL --with-gnu-ld
$ make
$ make install DESTDIR=$INSTALLDIR


libvorbis

$ ./configure --prefix=$PREFIX --host=$HOSTTPL --with-gnu-ld \
        --with-ogg="$INSTALLDIR/usr/local"
$ make
$ make install DESTDIR=$INSTALLDIR

Wednesday, August 10, 2011

Using UBIFS with CRAMFS(2)

As emphasized here, there is better (faster) method of creating UBI file system on our FLASH. We can prepare UBI volume image file with mkfs.ubifs + ubinize and populate it to our FLASH when we format the memory with ubiformat.

First create a ubi file system image with mkfs.ubifs

$ cd /home/user/nfsroot/usr
$ mkfs.ubifs -v -q -r local -m 2048 -e 258048 -c 4020 -o usrlocal.ubifs

mkfs.ubifs
      root:        local/
      min_io_size: 2048
      leb_size:    258048
      max_leb_cnt: 4020
      output:      usrlocal.ubifs
      jrn_size:    8388608
      reserved:    0
      compr:       lzo
      keyhash:     r5
      fanout:      8
      orph_lebs:   1
      super lebs:  1
      master lebs: 2
      log_lebs:    4
      lpt_lebs:    2
      orph_lebs:   1
      main_lebs:   206
      gc lebs:     1
      index lebs:  5
      leb_cnt:     216
      UUID:        910D9091-011A-4F91-AAE8-A70F1930CA08
Success!

Note that the parameter values should match with the ones we would get when we execute ubiattach on our device, such as minimum I/O unit size, size of logical erase block, maximum logical erase block count. Please refer to the previous post.

Next, we can create a ubi volume image from the file system image (usrlocal.ubifs) just created. To do that, we need to prepare configuration file, ubinize.cfg:

[ubifs]
mode=ubi
image=usrlocal.ubifs
vol_id=0
vol_type=dynamic
vol_name=usrlocal
vol_flag=autoresize

The reason we need this is that the ubinize is designed to create multiple, heterogeneous file system on a same volume image. So, fire up ubinize to create a volume image :

$ ubinize -v -o usrlocal.ubi -m 2048 -p 256KiB ubinize.cfg

ubinize: LEB size: 258048
ubinize: PEB size: 262144
ubinize: min. I/O size: 2048
ubinize: sub-page size: 2048
ubinize: VID offset: 2048
ubinize: data offset: 4096
ubinize: UBI image sequence number: 2101116498
ubinize: loaded the ini-file "ubinize.cfg"
ubinize: count of sections: 1

ubinize: parsing section "ubifs"
ubinize: mode=ubi, keep parsing
ubinize: volume type: dynamic
ubinize: volume ID: 0
ubinize: volume size was not specified in section "ubifs", assume minimum ...
ubinize: volume name: usrlocal
ubinize: volume alignment: 1
ubinize: autoresize flags found
ubinize: adding volume 0
ubinize: writing volume 0
ubinize: image file: usrlocal.ubifs

ubinize: writing layout volume
ubinize: done

Note here that the -p parameter value denotes the physical erase block size, which is different from the logical erase block size.

Now, put this ubi volume image (usrlocal.ubi) to SD card, mount it on our device to be available for ubiformat.

At the device side, unmount and detach the partition first if the ubi partition is attached and mounted as previous post:

# umount /usr/local
# ubidetach /dev/ubi_ctrl -d 0

All we have to do is just execute ubiformat utility with the prepared volume image

# ubiformat -y /dev/mtd3 -f /mnt/sdcard/usrlocal.ubi

ubiformat: warning!: your MTD system is old and it is impossible to detect ...
ubiformat: assume sub-page to be 2048
ubiformat: mtd3 (nand), size 1065353216 bytes (1016.0 MiB), 4064 eraseblocks ...
libscan: scanning eraseblock 4063 -- 100 % complete
ubiformat: 4064 eraseblocks have valid erase counter, mean value is 1
ubiformat: flashing eraseblock 217 -- 100 % complete
ubiformat: formatting eraseblock 4063 -- 100 % complete

Here we assume that the target partition is /dev/mtd3 and the ubi volume image is located at /mnt/sdcard. The warnig message about sub-page size is because we use MLC FLASH which has no sub-page.

And that's it!. UBI volume is just created with formatting. We can attach and mount the volume as before:

# ubiattach /dev/ubi_ctrl -m 3
# mount -t ubifs ubi0:usrlocal /usr/local

Using UBIFS with CRAMFS(1)

In this post, we are going to port Qt embedded on S3C6410 platform. The main CPU module consists of:
  • CPU: S3C6410(ARM1176
  • RAM: SRAM 256MB
  • FLASH: NAND 1GB(MLC type)
We assume that we have already u-boot and kernel running on the machine and that root file system (busybox) and Qt embedded are ready on our host (nfsroot).

Although, UBIFS is a good FLASH file system in most cases, we cannot use UBIFS as our root file system for some reasons. Most of all, the version of u-boot we can use for S3C6410 is v1.3.4, which has no UBIFS support features unlike recent ones. (I don't want to talk about the pathetic support from samsung for their products here but my recommendation is just avoid their products as far as you can.) Still we can use nfsroot to create UBI volume on the FLASH. But if we consider the (mass) production or on-site service, this is hardly a good choice.

Anyway, we take CRAMFS as our root file system and mount UBIFS on the /usr/local. Since CRAMFS is read-only file system, we put on the CRAMFS only minimum files required to load UBIFS, which would be busybox plus some mtd utils. For the rest of files we can locate under /usr/local directory including Qt embedded. I'm not going to describe the details here. But as usual, you can test your initial file system on NFS and deploy afterwards.

First we need an appropriate partition on our FLASH system, which is hard-coded in our kernel. For kernel-2.6.28.6 (with samsung modification), you can find the FLASH partition information here:

arch/arm/plat-s3c/include/plat/partition.h

and its contents would be:

struct mtd_partition s3c_partition_info[] = {

  /* u-boot : 0x0000.0000 - 0x0004.0000 */
  {
    .name = "bootloader",
    .offset = 0,
    .size = (256*SZ_1K),
    .mask_flags = MTD_CAP_NANDFLASH,
  },
  /* kernel : 0x0004.0000 - 0x0040.0000 */
  {
    .name = "kernel",
    .offset = (256*SZ_1K),
    .size = (4*SZ_1M) - (256*SZ_1K),
    .mask_flags = MTD_CAP_NANDFLASH,
  },
  /* cramfs : 0x40.0000 - 0x0080.0000 */
  {
    .name = "rootfs",
    .offset = (4*SZ_1M),
    .size = (4*SZ_1M),
  },
  /* ubifs : 0x0080.0000 - (end_of_FLASH) */
  {
    .name = "ubifs",
    .offset = MTDPART_OFS_APPEND,
    .size = MTDPART_SIZ_FULL,
  }
};

This will make 4 partitions  on your FLASH memory. You can check this on your device by

# cat /proc/mtd

dev:    size   erasesize  name
mtd0: 00040000 00040000 "bootloader"
mtd1: 003c0000 00040000 "kernel"
mtd2: 00400000 00040000 "rootfs"
mtd3: 3f800000 00040000 "ubifs"

At the same time, you can find corresponding devices under /dev

/dev/mtd0 - /dev/mtd3 : character devices
/dev/mtdblock0 - /dev/mtdblock3 : block devices

We will use the mtd3 partition for mounting /usr/local directory. Rest of them have no meaning for now. First erase the partition:

# flash_erase /dev/mtd3 0 0

Erasing 256 Kibyte @ 3f7c0000 -- 100 % complete

For the MTD utils used here, please refer to other post about how to cross-compile them. Then attach this partition(mtd3) to ubi drive 0:

# ubiattach /dev/ubi_ctrl -m 3

UBI: attaching mtd3 to ubi0
UBI: physical eraseblock size:   262144 bytes (256 KiB)
UBI: logical eraseblock size:    258048 bytes
UBI: smallest flash I/O unit:    2048
UBI: VID header offset:          2048 (aligned 2048)
UBI: data offset:                4096
UBI: empty MTD device detected
UBI: create volume table (copy #1)
UBI: create volume table (copy #2)
UBI: attached mtd3 to ubi0
UBI: MTD device name:            "ubifs"
UBI: MTD device size:            1016 MiB
UBI: number of good PEBs:        4064
UBI: number of bad PEBs:         0
UBI: max. allowed volumes:       128
UBI: wear-leveling threshold:    4096
UBI: number of internal volumes: 1
UBI: number of user volumes:     0
UBI: available PEBs:             4020
UBI: total number of reserved PEBs: 44
UBI: number of PEBs reserved for bad PEB handling: 40
UBI: max/mean erase counter: 0/0
UBI: background thread "ubi_bgt0d" started, PID 1253
UBI device number 0, total 4064 LEBs (1048707072 bytes, 1000.1 MiB), available 4020 LEB)

You can find some useful information about your FLASH memory here, which will be used later, such as:
  • physical erase block (PEB) size : 256KiB
  • logical erase block (LEB) size : 258048 bytes
  • available PEBs / LEBs : 4020 / 4020
  • minimum I/O unit size : 2048
If you want to detach  the partition from the ubi drive 0 then you can execute:

ubidetach /dev/ubi_ctrl -d 0

UBI: mtd3 is detached from ubi0

any time. But for now, let us just move on.

Next thing we have to do is create a volume on the drive

# ubimkvol /dev/ubi0 -N usrlocal -m

Set volume size to 1037352960
Volume ID 0, size 4020 LEBs (1037352960 bytes, 989.3 MiB), LEB size 258048 bytes ...

where usrlocal is the volume name. Now we can mount this volume to the point we want

# mount -t ubifs ubi0:usrlocal /usr/local

UBIFS: default file-system created
UBIFS: mounted UBI device 0, volume 0, name "usrlocal"
UBIFS: file system size:   1034514432 bytes (1010268 KiB, 986 MiB, 4009 LEBs)
UBIFS: journal size:       33546240 bytes (32760 KiB, 31 MiB, 130 LEBs)
UBIFS: media format:       4 (latest is 4)
UBIFS: default compressor: LZO
UBIFS: reserved for root:  5182151 bytes (5060 KiB)

At this point, we have additional MTD device :

# cat /proc/mtd

mtd0: 00040000 00040000 "bootloader"
mtd1: 003c0000 00040000 "kernel"
mtd2: 00400000 00040000 "rootfs"
mtd3: 3f800000 00040000 "ubifs"
mtd4: 3dd4c000 0003f000 "usrlocal"

Now, we can populate the directory with files we want. For example, we can archive the whole local directory in the host machine, copy the archive file on SD card, mount it on the device, and populate the directory.

# mount /dev/mmcblk0p1 /mnt
# cd /usr
# tar xvf /mnt/usrlocal.tgz local/

To mount this volume automatically every time the device boots up, we have to add the following line on the file /etc/init.d/rcS :

ubiattach /dev/ubi_ctrl -m 3
mount -t ubifs ubi0:usrlocal /usr/local

Be sure to remember that our root file system is CRAMFS. so all the change should be done on the host machine (NFS directory) and be prepared by mkcramfs utility:

$ cd /home/user
$ mkcramfs -v local/ /var/lib/tftpboot/cramfs.image

Then download and flash on your device with u-boot

> tftp 51000000 cramfs.image
> nand erase 400000 400000
> nand write 51000000 40000 40000
> reset

Many executables including Qt application, use /tmp directory for their temporary data storage. So it is required to mount tmpfs on /tmp since our root file system is read-only. Add the following line to /etc/init.d/rcS as well:

mount -n -t tmpfs -o size-32m tmpfs /tmp