231 lines
6.6 KiB
C
231 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();
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|