Contiki 3.x
batmon.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010, Loughborough University - Computer Science
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  */
31 
32 /**
33  * \file
34  * Sources for the BATtery MONitor app. It dumps a log entry to the
35  * external flash periodically as well as upon external trigger.
36  *
37  * It started off as a VDD and battery logger but now it also stores
38  * energest values and other goodies.
39  *
40  * \author
41  * George Oikonomou - <oikonomou@users.sourceforge.net>
42  */
43 
44 #include "contiki.h"
45 
46 #define DEBUG 0
47 #if DEBUG
48 #include <stdio.h>
49 #define PRINTF(...) printf(__VA_ARGS__)
50 #else
51 #define PRINTF(...)
52 #endif
53 
54 #include "sys/etimer.h"
55 #include "sys/energest.h"
56 #include "dev/sensinode-sensors.h"
57 #include "dev/n740.h"
58 #include "dev/m25p16.h"
59 
60 #define BATMON_LOG_PERIOD 60 /* in seconds */
61 /*---------------------------------------------------------------------------*/
62 static const uint8_t magic[3] = { 0x0B, 0xEE, 0xF0 };
63 /*---------------------------------------------------------------------------*/
64 struct record {
65  uint8_t magic[3];
66  uint8_t trigger;
67  unsigned long c; /* uptime */
68  int v; /* VDD (reference) */
69  int b; /* Voltage ADC */
70 #if ENERGEST_CONF_ON
71  unsigned long mcu;
72  unsigned long lpm;
73  unsigned long irq;
74  unsigned long tx;
75  unsigned long rx;
76  unsigned long f_write;
77  unsigned long f_read;
78 #endif
79 };
80 
81 #define RECORD_SIZE 64
82 #define LAST_WRITE (0xFFFF - RECORD_SIZE)
83 
84 #define LOG_TRIGGER_PERIODIC 0xFF
85 /*---------------------------------------------------------------------------*/
86 struct flash_address {
87  uint8_t s; /* sector */
88  uint8_t p; /* page */
89  uint8_t a; /* address */
90 };
91 static struct flash_address f;
92 
93 static struct record r;
94 static struct sensors_sensor *s;
95 static struct etimer et;
96 #define FLASH_START_ADDR 0x1E0000
97 #define FLASH_END_ADDR 0x1FFFFF
98 /*---------------------------------------------------------------------------*/
99 PROCESS(batmon_process, "Logger Process");
100 /*---------------------------------------------------------------------------*/
101 static int
102 find_gap() CC_NON_BANKED
103 {
104  uint8_t seq[3];
105  uint32_t address = FLASH_START_ADDR;
106  memset(&f, 0, sizeof(f));
107 
108  for(address = FLASH_START_ADDR; address <= FLASH_END_ADDR; address +=
109  RECORD_SIZE) {
110  n740_analog_deactivate();
111  f.s = ((address & 0xFF0000) >> 16);
112  f.p = ((address & 0xFF00) >> 8);
113  f.a = address & 0xFF;
114  m25p16_read_fast((uint8_t *)&f, seq, sizeof(magic));
115  n740_analog_activate();
116  if(memcmp(seq, magic, sizeof(magic)) != 0) {
117  PRINTF("BatMon: Resume write @ 0x%02x%02x%02x\n", f.s, f.p, f.a);
118  return 1;
119  }
120  }
121 
122  /* If we reach here, we ran out of flash */
123  return -1;
124 }
125 /*---------------------------------------------------------------------------*/
126 static void
127 abort() CC_NON_BANKED
128 {
129  PRINTF("BatMon: Abort\n");
130  etimer_stop(&et);
131  process_exit(&batmon_process);
132 }
133 /*---------------------------------------------------------------------------*/
134 void
135 batmon_log(uint8_t trigger)
136 {
137  uint32_t next;
138 
139  /* Only continue if the process (us) is running */
140  if(!process_is_running(&batmon_process)) {
141  return;
142  }
143 
144  next = f.a;
145  next |= (((uint32_t) f.p) << 8);
146  next |= (((uint32_t) f.s) << 16);
147 
148  memcpy(r.magic, magic, sizeof(magic));
149  r.trigger = trigger;
150  r.c = clock_seconds();
151 
152  /* Read VDD and use as ADC reference */
153  r.v = s->value(ADC_SENSOR_TYPE_VDD);
154 
155  /* And then carry on with battery */
156  r.b = s->value(ADC_SENSOR_TYPE_BATTERY);
157 
158 #if ENERGEST_CONF_ON
159  /* ENERGEST values */
160  r.mcu = energest_type_time(ENERGEST_TYPE_CPU);
161  r.lpm = energest_type_time(ENERGEST_TYPE_LPM);
162  r.irq = energest_type_time(ENERGEST_TYPE_IRQ);
163  r.tx = energest_type_time(ENERGEST_TYPE_TRANSMIT);
164  r.rx = energest_type_time(ENERGEST_TYPE_LISTEN);
165  r.f_write = energest_type_time(ENERGEST_TYPE_FLASH_WRITE);
166  r.f_read = energest_type_time(ENERGEST_TYPE_FLASH_READ);
167 #endif
168 
169  n740_analog_deactivate();
170  /* Make sure we're on */
171  if(M25P16_WIP()) {
172  m25p16_res();
173  }
174  m25p16_pp((uint8_t *)&f, (uint8_t *)&r, sizeof(r));
175  n740_analog_activate();
176 
177  PRINTF("BatMon: @%lu [%u] ", r.c, r.trigger);
178  PRINTF("BatMon: 0x%02x%02x%02x\n", f.s, f.p, f.a);
179 
180  next += RECORD_SIZE;
181 
182  if(next >= FLASH_END_ADDR) {
183  abort();
184  return;
185  }
186 
187  f.s = ((next & 0xFF0000) >> 16);
188  f.p = ((next & 0xFF00) >> 8);
189  f.a = next & 0xFF;
190 
191  if(trigger == LOG_TRIGGER_PERIODIC) {
192  etimer_reset(&et);
193  }
194 }
195 /*---------------------------------------------------------------------------*/
196 PROCESS_THREAD(batmon_process, ev, data)
197 {
198 
199  PROCESS_BEGIN();
200 
201  PRINTF("BatMon\n", sizeof(r));
202 
203  s = sensors_find(ADC_SENSOR);
204  if(!s) {
205  PRINTF("BatMon: ADC not found\n");
206  PROCESS_EXIT();
207  }
208 
209  n740_analog_deactivate();
210  m25p16_res();
211  n740_analog_activate();
212 
213  /* Find last written location */
214  if(find_gap() == -1) {
215  PRINTF("BatMon: Flash storage full\n");
216  PROCESS_EXIT();
217  }
218 
219  etimer_set(&et, BATMON_LOG_PERIOD * CLOCK_SECOND);
220 
221  while(1) {
222  PROCESS_YIELD();
223  if(ev == PROCESS_EVENT_TIMER && etimer_expired(&et)) {
224  batmon_log(LOG_TRIGGER_PERIODIC);
225  }
226  }
227 
228  PROCESS_END();
229 }
230 /*---------------------------------------------------------------------------*/
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
Definition: etimer.c:205
int process_is_running(struct process *p)
Check if a process is running.
Definition: process.c:383
#define PROCESS_EXIT()
Exit the currently running process.
Definition: process.h:200
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
Header file for the control of the M25P16 on sensinode N740s.
void m25p16_pp(uint8_t *addr, uint8_t *buff, uint8_t buff_len)
Program Page (PP) instruction.
Definition: m25p16.c:224
Header file for the energy estimation mechanism
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
Header File for the module which controls the Sensinode N740 8-bit serial-in/serial or parall...
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
CCIF unsigned long clock_seconds(void)
Get the current value of the platform seconds.
Definition: clock.c:57
void etimer_reset(struct etimer *et)
Reset an event timer with the same interval as was previously set.
Definition: etimer.c:184
void etimer_stop(struct etimer *et)
Stop a pending event timer.
Definition: etimer.c:235
#define PROCESS_YIELD()
Yield the currently running process.
Definition: process.h:164
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
Definition: etimer.c:177
Defines for the sensors on the various Sensinode models.
Event timer header file.
A timer.
Definition: etimer.h:76
#define M25P16_WIP()
Check for Write in Progress.
Definition: m25p16.h:116
void process_exit(struct process *p)
Cause a process to exit.
Definition: process.c:202
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82
void m25p16_res()
Release from Deep Power Down (RES) instruction.
Definition: m25p16.c:284