Lesson 8: Data logging application

Last updated 9 September 2003

This lesson will discuss a fairly complete application for remote data logging and collection, called SenseLightToLog. This is an extension to SimpleCmd that accepts two new commands: one that causes the mote to collect sensor readings and write them to the EEPROM, and another that causes the mote to transmit sensor readings from the EEPROM over the radio.
The SenseLightToLog Application

The high-level functionality of SenseLightToLog can be best understood by looking at the apps/SenseLightToLog/SimpleCmdM.nc component. This is an extended version of the original SimpleCmd component from the previous lesson. The cmdInterpret() task now recognizes two additional commands:

The Sensing interface

We have abstracted the concept of taking a number of sensor readings behind the Sensing interface, which is implemented by the SenseLightToLog component. This interface provides the start() command to initiate a series of sensor readings, and signals the done() event when sensing has completed.

SenseLightToLogM.nc
  command result_t Sensing.start(int samples, int interval_ms) {
    nsamples = samples;
    call Timer.start(TIMER_REPEAT, interval_ms);
    return SUCCESS;
  }

  event result_t Timer.fired() {
    nsamples--;
    if (nsamples== 0) {
      call Timer.stop();
      signal Sensing.done();
    }
    call Leds.redToggle();
    call ADC.getData();
    return SUCCESS;
  }

  async event result_t ADC.dataReady(uint16_t this_data){
   atomic {
    int p = head;
    bufferPtr[currentBuffer][p] = this_data;
    head = (p+1);
    if (head == maxdata) head = 0; // Wrap around circular buffer
    if (head == 0) {
        post writeTask(); 
     }
    }
    return SUCCESS;
  }

  task void writeTask() {
    char* ptr;
    atomic {
      ptr = (char*)bufferPtr[currentBuffer];
      currentBuffer ^= 0x01; // Toggle between two buffers
    }
    call LoggerWrite.append(ptr);
  }

When start() is invoked, the timer is started to tick at the given interval. When the timer event fires, ADC.getData() is invoked to get a sensor reading. The ADC.dataReady() event causes the sensor reading to be stored in a circular buffer. When the appropriate number of samples have been collected the Sensing.done() event is signaled.

When SimpleCmd receives a READ_LOG command, it initiates an EEPROM read (through LoggerRead). When the read has completed it broadcasts the data in a packet. There are 16 bytes in each log entry, which are displayed when you run BcastInject tool (as described below).

Notice the atomic statements in ADC.dataReady() async event. They protect access to the shared variables head, bufferPtr, and currentBuffer.  Why do you think the command LoggerWrite.append() is called from a task and  not from the ADC.dataReady() async event ? That is because LoggerWrite.append() is not async, so it may not safely preempt other code and should not be called from an async event.
 
Logger component, interfaces, usage, and limitations

The Mica mote has an on-board, 512 kbyte flash EEPROM. The EEPROM serves as a persistent storage device for the mote, and is indispensable for many applications involving data collection, such as sensor data and debugging traces. The EEPROMRead and EEPROMWrite interfaces provide a clean abstraction to this hardware. The EEPROM may be read and written in 16-byte blocks, called lines. Read and write to the EEPROM are split-phase operations: one must first initiate a read or write operation and wait for the corresponding done event before performing another operation.

To simplify access to the EEPROM even further, the Logger component is provided (see tos/system/LoggerM.nc). Logger maintains an internal pointer to the next EEPROM line to be read or written, treating the EEPROM as a circular buffer that may be accessed sequentially. The logger does not read or write data at the beginning of the EEPROM, which is set aside to store persistent data for the mote. For example, when using network reprogramming of motes, this region stores the TOS_LOCAL_ADDRESS of the mote.

The LoggerRead and LoggerWrite interfaces are used for reading and writing, respectively. LoggerRead provides the commands:

Likewise, LoggerWrite provides the following commands:
Logging performance
The Logger component does not offer very high performance. Please see the apps/HighFrequencySampling application if you are interested in high-frequency sampling (up to around 5kHz), using the ByteEEPROM component. This lesson will eventually be updated to reflect this new component.
Data collection using SenseLightToLog

Program one mote with SenseLightToLog and another with TOSBase, as before. You may want to attach a sensor board to your mote to get meaningful photo readings.

The first step is to instruct the mote to take a number of sensor readings. Type

    export MOTECOM=serial@COM1:19200

Run

  java net.tinyos.tools.BcastInject start_sensing <num_samples> <interval>
where num_samples is the number of samples to take (say, 8 or 16), and interval is the time in milliseconds between samples (say, 100). For example:
  java net.tinyos.tools.BcastInject start_sensing 16 100
You should see the mote's red LED blink while samples are being taken.

To get the log data back from the mote, use:

  java net.tinyos.tools.BcastInject read_log <mote_address>
where mote_address is the address of the mote to read log data from. For example:
  % java net.tinyos.tools.BcastInject read_log 2
  Sending payload: 65 6 0 0 0 2 0 0 0 0 0 
  serial@COM1:19200: resynchronizing 
  Waiting for response to read_log...
  Received log message: Message <LogMsg> [sourceaddr=0x2] 
  Log values: 48 1 38 1 33 1 32 1 32 1 33 1 34 1 34 1
The program will wait 10 seconds for a response to the read_log command; if you don't see a response, try again. If you don't get a reply, then possibly the mote didn't get the command (the green LED will toggle for each command received), or you didn't specify the right mote_address. Each subsequent read_log command you send will read the next log entry from the mote; if you want to reset the read pointer, just power-cycle the mote. Remember that the EEPROM data is persistent across power-cycles, but the current read pointer is kept in volatile memory!


< Previous Lesson | Index Page > | Top