Contiki 2.6

batmon.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2010, Loughborough University - Computer Science
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the Institute nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * This file is part of the Contiki operating system.
00030  */
00031 
00032 /**
00033  * \file
00034  *         Sources for the BATtery MONitor app. It dumps a log entry to the
00035  *         external flash periodically as well as upon external trigger.
00036  *
00037  *         It started off as a VDD and battery logger but now it also stores
00038  *         energest values and other goodies.
00039  *
00040  * \author
00041  *         George Oikonomou - <oikonomou@users.sourceforge.net>
00042  */
00043 
00044 #include "contiki.h"
00045 
00046 #define DEBUG 0
00047 #if DEBUG
00048 #include <stdio.h>
00049 #define PRINTF(...) printf(__VA_ARGS__)
00050 #else
00051 #define PRINTF(...)
00052 #endif
00053 
00054 #include "sys/etimer.h"
00055 #include "sys/energest.h"
00056 #include "dev/sensinode-sensors.h"
00057 #include "dev/n740.h"
00058 #include "dev/m25p16.h"
00059 
00060 #define BATMON_LOG_PERIOD 60 /* in seconds */
00061 /*---------------------------------------------------------------------------*/
00062 static const uint8_t magic[3] = { 0x0B, 0xEE, 0xF0 };
00063 /*---------------------------------------------------------------------------*/
00064 struct record {
00065   uint8_t magic[3];
00066   uint8_t trigger;
00067   unsigned long c; /* uptime */
00068   int v; /* VDD (reference) */
00069   int b; /* Voltage ADC */
00070 #if ENERGEST_CONF_ON
00071   unsigned long mcu;
00072   unsigned long lpm;
00073   unsigned long irq;
00074   unsigned long tx;
00075   unsigned long rx;
00076   unsigned long f_write;
00077   unsigned long f_read;
00078 #endif
00079 };
00080 
00081 #define RECORD_SIZE 64
00082 #define LAST_WRITE (0xFFFF - RECORD_SIZE)
00083 
00084 #define LOG_TRIGGER_PERIODIC 0xFF
00085 /*---------------------------------------------------------------------------*/
00086 struct flash_address {
00087   uint8_t s; /* sector */
00088   uint8_t p; /* page */
00089   uint8_t a; /* address */
00090 };
00091 static struct flash_address f;
00092 
00093 static struct record r;
00094 static struct sensors_sensor * s;
00095 static struct etimer et;
00096 #define FLASH_START_ADDR 0x1E0000
00097 #define FLASH_END_ADDR   0x1FFFFF
00098 /*---------------------------------------------------------------------------*/
00099 PROCESS(batmon_process, "Logger Process");
00100 /*---------------------------------------------------------------------------*/
00101 static int
00102 find_gap() CC_NON_BANKED
00103 {
00104   uint8_t seq[3];
00105   uint32_t address = FLASH_START_ADDR;
00106   memset(&f, 0, sizeof(f));
00107 
00108   for(address = FLASH_START_ADDR; address <= FLASH_END_ADDR; address +=
00109       RECORD_SIZE) {
00110     n740_analog_deactivate();
00111     f.s = ((address & 0xFF0000) >> 16);
00112     f.p = ((address & 0xFF00) >> 8);
00113     f.a = address & 0xFF;
00114     m25p16_read_fast((uint8_t *)&f, seq, sizeof(magic));
00115     n740_analog_activate();
00116     if(memcmp(seq, magic, sizeof(magic)) != 0) {
00117       PRINTF("BatMon: Resume write @ 0x%02x%02x%02x\n", f.s, f.p, f.a);
00118       return 1;
00119     }
00120   }
00121 
00122   /* If we reach here, we ran out of flash */
00123   return -1;
00124 }
00125 /*---------------------------------------------------------------------------*/
00126 static void
00127 abort() CC_NON_BANKED
00128 {
00129   PRINTF("BatMon: Abort\n");
00130   etimer_stop(&et);
00131   process_exit(&batmon_process);
00132 }
00133 /*---------------------------------------------------------------------------*/
00134 void
00135 batmon_log(uint8_t trigger)
00136 {
00137   uint32_t next;
00138 
00139   /* Only continue if the process (us) is running */
00140   if(!process_is_running(&batmon_process)) {
00141     return;
00142   }
00143 
00144   next = f.a;
00145   next |= (((uint32_t) f.p) << 8);
00146   next |= (((uint32_t) f.s) << 16);
00147 
00148   memcpy(r.magic, magic, sizeof(magic));
00149   r.trigger = trigger;
00150   r.c = clock_seconds();
00151 
00152   /* Read VDD and use as ADC reference */
00153   r.v = s->value(ADC_SENSOR_TYPE_VDD);
00154 
00155   /* And then carry on with battery */
00156   r.b = s->value(ADC_SENSOR_TYPE_BATTERY);
00157 
00158 #if ENERGEST_CONF_ON
00159   /* ENERGEST values */
00160   r.mcu = energest_type_time(ENERGEST_TYPE_CPU);
00161   r.lpm = energest_type_time(ENERGEST_TYPE_LPM);
00162   r.irq = energest_type_time(ENERGEST_TYPE_IRQ);
00163   r.tx = energest_type_time(ENERGEST_TYPE_TRANSMIT);
00164   r.rx = energest_type_time(ENERGEST_TYPE_LISTEN);
00165   r.f_write = energest_type_time(ENERGEST_TYPE_FLASH_WRITE);
00166   r.f_read = energest_type_time(ENERGEST_TYPE_FLASH_READ);
00167 #endif
00168 
00169   n740_analog_deactivate();
00170   /* Make sure we're on */
00171   if(M25P16_WIP()) {
00172     m25p16_res();
00173   }
00174   m25p16_pp((uint8_t *)&f, (uint8_t *)&r, sizeof(r));
00175   n740_analog_activate();
00176 
00177   PRINTF("BatMon: @%lu [%u] ", r.c, r.trigger);
00178   PRINTF("BatMon: 0x%02x%02x%02x\n", f.s, f.p, f.a);
00179 
00180   next += RECORD_SIZE;
00181 
00182   if(next >= FLASH_END_ADDR) {
00183     abort();
00184     return;
00185   }
00186 
00187   f.s = ((next & 0xFF0000) >> 16);
00188   f.p = ((next & 0xFF00) >> 8);
00189   f.a = next & 0xFF;
00190 
00191   if(trigger == LOG_TRIGGER_PERIODIC) {
00192     etimer_reset(&et);
00193   }
00194 }
00195 /*---------------------------------------------------------------------------*/
00196 PROCESS_THREAD(batmon_process, ev, data)
00197 {
00198 
00199   PROCESS_BEGIN();
00200 
00201   PRINTF("BatMon\n", sizeof(r));
00202 
00203   s = sensors_find(ADC_SENSOR);
00204   if (!s) {
00205     PRINTF("BatMon: ADC not found\n");
00206     PROCESS_EXIT();
00207   }
00208 
00209   n740_analog_deactivate();
00210   m25p16_res();
00211   n740_analog_activate();
00212 
00213   /* Find last written location */
00214   if(find_gap() == -1) {
00215     PRINTF("BatMon: Flash storage full\n");
00216     PROCESS_EXIT();
00217   }
00218 
00219   etimer_set(&et, BATMON_LOG_PERIOD * CLOCK_SECOND);
00220 
00221   while(1) {
00222     PROCESS_YIELD();
00223     if(ev == PROCESS_EVENT_TIMER && etimer_expired(&et)) {
00224       batmon_log(LOG_TRIGGER_PERIODIC);
00225     }
00226   }
00227 
00228   PROCESS_END();
00229 }
00230 /*---------------------------------------------------------------------------*/