osd-contiki/platform/sensinode/apps/batmon/batmon.c
2012-12-16 19:28:55 +00:00

230 lines
6.6 KiB
C

/*
* 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 - <oikonomou@users.sourceforge.net>
*/
#include "contiki.h"
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#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();
}
/*---------------------------------------------------------------------------*/