/* * Copyright (c) 2010, Loughborough University - Computer Science * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the Contiki operating system. */ /** * \file * Sources for the BATtery MONitor app. It dumps a log entry to the * external flash periodically as well as upon external trigger. * * It started off as a VDD and battery logger but now it also stores * energest values and other goodies. * * \author * George Oikonomou - */ #include "contiki.h" #define DEBUG 0 #if DEBUG #include #define PRINTF(...) printf(__VA_ARGS__) #else #define PRINTF(...) #endif #include "sys/etimer.h" #include "sys/energest.h" #include "dev/sensinode-sensors.h" #include "dev/n740.h" #include "dev/m25p16.h" #define BATMON_LOG_PERIOD 60 /* in seconds */ /*---------------------------------------------------------------------------*/ static const uint8_t magic[3] = { 0x0B, 0xEE, 0xF0 }; /*---------------------------------------------------------------------------*/ struct record { uint8_t magic[3]; uint8_t trigger; unsigned long c; /* uptime */ int v; /* VDD (reference) */ int b; /* Voltage ADC */ #if ENERGEST_CONF_ON unsigned long mcu; unsigned long lpm; unsigned long irq; unsigned long tx; unsigned long rx; unsigned long f_write; unsigned long f_read; #endif }; #define RECORD_SIZE 64 #define LAST_WRITE (0xFFFF - RECORD_SIZE) #define LOG_TRIGGER_PERIODIC 0xFF /*---------------------------------------------------------------------------*/ struct flash_address { uint8_t s; /* sector */ uint8_t p; /* page */ uint8_t a; /* address */ }; static struct flash_address f; static struct record r; static struct sensors_sensor *s; static struct etimer et; #define FLASH_START_ADDR 0x1E0000 #define FLASH_END_ADDR 0x1FFFFF /*---------------------------------------------------------------------------*/ PROCESS(batmon_process, "Logger Process"); /*---------------------------------------------------------------------------*/ static int find_gap() CC_NON_BANKED { uint8_t seq[3]; uint32_t address = FLASH_START_ADDR; memset(&f, 0, sizeof(f)); for(address = FLASH_START_ADDR; address <= FLASH_END_ADDR; address += RECORD_SIZE) { n740_analog_deactivate(); f.s = ((address & 0xFF0000) >> 16); f.p = ((address & 0xFF00) >> 8); f.a = address & 0xFF; m25p16_read_fast((uint8_t *)&f, seq, sizeof(magic)); n740_analog_activate(); if(memcmp(seq, magic, sizeof(magic)) != 0) { PRINTF("BatMon: Resume write @ 0x%02x%02x%02x\n", f.s, f.p, f.a); return 1; } } /* If we reach here, we ran out of flash */ return -1; } /*---------------------------------------------------------------------------*/ static void abort() CC_NON_BANKED { PRINTF("BatMon: Abort\n"); etimer_stop(&et); process_exit(&batmon_process); } /*---------------------------------------------------------------------------*/ void batmon_log(uint8_t trigger) { uint32_t next; /* Only continue if the process (us) is running */ if(!process_is_running(&batmon_process)) { return; } next = f.a; next |= (((uint32_t) f.p) << 8); next |= (((uint32_t) f.s) << 16); memcpy(r.magic, magic, sizeof(magic)); r.trigger = trigger; r.c = clock_seconds(); /* Read VDD and use as ADC reference */ r.v = s->value(ADC_SENSOR_TYPE_VDD); /* And then carry on with battery */ r.b = s->value(ADC_SENSOR_TYPE_BATTERY); #if ENERGEST_CONF_ON /* ENERGEST values */ r.mcu = energest_type_time(ENERGEST_TYPE_CPU); r.lpm = energest_type_time(ENERGEST_TYPE_LPM); r.irq = energest_type_time(ENERGEST_TYPE_IRQ); r.tx = energest_type_time(ENERGEST_TYPE_TRANSMIT); r.rx = energest_type_time(ENERGEST_TYPE_LISTEN); r.f_write = energest_type_time(ENERGEST_TYPE_FLASH_WRITE); r.f_read = energest_type_time(ENERGEST_TYPE_FLASH_READ); #endif n740_analog_deactivate(); /* Make sure we're on */ if(M25P16_WIP()) { m25p16_res(); } m25p16_pp((uint8_t *)&f, (uint8_t *)&r, sizeof(r)); n740_analog_activate(); PRINTF("BatMon: @%lu [%u] ", r.c, r.trigger); PRINTF("BatMon: 0x%02x%02x%02x\n", f.s, f.p, f.a); next += RECORD_SIZE; if(next >= FLASH_END_ADDR) { abort(); return; } f.s = ((next & 0xFF0000) >> 16); f.p = ((next & 0xFF00) >> 8); f.a = next & 0xFF; if(trigger == LOG_TRIGGER_PERIODIC) { etimer_reset(&et); } } /*---------------------------------------------------------------------------*/ PROCESS_THREAD(batmon_process, ev, data) { PROCESS_BEGIN(); PRINTF("BatMon\n", sizeof(r)); s = sensors_find(ADC_SENSOR); if(!s) { PRINTF("BatMon: ADC not found\n"); PROCESS_EXIT(); } n740_analog_deactivate(); m25p16_res(); n740_analog_activate(); /* Find last written location */ if(find_gap() == -1) { PRINTF("BatMon: Flash storage full\n"); PROCESS_EXIT(); } etimer_set(&et, BATMON_LOG_PERIOD * CLOCK_SECOND); while(1) { PROCESS_YIELD(); if(ev == PROCESS_EVENT_TIMER && etimer_expired(&et)) { batmon_log(LOG_TRIGGER_PERIODIC); } } PROCESS_END(); } /*---------------------------------------------------------------------------*/