NeTV AMI Instance

What this is
The Amazon AMI is a preconfigured machine image that can be used for developing on the chumby NeTV board. It comes with a copy of the chumby build system and source code, as well as a precompiled image suitable for burning directly onto an SD card.

The public AMI ID is ami-e68ff4b4 ami-c0b3f692 (v1.3 now points to github for source), and it is bound to the Asia-Pacific (Singapore) region. For instructions on how to start an AMI, please see Quickstarting OE for a step-by-step howto. Please note that in order to access the more advanced features such as buildbot and gitweb, you will need to also add port 80 to the security group.

Screenshots
Here are some screenshots of the NeTV AMI in action.

Getting started
To get started, log onto the instance as the "ubuntu" user. Then switch to building image for chumby-silvermoon-netv, and build the chumby-image:

cd chumby-oe source setup-chumby.sh # Pick option 5 here bitbake chumby-image

Then, download the resulting ROM image by using your web browser to go to /output/ on your instance. For example, http://169.254.169.254/output/. Click on "images", then on "chumby-silvermoon-netv", then download "rom-chumby-silvermoon-netv-chumby-image.img.gz".

Development Flows
The system comes configured to support several development flows, including command line and GUI-assisted flows.

Here are a couple of suggested flows:

Local editing and building
 * 1) ssh into the AMI
 * 2) edit code locally on the AMI
 * 3) initiate bitbake manually (e.g. bitbake chumby-image)
 * 4) (first time only) copy ROM image from server and dd onto a microSD card
 * 5) (successive builds, assuming network connectivity) use opkg update; opkg upgrade to grab the latest build and install on your local test machine

Remote editing and building
 * 1) check out git repo from the AMI using ssh (git clone ssh://ubuntu@instance-address:chumby-oe/meta-chumby/.git)
 * 2) edit code locally, and do a git push
 * 3) buildbot will pick up the push and within a few minutes automatically kick off a build, or you can use the UI on the webpage to manually start a build
 * 4) (first time only) navigate to the web directory on the server and copy the file locally, and burn to SD card
 * 5) (successive builds, assuming network connectivity) use opkg update; opkg upgrade to grab the latest build and install on your local test machine

Burning images to disk
To burn a ROM image to disk, you'll first need to uncompress it. Usually you can just double-click on the .gz or .zip file. Once you have an uncompressed .img file, you'll need to write it to a micro-SD card. Place the card into a USB reader, and insert the card into your computer.



The instructions for writing a .img file to an SD card is described in detail at the Ubuntu IMG-install page.

Once the card has been burned, insert it into the NeTV and turn it on. The blue light should begin flashing, which indicates the FPGA firmware has been loaded and the device is booting.

If the light doesn't come on, then the image didn't work. Possible causes are:


 * Dirty contacts. The SD card is very sensitive to dirt and grease.  Wipe off the contacts with a cloth and try the card again.


 * Card not inserted correctly. The door should not be able to open on its own, even when the board is turned upside-down.


 * ROM file not uncompressed. You must un-gzip the file before burning it.


 * ROM file copied, not burned. You must burn the ROM file to the card, not copy it using e.g. Windows file explorer.  If you can add files to the SD card in either Windows or Mac, then the card has not been burned properly.

Git
All chumby code used in this AMI instance comes from git. Because git is a distributed version control system, you can make changes and commit code, and still track the main trunk. This allows you to make changes and submit patches without having to set up your own server.

Basics
Before you check in any changes, you should set up your git username and email address. This allows you to mail patches around and still be given credit for fixes and feature additions. Run these commands inside the instance to personalize your settings: git config --global user.name "Firstname Lastname" git config --global user.email "your_email@youremail.com"

To update a repository from the remote copy, run "git pull". To mark files as having changed, or to add new files to git, run "git add [filename]". To remove files, run "git rm [filename]". To commit a series of added/changed/removed files, run "git commit".

chumby-oe
There are three primary git repositories you will encounter while building images:
 * chumby-oe - Contains setup scripts and the bitbake program
 * openembedded - A mirror of the openembedded monolithic project
 * meta-chumby - An overlay on top of openembedded that implements chumby code

Most development will take place under meta-chumby. You can sync your copy of the code by running "git pull" in each of the directories.

Local mirrors
In order to make development easier, local mirrors of the kernel and u-boot have been made. They are located under ~/git/. New recipes have been added under meta-chumby that cause locally-built images to look in this directory for source code rather than going to chumby's git repo.

You can make and commit changes in the mirrored repos and still pull changes from master. To submit a patch, use the "git format-patch" command.

Cgit
You can use the web-based git interface by going to /cgit/cgit.cgi on your EC2 instance's web server. Checked-in changes are automatically displayed here. CGit is configured by editing the file /etc/cgitrc. Pages are cached in the directory /var/cache/cgit/, so if you update the config file you'll need to clear the cache by removing the contents of /var/cache/cgit/.

Overview
The build system is based on openembedded, which uses the **bitbake** tool to assemble packages that are described by **recipes**. The bitbake command uses recipes to determine how to compile and package software, as well as to build bootable images for various devices.

A recipe is a series of steps that are executed in order to fetch source, unpack source, configure, build, and install the package(s), and then distribute the resulting packages. Recipes are defined in files that end in .bb, and are located in subdirectories under the recipes/ directory. Each step is a shell script by default, unless explicitly defined as a python step.

Many steps are inherited automatically from chumby-oe/openembedded/classes/base.bbclass, and you can override any steps by explicitly specifying them in your recipe file. You can inherit additional classes such as "qt4e" that will give you a pre-defined set of steps to draw from by adding "inherit qt4e" at the top of your recipe.

A package name (PN) is defined as the portion of a .bb filename before the underscore (_). A package version (PV) is the portion after the underscore. Thus, the PN for meta-chumby/recipes/netv-utils_0.bb is "netv-utils", and the PV is 0. Unless told otherwise, bitbake will always use the package with the highest PV.

meta-chumby Overlay
There is a chumby "overlay" on top of a minimally-modified openembedded tree that adds chumby-specific machine definitions and recipes. If there are identically-named packages in both openembedded and meta-chumby, the package from meta-chumby will take precedence. Additionally, the configuration file inside meta-chumby inherits the "amend" bbclass, which allows for meta-chumby to provide additional steps and patches to recipes in the openembedded directory.

In this way, meta-chumby modifies openembedded, allowing for it to work better with chumby devices. If possible, avoid modifying files in the openembedded directory, and instead modify/add files to the meta-chumby directory.

Packages
A package is a combination of files and meta-data such as platform, dependencies, and install scripts. A single recipe will usually build four packages, but can end up building any number of packages. The four packages that will get built by default are:


 * Application package. Has the same package name (PN) as the recipe.
 * Debug package. Named PN-dbg.  Contains debugging symbols for the binaries in the application package.
 * Development package. Named PN-dev.  Usually empty.  Contains static libraries and headers useful for compilers.
 * Documentation package. Named PN-doc.  Contains manpages, info pages, and any other documentation.

To install a package, copy it over to the device through scp, then install it: mount -oremount,rw /            # Remount / as read-write opkg install [package-name].ipk # Install the package

To remove a package, specify only the PN: opkg remove [package-name]

A hello-world Package
There is a "hello world" recipe that creates a package containing an executable that simply prints the canonical "Hello, world!" message. It is located under meta-chumby/recipes/examples/hello-world_1.0.bb, and the source code is located under meta-chumby/recipes/examples/hello-world/.

To build the hello-world program, run "bitbake hello-world". This will cause openembedded to parse the .bb file, run each step in turn, and then generate a package. You can find the resulting .ipk in ~/chumby-oe/output-angstrom-.9/deploy/eglibc/ipk/armv5te/ and it will be called hello-world_1.0-r1.9_armv5te.ipk.

If you run "bitbake hello-world" again, nothing will happen. This is because the package has been marked as "already built". You have two options for forcing the package to get rebuilt:


 * Run "bitbake -c clean hello-world; bitbake hello-world" to clean the package, then rebuild it
 * Edit hello_world-1.0.bb and change the PR variable from "r1" to "r2"

The last option is called "bumping the PR", and is required if you share your changes. If you change any source the package relies on, or if you modify the recipe in any way, you should bump the PR prior to checking the changes in. That way, anyone who checks out your code will be forced to rebuild the package, and will get the new version.

Modifying the kernel
In order to make kernel development easier, a local mirror of the chumby kernel has been made. You can view and edit the source in the ~/ubuntu/git/linux-2.6.28-silvermoon directory. Since it is a read-only git repo, you can pull from trunk and commit changes, but not push patches. Any patches you make can be submitted upstream using the "git format-patch" command, and then emailing the resulting files.

The kernel configuration used in bitbake is stored in ~/chumby-oe/meta-chumby/recipes/linux/linux-silvermoon-netv/defconfig. You will need to copy this before making any kernel changes.

You have several options for building the test kernel. Perhaps the easiest method is to use the build scripts from bitbake. You can manually run the do_compile script:

cd ~/git/linux-2.6.28-silvermoon/src/ cp ~/chumby-oe/meta-chumby/recipes/linux/linux-silvermoon-netv/defconfig ~/git/linux-2.6.28-silvermoon/src/.config ~/chumby-oe/output-angstrom-.9/work/chumby-silvermoon-netv-angstrom-linux-gnueabi/linux-silvermoon-netv-2.6.28.local-r29/temp/run.do_compile.*

The kernel itself will get compiled and the output image will be placed in arch/arm/boot/zImage. Copy this image to your running NeTV board and install it there by connecting through SSH and running: config_util --cmd=putblock --block=krnA < ~/zImage

You will need to reboot to try out the new kernel.

When you are satisfied with your changes, add them to git: git commit -a

Bump the PR in ~/chumby-oe/meta-chumby/recipes/linux/linux-silvermoon-netv_2.6.28.local.bb and rebuild the kernel package: bitbake virtual/kernel

Changing kernel config
You will first need to install ncurses-dev, in order to be able to use the graphical kernel configuration screen: sudo apt-get install ncurses-dev

The kernel config used in the chumby distribution is located under meta-chumby. To restore the default kernel config, copy it from meta-chumby to the kernel src directory: cp ~/chumby-oe/meta-chumby/recipes/linux/linux-silvermoon-netv/defconfig ~/git/linux-2.6.28-silvermoon/src/.config

To change kernel config, change to ~/git/linux-2.6.28-silvermoon/src/ and run "make ARCH=arm menuconfig". Make any changes you like. When you're satisfied with your changes, save and exit the editor. To add the changes to the build system, run the following: cp ~/git/linux-2.6.28-silvermoon/src/.config ~/chumby-oe/meta-chumby/recipes/linux/linux-silvermoon-netv/defconfig

Then bump the kernel PR and rebuild virtual/kernel.

Compiling kernel modules
To compile the kernel modules, make sure you have already run the "do_compile" step, then run the "do_compile_kernelmodules" step: ~/chumby-oe/output-angstrom-.9/work/chumby-silvermoon-netv-angstrom-linux-gnueabi/linux-silvermoon-netv-2.6.28.local-r29/temp/run.do_compile.* ~/chumby-oe/output-angstrom-.9/work/chumby-silvermoon-netv-angstrom-linux-gnueabi/linux-silvermoon-netv-2.6.28.local-r29/temp/run.do_compile_kernelmodules.*

If you get errors such as "ERROR: "kmalloc_caches" [sound/usb/snd-usb-lib.ko] undefined!", then you will need to re-run the do_compile step before running the do_compile_kernelmodules step.

Modifying the bootloader
The bootloader can be modified using the same process as the kernel. Like the kernel, an additional bootloader recipe has been added that takes precedence over the stock u-boot recipe, and pulls from the git repository located at /home/ubuntu/git/u-boot-2009.07-silvermoon/. When you want to make changes and want to force a rebuild, bump the PR in chumby-oe/meta-chumby/recipes/u-boot/u-boot-silvermoon_local.bb and rebuild the bootloader: bitbake virtual/bootloader

Buildbot
There is a copy of buildbot running on the system. Any time you check in changes to meta-chumby, openembedded, or chumby-oe, a five-minute timer starts. If no more changes are checked in after five minutes, it automatically runs "bitbake chumby-image" to generate a new compressed rom image.

There is a second buildbot factory called netv-trunk, which automatically pulls the latest code from chumby's master git repository. This is separate from any development you do on the EC2 instance, and exists to demonstrate the ability to build a stock chumby firmware. It will never automatically trigger.

oth builders have openembedded trees separate from ~/chumby-oe/. They reside in ~/buildslave/(netv|netv-trunk)/work/ and have their own output directories. You should avoid doing developent in these directories unless you're trying to troubleshoot build system failures.

Accessing
You can monitor build progress by going to /waterfall on your build machine's web server. When the build has completed, you can download the automatically-built images by navigating to /output-buildbot/ on the web server. This is separate from builds you make on the command line, which can be accessed by going to /output/.

To start a build, navigate to /builders/netv and click "Force Build".

Modifying
Nearly all of the configuration takes place on the build master. The configuration file is stored in ~/buildbot/master.cfg. It is a python script. It is documented at the buildbot documentation page.

Whenever you change the configuration file, be sure run a syntax check by running: buildbot checkconfig ~/buildbot/

To apply the config, restart buildbot: buildbot stop ~/buildbot/ buildbot start ~/buildbot/

The patch
A patch was made to the buildbot source in order to support multiple git repos. Without the patch, the automated builder would pull the wrong branch. It is unclear whether this change will be accepted to buildbot trunk, but be aware of it if you decide to upgrade the installed copy of buildbot:

diff -ur buildbot-0.8.4p2-stock/buildbot/steps/source.py buildbot-0.8.4p2/buildbot/steps/source.py --- buildbot-0.8.4p2-stock/buildbot/steps/source.py    2011-07-17 12:49:06.000000000 +0800 +++ buildbot-0.8.4p2/buildbot/steps/source.py  2011-07-29 06:49:53.000000000 +0800 @@ -228,7 +228,7 @@        # what source stamp would this build like to use? s = self.build.getSourceStamp # if branch is None, then use the Step's "default" branch -       branch = s.branch or self.branch +       branch = self.branch or s.branch # if revision is None, use the latest sources (-rHEAD) revision = s.revision if not revision and not self.alwaysUseLatest:

Creating images
An image recipe is defined as a recipe that inherits from image.bbclass. When built, an image will create a burnable ROM file that you can uncompress and write directly to an SD card. The starter image recipe is located in ~/chumby-oe/meta-chumby/recipes/images/chumby-starter-image.bb. A full chumby image, including the control panel and browser code, may be found in ~/chumby-oe/meta-chumby/recipes/images/chumby-image.bb. Other images can be found under ~/chumby-ie/openembedded/recipes/images/. Some of these image recipes won't build due to missing dependencies such as OpenGL acceleration, which aren't available on this particular platform.

To create your own image, copy "chumby-starter-image.bb" to another file, say "my-starter-image.bb". Then, add files to the "IMAGE_INSTALL" and the "DEPENDS" variables. If you don't add the package name to DEPENDS, then it might not get built. On the other hand, if you don't add the package to IMAGE_INSTALL, then it won't get included in the image.

Package repositories
When you build an image, bitbake looks at the environment variable "FEED_DEPLOYDIR_BASE_URI". If set, it instructs the resulting image to look to that URL to find packages. If not, it will look up your hostname during the buld process by consulting http://ifconfig.me/host, and set the URL to "http://hostname/${FEED_DEPLOYDIR_PATH}". If FEED_DEPLOYDIR_PATH is not defined, it defaults to /build/localhost/LATEST. The setup-chumby.sh sets it to /output/ipk/, so the defaults should be okay.

The NeTV device will consult this URL if it needs to install packages. To install packages, mount the root filesystem as read-write, update the list of packages, and install the package. For example, to install "hello-world", run: mount -oremount,rw /      # Allow the root filesystem to be modified opkg update               # Update the list of available packages opkg install hello-world  # Fetch and install hello-world package

The opkg command will examine the list of dependencies and install any required packages.

Running programs at startup
The system uses a Sys-V startup style. That means scripts are placed under /etc/init.d/ that accept "start", "stop", and "restart" arguments. The system boots and runs every script in /etc/rc5.d/ alphabetically, and allows you to log on only after all the scripts have run.

There is an example recipe located in meta-chumby/recipes/examples/ called init_example-1.0.bb that uses the update-rc.d class to install a startup/shutdown script. It installs a simple daemon that basically does nothing but stay running.

Build the package by running "bitbake init-example", and then install it on your device. As part of the package installation, the package will be added to /etc/rc5.d/ and the startup script will be called as "/etc/init.d/init-example-script start". When the system starts up in the future, the script will be called automatically.

If you remove the package, opkg will call "/etc/init.d/init-example-script stop" immediately prior to removing the package. If you bump the package's PR, and rebuild it, and then reinstall it, opkg will call "/etc/init.d/init-example-script restart".

Postinstall scripts
Packages can run scripts after being installed. For example, this is used by the bootloader recipe to load a new copy of the bootloader to the config block when it is installed.

The basic template of a postinstall script is: pkg_postinst_${PN} { # Your shell script here }

The postinst script will get run as part of the do_rootfs when you bitbake an image. If the script fails, or if you copy the package directly to the device, it will be run when it's installed. In order to force a package to get run on the device and not during do_rootfs, add this to the top of your postinst script: if test "x$D" != "x"; then exit 1; fi # Don't do postinst on build system

Debugging binary programs
All packages are built with debugging symbols included, all of which are stripped as part of the do_package step. Each binary in your package will have its symbols placed in a -dbg package. For example, the "regutil" recipe creates a regutil package, as well as a regutil-dbg package.

In order to use these symbols, you must first install the "gdb" package. Either add gdb to a custom image, or run "mount -oremount,rw /; opkg install gdb". If you try to install regutil-dbg, it will try to pull in all of the symbols for eglibc, so install the debug symbols package by running "opkg install -nodeps regutil-dbg".

You can now launch regutil under gdb and step code by typing "gdb regutil". Alternately, you can attach to a running instance of regutil by figuring out its process id and running "gdb regutil ". When you end a debugging session attached this way, the program will continue running.