CSE 466 Lab 7:
Project Preparation & Miscellanea

Introduction

This week, you'll work on several small things that will be useful for the final project. The focus of this lab is less on the deliverables and more on making sure you're ready to start working on the project.

You may also continue working on your creative audio applications this week and they will be checked off for potential extra credit at the start of next week's lab.

WARNING: NEVER attach or detach the iMote2 from the debug board or the sensor board when power is attached. ALWAYS make sure you've unplugged ALL of the USB cables when connecting or disconnecting the sensor board, debug board, or SuperBird.
NOTE: The sections of this lab are independent of each other, so you may complete them in any order.

Objectives

In this lab, you will:

Suggested Reading and Resources

Part 1: RSSI and Location

In this part of the lab, you will experiment with the RSSI function of the iMote2's ChipCon 2420 802.15.4 wireless radio. RSSI stands for Received Signal Strength Indication, and is a rough measure of the strength of the signal of a given packet that has been received. The datasheet for the CC2420 radio explains briefly how RSSI is measured (see section 23.) RSSI can be used as a metric that roughly represents the distance between two nodes in the wireless network.

Before beginning this part of the lab, note that there was a bug in some of the example code provided when you started working with the 802.15.4 radio. The sample code used TOSH_DATA_LENGTH as the size argument to the read and write calls for receiving and sending packets. TOSH_DATA_LENGTH has a value of 28, which is the maximum number of bytes of data you can send and receive with the version of the wireless driver that we have distributed. However, these 28 bytes do not include the headers and other fields in the packet.

Using TOSH_DATA_LENGTH as the size argument likely worked for the labs up to this point because you were only sending a few bytes back and forth, and all of this data fit within the first 28 bytes of the packet, even including the headers. However, since the RSSI measurement is stored as one of the last fields, after the data field, reading just TOSH_DATA_LENGTH bytes won't get us the RSSI information we'll need. Instead, you should be reading and writeing with a length of sizeof(TOS_Msg). This will ensure that you are actually communicating entire packets with the driver.

For this section of the lab, you will become familiar with accessing the RSSI data, make sure that you can interpret it correctly, and experiment with its usability as a metric for the distance between nodes.

  1. Develop an application that sends out packets with a unique ID. You have probably already developed something similar as a requirement for previous labs. You will need an application that sends out packets that you can identify as your own, with a transmit rate of a few packets per second (limit yourself to 10 packets per second to conserve radio bandwidth for other groups.) It doesn't really matter what the payload of these packets are as long as you can identify them.
  2. Develop a receiver application that listens for your packets, and when it receives one, it prints out the RSSI field (called strength in the TOS_Msg struct). The output of your program should be set up so that you can redirect it to a file and easily plot it with another program, such as MATLAB, Excel, GnuPlot, or matplotlib. You may wish to include (relative) timestamps with each packet that you receive.
  3. The RSSI value is stored as an unsigned char in the TOS_Msg struct, but it's not really an unsigned char. See the datasheet for the CC2420 radio for more information about what the bits really mean. Verify that you are correctly interpreting the RSSI data that you are receiving. If you wish, you may optionally fix the tosmac driver so that the RSSI field is a signed char with the correct representation (driver code for the tosmac.ko provided on your iMote2 is available on the web here, or in the subversion repository here):
    svn co http://imote2.orderedpixels.com/svn/drivers/tosmac
    (Note, however, that any driver modifications are strictly optional. You are welcome to simply interpret the unsigned char in your userspace program to recover the correct RSSI value.)
  4. Experiment with moving around your iMotes, and watching how the RSSI value changes. If you run your application through the nohup command (see man nohup; this will prevent the program from being terminated if you disconnect the terminal session you started it from), and redirect the output to a file, you can collect data while disconnected from the computer. Using the SuperBird and battery, you can walk around with one iMote2/SuperBird untethered.
  5. Depending on how many SuperBirds Brian is able to get working this week before taking off for Germany, you may be able to check out your second SuperBird from a TA and have both nodes battery powered and disconnected from a computer. Try going up to the Atrium to get some separation between your iMotes. (In the case where both iMotes are disconnected from a computer, it might be useful to do the same thing as the count_and_send and count_and_receive programs, where a counter from 0-7 is displayed as a color on the iMotes' LEDs. You can easily use the LED to determine if packets are actually being received based on whether or not the colors are changing.) Try to see how far away the iMotes can actually receive packets. You can have one partner stay on the ground floor and the other walk around the higher floors. Later, you can plot your saved RSSI data and see if you can figure out how far apart you were.
  6. You can also play around with the transmit power on the transmitting iMote. There's an ioctl for this in the tosmac driver. You may find that a different setting for transmit power provides better correlation between distance and RSSI.
Question 1. Write up your findings on using RSSI as a metric for distance. Include any plots and data you have generated.

Part 2: Threads with pthreads

This part of the lab is optional. For the final project, you may develop your application as a multi-threaded application that continuously listens for packets, or as a single-threaded application that only listens for radio data when it is idle/not playing sound. A multi-threaded implementation will be able to continue to listen for packets while it is playing sound.

NOTE: This section is written assuming that you wrote the suggested sequencer application in Lab 6 to play a song with your synthesizer. If you have chosen to write a different audio application, you may adapt this part to the application that you developed, or develop a different multi-threaded application to introduce yourself to the pthreads API.

In the previous lab, you created a synthesizer (or other audio project) likely with a single thread. If you want to adjust the parameters or otherwise control your synthesizer, you must do this in the short amount of time between writing buffers of data to the audio device. Your program spends the rest of its time blocked while the sound device is not ready for new data. If you spend too much time preparing the next buffer of data, the audio will skip and need to be recovered because the audio device will run out of samples to play before the next buffer is ready.

Because your application spends most of its time blocked waiting for ALSA to be ready for more samples, it is difficult to do other things at the same time. For the final project, it may be useful to be able to continue listening for radio packets while you are in the middle of playing a sound file. To do this well, you will need to implement a multi-threaded application. In this part of the lab, you will investigate the pthreads API and use it to add multi-threading to your audio application.

  1. First, implement a simple application with a few threads to introduce yourself to the pthreads API. This tutorial provides an example of a simple pthreads program. Note that when you compile a program that uses the pthreads API, you should use the -pthread compiler flag.
  2. Your program can be as simple as threads that loop several times, print out their IDs, and sleep for a few seconds. When you run it, you should see output from all of your threads to indicate that they are running concurrently.
  3. Separate the control and synthesis threads in your synthesizer application. Your threads can communicate through shared global variables, but make sure you use mutexes when accessing shared data structures to avoid synchronization errors.
  4. When your synthesis thread is idle (i.e. not producing sound and waiting for input from the control thread) it should wait on a condition variable. When your control thread wants to start playing sound, it should signal the synthesis thread to wake up.
  5. Note the semantics for condition variables. Specifically, pthread_condition_wait takes a lock as a parameter, which is expected to be locked at the time it is called. If it is necessary to wait on the condition (i.e. it is not already set) then the lock will be released, and then re-acquired once the waiting is finished. If you ignore this, you will run into problems.

There are no deliverables for this section, it is for your own preparation only.

Part 3: Ogg Vorbis Playback

In order to be able to store several minutes of audio at good quality in the limited Flash memory on your iMote2, we will be using the Vorbis audio codec. The mainline Vorbis libraries are intended for desktop PCs, and make use of floating point arithmetic. However, there is another implementation of the Vorbis decoder called Tremor, which is intended for embedded platforms and uses only fixed-point arithmetic. Where possible, the Tremor library tries to maintain the same API as the mainline libvorbisfile.

Download and install the tremor package on your iMote2. Packages are available here. The header files and libraries you will need to compile code using Tremor have already been installed into the CSE 466 toolchain on attu.

Make a copy of your auplay.c file, and call it vorbisplay.c. You will modify this version to play Vorbis files instead of AU files.

To use the Tremor library, you should include tremor/ivorbiscodec.h and tremor/ivorbisfile.h in your source code. When you link your application, you will need to use the -lvorbisidec flag, in addition to -lasound. The Tremor documentation will be a useful reference while writing your code.

Playing back encoded files is similar to playing back the raw PCM data from an AU file. You will read the file header, determine a few parameters, use these to configure the audio interface, and finally, read samples and write them to the audio interface. The difference is that the library provides functions for reading and parsing the header, and for reading the encoded audio data, decoding it, and giving you samples.

In order to make the code you write in this lab easily adaptable to the final project, you should develop a function that takes the name of an Ogg file, plays it back, and then returns. This will allow you to reuse this function to play audio files for the final project.

ov_open takes an existing FILE* pointer and takes possession of it. It also initializes an OggVorbis_File struct, which will be passed to all further calls to Vorbis functions.

ov_info will return a pointer to a vorbis_info struct, which can be used to get the number of channels and the sample rate for a file, which you can use to configure the ALSA interface. When playing back Vorbis files, the format will always be 16-bit linear PCM, in native endian (which for the iMote2 is little endian.)

ov_read will read up to one packet of Vorbis data, or up to the number of bytes you request, whichever is smaller. You should certainly check the return value, since it won't always be giving you a full buffer of data.

Once you get decoded samples from ov_read, you can send them to the audio interface with snd_pcm_writei.

When ov_read returns 0, the stream has ended and there are no more samples to play. You should clean up by calling ov_close to close the file handle and free the memory used by the OggVorbis_File struct.

Deliverables: Turn in your code and demonstrate your Vorbis playback app to a TA during the first half-hour of the next lab.

Part 4: Using the LED on the SuperBird

We'll be using the RGB LED on the SuperBird to indicate the status of the application for our final project. You should familiarize yourself with setting the color of this LED.

The SuperBird driver uses the sysfs interface to provide access to several of the peripherals on the SuperBird. The LED interface is available at /sys/bus/i2c/devices/0-004d/rgb_led. To change the LED color, you write the color as a hex string (RRGGBB) to this file. You can also read this file to get the current color.

Experiment with changing the LED color from the command line by using echo to write a new value to it, and cat to get its current value.

Write a simple C program that can alter the LED's color.

Deliverables: Turn in your code and demonstrate your program for changing the color of the LED during the first half-hour of next week's lab.