diff --git a/examples/energest-demo/Makefile b/examples/energest-demo/Makefile
new file mode 100644
index 000000000..ea6206bd7
--- /dev/null
+++ b/examples/energest-demo/Makefile
@@ -0,0 +1,39 @@
+
+all: burn-nodeids javaapp energest-demo.ihex
+
+burn-nodeids:
+ (cd nodeid; $(MAKE))
+
+javaapp:
+ ant compile
+
+ifndef CONTIKI
+CONTIKI = ../..
+endif
+
+# Ensure that ./contiki-conf.h is included
+CFLAGS+=-I.
+
+ifndef TARGET
+TARGET=sky
+endif
+
+ifdef UPDATE
+CFLAGS += -DUPDATE_TICKS=CLOCK_SECOND*$(UPDATE)
+else
+CFLAGS += -DUPDATE_TICKS=CLOCK_SECOND
+endif
+
+ifdef CHANNEL
+CFLAGS += -DRF_CHANNEL=$(CHANNEL)
+else
+CFLAGS += -DRF_CHANNEL=20
+endif
+
+
+%.upload: %.ihex
+ cp $< ../testbed-server/image.ihex
+ (cd ../testbed-server; make upload)
+
+
+include $(CONTIKI)/Makefile.include
diff --git a/examples/energest-demo/build.xml b/examples/energest-demo/build.xml
new file mode 100644
index 000000000..d67ea76e5
--- /dev/null
+++ b/examples/energest-demo/build.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Examples:
+
+> ant run -Dargs="com1"
+Starts demo application listening on COM1 and tracking the first node.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/energest-demo/contiki-conf.h b/examples/energest-demo/contiki-conf.h
new file mode 100644
index 000000000..994e31c81
--- /dev/null
+++ b/examples/energest-demo/contiki-conf.h
@@ -0,0 +1,180 @@
+/* -*- C -*- */
+/* @(#)$Id: contiki-conf.h,v 1.1 2007/10/25 12:56:28 adamdunkels Exp $ */
+
+#ifndef CONTIKI_CONF_H
+#define CONTIKI_CONF_H
+
+#define HAVE_STDINT_H
+#include "msp430def.h"
+
+#ifndef RF_CHANNEL
+#define RF_CHANNEL 26
+#endif
+
+#define ELFLOADER_CONF_DATAMEMORY_SIZE 0x1800
+#define ELFLOADER_CONF_TEXTMEMORY_SIZE 0x1000
+
+#define IRQ_PORT1 0x01
+#define IRQ_PORT2 0x02
+#define IRQ_ADC 0x03
+
+#define CCIF
+#define CLIF
+
+#define CC_CONF_INLINE inline
+
+#define AODV_COMPLIANCE
+#define AODV_NUM_RT_ENTRIES 32
+
+#define TMOTE_SKY 1
+#define WITH_ASCII 1
+
+#define PROCESS_CONF_FASTPOLL 4
+
+/* CPU target speed in Hz */
+#define F_CPU 2457600uL
+
+/* Our clock resolution, this is the same as Unix HZ. */
+#define CLOCK_CONF_SECOND 100
+
+#define BAUD2UBR(baud) ((F_CPU/baud))
+
+#define UIP_CONF_DHCP_LIGHT
+#define UIP_CONF_LLH_LEN 0
+#define UIP_CONF_BUFFER_SIZE 116
+#define UIP_CONF_RECEIVE_WINDOW (UIP_CONF_BUFFER_SIZE - 40)
+#define UIP_CONF_MAX_CONNECTIONS 4
+#define UIP_CONF_MAX_LISTENPORTS 8
+#define UIP_CONF_UDP_CONNS 12
+#define UIP_CONF_FWCACHE_SIZE 30
+#define UIP_CONF_BROADCAST 1
+#define UIP_ARCH_IPCHKSUM 1
+#define UIP_CONF_UDP_CHECKSUMS 1
+#define UIP_CONF_PINGADDRCONF 0
+#define UIP_CONF_LOGGING 0
+
+/*
+ * Definitions below are dictated by the hardware and not really
+ * changeable!
+ */
+
+/* LED ports */
+#define LEDS_PxDIR P5DIR
+#define LEDS_PxOUT P5OUT
+#define LEDS_CONF_RED 0x10
+#define LEDS_CONF_GREEN 0x20
+#define LEDS_CONF_YELLOW 0x40
+
+/* Button sensors. */
+#define IRQ_PORT2 0x02
+
+typedef unsigned short uip_stats_t;
+typedef unsigned short clock_time_t;
+
+typedef unsigned long off_t;
+#define ROM_ERASE_UNIT_SIZE 512
+#define XMEM_ERASE_UNIT_SIZE (64*1024L)
+
+#define XMAC_CONF_ON_TIME RTIMER_ARCH_SECOND / 100
+#define XMAC_CONF_OFF_TIME RTIMER_ARCH_SECOND / 10
+
+/* Use the first 64k of external flash for node configuration */
+#define NODE_ID_XMEM_OFFSET (0 * XMEM_ERASE_UNIT_SIZE)
+
+/* Use the second 64k of external flash for codeprop. */
+#define EEPROMFS_ADDR_CODEPROP (1 * XMEM_ERASE_UNIT_SIZE)
+
+#define CFS_XMEM_CONF_OFFSET (2 * XMEM_ERASE_UNIT_SIZE)
+#define CFS_XMEM_CONF_SIZE (1 * XMEM_ERASE_UNIT_SIZE)
+
+#define CFS_RAM_CONF_SIZE 4096
+
+#define CC2420_RADIO
+/*
+ * SPI bus configuration for the TMote Sky.
+ */
+
+/* SPI input/output registers. */
+#define SPI_TXBUF U0TXBUF
+#define SPI_RXBUF U0RXBUF
+
+ /* USART0 Tx buffer ready? */
+#define SPI_WAITFOREOTx() while ((U0TCTL & TXEPT) == 0)
+ /* USART0 Rx buffer ready? */
+#define SPI_WAITFOREORx() while ((IFG1 & URXIFG0) == 0)
+
+#define SCK 1 /* P3.1 - Output: SPI Serial Clock (SCLK) */
+#define MOSI 2 /* P3.2 - Output: SPI Master out - slave in (MOSI) */
+#define MISO 3 /* P3.3 - Input: SPI Master in - slave out (MISO) */
+
+/*
+ * SPI bus - M25P80 external flash configuration.
+ */
+
+#define FLASH_PWR 3 /* P4.3 Output */
+#define FLASH_CS 4 /* P4.4 Output */
+#define FLASH_HOLD 7 /* P4.7 Output */
+
+/* Enable/disable flash access to the SPI bus (active low). */
+
+#define SPI_FLASH_ENABLE() ( P4OUT &= ~BV(FLASH_CS) )
+#define SPI_FLASH_DISABLE() ( P4OUT |= BV(FLASH_CS) )
+
+#define SPI_FLASH_HOLD() ( P4OUT &= ~BV(FLASH_HOLD) )
+#define SPI_FLASH_UNHOLD() ( P4OUT |= BV(FLASH_HOLD) )
+
+/*
+ * SPI bus - CC2420 pin configuration.
+ */
+
+#define FIFO_P 0 /* P1.0 - Input: FIFOP from CC2420 */
+#define FIFO 3 /* P1.3 - Input: FIFO from CC2420 */
+#define CCA 4 /* P1.4 - Input: CCA from CC2420 */
+
+#define SFD 1 /* P4.1 - Input: SFD from CC2420 */
+#define CSN 2 /* P4.2 - Output: SPI Chip Select (CS_N) */
+#define VREG_EN 5 /* P4.5 - Output: VREG_EN to CC2420 */
+#define RESET_N 6 /* P4.6 - Output: RESET_N to CC2420 */
+
+/* Pin status. */
+
+#define FIFO_IS_1 (!!(P1IN & BV(FIFO)))
+#define CCA_IS_1 (!!(P1IN & BV(CCA) ))
+#define RESET_IS_1 (!!(P4IN & BV(RESET_N)))
+#define VREG_IS_1 (!!(P4IN & BV(VREG_EN)))
+#define FIFOP_IS_1 (!!(P1IN & BV(FIFO_P)))
+#define SFD_IS_1 (!!(P4IN & BV(SFD)))
+
+/* The CC2420 reset pin. */
+#define SET_RESET_INACTIVE() ( P4OUT |= BV(RESET_N) )
+#define SET_RESET_ACTIVE() ( P4OUT &= ~BV(RESET_N) )
+
+/* CC2420 voltage regulator enable pin. */
+#define SET_VREG_ACTIVE() ( P4OUT |= BV(VREG_EN) )
+#define SET_VREG_INACTIVE() ( P4OUT &= ~BV(VREG_EN) )
+
+/* CC2420 rising edge trigger for external interrupt 0 (FIFOP). */
+#define FIFOP_INT_INIT() do {\
+ P1IES &= ~BV(FIFO_P);\
+ CLEAR_FIFOP_INT();\
+} while (0)
+
+/* FIFOP on external interrupt 0. */
+#define ENABLE_FIFOP_INT() do { P1IE |= BV(FIFO_P); } while (0)
+#define DISABLE_FIFOP_INT() do { P1IE &= ~BV(FIFO_P); } while (0)
+#define CLEAR_FIFOP_INT() do { P1IFG &= ~BV(FIFO_P); } while (0)
+
+/* Enables/disables CC2420 access to the SPI bus (not the bus).
+ *
+ * These guys should really be renamed but are compatible with the
+ * original Chipcon naming.
+ *
+ * SPI_CC2420_ENABLE/SPI_CC2420_DISABLE???
+ * CC2420_ENABLE_SPI/CC2420_DISABLE_SPI???
+ */
+
+#define SPI_ENABLE() ( P4OUT &= ~BV(CSN) ) /* ENABLE CSn (active low) */
+#define SPI_DISABLE() ( P4OUT |= BV(CSN) ) /* DISABLE CSn (active low) */
+
+
+#endif /* CONTIKI_CONF_H */
diff --git a/examples/energest-demo/contiki-sky-main.c b/examples/energest-demo/contiki-sky-main.c
new file mode 100644
index 000000000..fd52efa45
--- /dev/null
+++ b/examples/energest-demo/contiki-sky-main.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2006, Swedish Institute of 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.
+ *
+ * @(#)$Id: contiki-sky-main.c,v 1.1 2007/10/25 12:56:28 adamdunkels Exp $
+ */
+
+#include
+#include
+#include
+
+#include
+
+#include "contiki.h"
+
+#include "dev/button-sensor.h"
+#include "dev/ds2411.h"
+#include "dev/sht11.h"
+#include "dev/leds.h"
+#include "dev/light.h"
+#include "dev/xmem.h"
+#include "dev/simple-cc2420.h"
+
+#include "dev/slip.h"
+#include "dev/uart1.h"
+
+#include "net/mac/xmac.h"
+#include "net/mac/nullmac.h"
+
+#include "node-id.h"
+
+#include "net/rime.h"
+
+#include "sys/autostart.h"
+
+/*#include "codeprop/codeprop.h"*/
+
+SENSORS(&button_sensor);
+
+extern int lpm_en;
+
+#define WITH_UIP 0
+
+#if WITH_UIP
+static struct uip_fw_netif slipif =
+{UIP_FW_NETIF(192,168,1,2, 255,255,255,255, slip_send)};
+#endif /* WITH_UIP */
+
+/*---------------------------------------------------------------------------*/
+#if 0
+int
+force_float_inclusion()
+{
+ extern int __fixsfsi;
+ extern int __floatsisf;
+ extern int __mulsf3;
+ extern int __subsf3;
+
+ return __fixsfsi + __floatsisf + __mulsf3 + __subsf3;
+}
+#endif
+/*---------------------------------------------------------------------------*/
+void uip_log(char *msg) { puts(msg); }
+/*---------------------------------------------------------------------------*/
+/* Radio stuff in network byte order. */
+static u16_t panId = 0x2024;
+
+#ifndef RF_CHANNEL
+#error define RF_CHANNEL!
+#endif
+
+/*---------------------------------------------------------------------------*/
+void
+force_inclusion(int d1, int d2)
+{
+ snprintf(NULL, 0, "%d", d1 % d2);
+}
+/*---------------------------------------------------------------------------*/
+static void
+set_rime_addr(void)
+{
+ rimeaddr_t addr;
+ addr.u16[0] = node_id;
+ rimeaddr_set_node_addr(&addr);
+}
+/*---------------------------------------------------------------------------*/
+int
+main(int argc, char **argv)
+{
+ /*
+ * Initalize hardware.
+ */
+ msp430_cpu_init();
+ clock_init();
+ leds_init();
+ leds_toggle(LEDS_RED | LEDS_GREEN | LEDS_BLUE);
+
+#if WITH_UIP
+ slip_arch_init(BAUD2UBR(115200)); /* Must come before first printf */
+#else /* WITH_UIP */
+ uart1_init(BAUD2UBR(115200)); /* Must come before first printf */
+#endif /* WITH_UIP */
+
+ printf("Starting %s "
+ "($Id: contiki-sky-main.c,v 1.1 2007/10/25 12:56:28 adamdunkels Exp $)\n", __FILE__);
+ ds2411_init();
+ sensors_light_init();
+ sht11_init();
+ xmem_init();
+ leds_toggle(LEDS_RED | LEDS_GREEN | LEDS_BLUE);
+
+ rtimer_init();
+ /*
+ * Hardware initialization done!
+ */
+
+ /* Restore node id if such has been stored in external mem */
+// node_id_burn(3);
+ node_id_restore();
+ printf("node_id : %hu\n", node_id);
+
+ printf("MAC %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ ds2411_id[0], ds2411_id[1], ds2411_id[2], ds2411_id[3],
+ ds2411_id[4], ds2411_id[5], ds2411_id[6], ds2411_id[7]);
+
+#if WITH_UIP
+ uip_init();
+ uip_sethostaddr(&slipif.ipaddr);
+ uip_setnetmask(&slipif.netmask);
+ uip_fw_default(&slipif); /* Point2point, no default router. */
+ tcpip_set_forwarding(0);
+#endif /* WITH_UIP */
+
+ /*
+ * Initialize Contiki and our processes.
+ */
+ process_init();
+ process_start(&etimer_process, NULL);
+ process_start(&sensors_process, NULL);
+
+ set_rime_addr();
+
+ simple_cc2420_init();
+ simple_cc2420_set_chan_pan_addr(RF_CHANNEL, panId, 0 /*XXX*/, ds2411_id);
+ simple_cc2420_set_txpower(31);
+ nullmac_init(&simple_cc2420_driver);
+ rime_init(&nullmac_driver);
+// xmac_init(&simple_cc2420_driver);
+// rime_init(&xmac_driver);
+
+ /* rimeaddr_set_node_addr*/
+#if WITH_UIP
+ process_start(&tcpip_process, NULL);
+ process_start(&uip_fw_process, NULL); /* Start IP output */
+ process_start(&slip_process, NULL);
+#endif /* WITH_UIP */
+
+ button_sensor.activate();
+
+ printf("Autostarting processes\n");
+ autostart_start((struct process **) autostart_processes);
+
+ energest_init();
+
+ /*
+ * This is the scheduler loop.
+ */
+ printf("process_run()...\n");
+ ENERGEST_ON(ENERGEST_TYPE_CPU);
+ while (1) {
+ do {
+ /* Reset watchdog. */
+ } while(process_run() > 0);
+
+ /*
+ * Idle processing.
+ */
+ if(lpm_en) {
+ int s = splhigh(); /* Disable interrupts. */
+ if(process_nevents() != 0) {
+ splx(s); /* Re-enable interrupts. */
+ } else {
+
+ static unsigned long irq_energest = 0;
+ /* Re-enable interrupts and go to sleep atomically. */
+ ENERGEST_OFF(ENERGEST_TYPE_CPU);
+ ENERGEST_ON(ENERGEST_TYPE_LPM);
+ /* We only want to measure the processing done in IRQs when we
+ are asleep, so we discard the processing time done when we
+ were awake. */
+ energest_type_set(ENERGEST_TYPE_IRQ, irq_energest);
+ _BIS_SR(GIE | SCG0 | /*SCG1 |*/ CPUOFF); /* LPM3 sleep. */
+ /* We get the current processing time for interrupts that was
+ done during the LPM and store it for next time around. */
+ dint();
+ irq_energest = energest_type_time(ENERGEST_TYPE_IRQ);
+ eint();
+ ENERGEST_OFF(ENERGEST_TYPE_LPM);
+ ENERGEST_ON(ENERGEST_TYPE_CPU);
+ }
+ }
+ }
+
+ return 0;
+}
+/*---------------------------------------------------------------------------*/
diff --git a/examples/energest-demo/energest-demo.c b/examples/energest-demo/energest-demo.c
new file mode 100644
index 000000000..2b7c93e50
--- /dev/null
+++ b/examples/energest-demo/energest-demo.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2007, Swedish Institute of 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.
+ *
+ * $Id: energest-demo.c,v 1.1 2007/10/25 12:56:28 adamdunkels Exp $
+ */
+
+/**
+ * \file
+ * Contiki application sending estimated energy to a sink node
+ * \author
+ * Zhitao He
+ */
+
+#include "contiki.h"
+#include "net/rime.h"
+#include "net/mac/mac.h"
+#include "net/mac/nullmac.h"
+#include "dev/button-sensor.h"
+
+#include "dev/simple-cc2420.h"
+
+#include "dev/leds.h"
+#include "node-id.h"
+#include
+
+#define SINK_ID 41
+/*---------------------------------------------------------------------------*/
+PROCESS(output_process, "output energest");
+PROCESS(user_process, "user input");
+AUTOSTART_PROCESSES(
+ &output_process,
+ &user_process
+ );
+/*---------------------------------------------------------------------------*/
+static struct abc_conn abc;
+static u16_t read = 0;
+static u16_t send = 0;
+
+int lpm_en;
+static int radio_off;
+static int computing;
+static int sending;
+
+enum states{
+ RADIO_OFF = 1,
+ RADIO_LOW,
+ RADIO_MID,
+ RADIO_FULL,
+ LPM_OFF,
+ SENDING1k,
+ SENDING12k,
+};
+
+struct energy_time {
+ unsigned short source;
+ long cpu;
+ long lpm;
+ long transmit;
+ long listen;
+};
+
+static struct energy_time last;
+static struct energy_time diff;
+
+// FIXME: workaround to turn on/off radio. Rime should export an MAC on/off interface to avoid forcing the user to do this explicitly
+static struct mac_driver *mac = &nullmac_driver;
+
+static clock_time_t sleep_cycles;
+static const char send_string[] = "I am a sending string.";
+static int send_length = 10;
+static int send_amount = 10;
+/*---------------------------------------------------------------------------*/
+static void
+abc_recv(struct abc_conn *c)
+{
+ struct energy_time *incoming= (struct energy_time *)rimebuf_dataptr();
+ read++;
+ if(node_id == SINK_ID) {
+ printf("%i SICS %i %u %li %li %li %li\n", node_id, read,
+ incoming->source, incoming->cpu, incoming->lpm,
+ incoming->transmit, incoming->listen);
+ }
+}
+/*---------------------------------------------------------------------------*/
+const static struct abc_callbacks abc_call = {abc_recv};
+/*---------------------------------------------------------------------------*/
+static void
+do_computing(void)
+{
+ int i;
+ for(i = 0; i < 100; i++) {
+ clock_delay(1000);
+ }
+}
+/*---------------------------------------------------------------------------*/
+static void
+do_sending(void)
+{
+ int i;
+ simple_cc2420_set_chan_pan_addr(11, 0x2024, node_id, NULL);
+ simple_cc2420_set_txpower(1);
+
+ for(i = 0;i < send_amount; i++) {
+ rimebuf_copyfrom(send_string, send_length);
+
+ mac->on();
+ abc_send(&abc);
+ mac->off();
+ }
+ simple_cc2420_set_txpower(31);
+ simple_cc2420_set_chan_pan_addr(RF_CHANNEL, 0x2024, node_id, NULL);
+}
+/*---------------------------------------------------------------------------*/
+PROCESS_THREAD(output_process, ev, data)
+{
+ static struct etimer et, et2;
+
+ PROCESS_EXITHANDLER(abc_close(&abc);)
+
+ PROCESS_BEGIN();
+
+ etimer_set(&et, 5*CLOCK_SECOND);
+ PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
+
+ /* Energy time init */
+ energest_init();
+ last.cpu = energest_type_time(ENERGEST_TYPE_CPU);
+ last.lpm = energest_type_time(ENERGEST_TYPE_LPM);
+ last.transmit = energest_type_time(ENERGEST_TYPE_TRANSMIT);
+ last.listen = energest_type_time(ENERGEST_TYPE_LISTEN);
+
+ abc_open(&abc, 128, &abc_call);
+
+ if (node_id == SINK_ID) {
+ while(1) {
+ PROCESS_YIELD();
+ printf("I'm a sink. I'm doing nothing...");
+ }
+ }
+
+ etimer_set(&et, UPDATE_TICKS);
+
+ while(1) {
+ PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
+
+ if(computing) {
+ do_computing();
+ }
+
+ /* stop-start ongoing time measurements to retrieve the diffs
+ during last interval */
+ ENERGEST_OFF(ENERGEST_TYPE_CPU);
+ ENERGEST_ON(ENERGEST_TYPE_CPU);
+ mac->on();
+ mac->off();
+
+ /* Energy time diff */
+ diff.source = node_id;
+ diff.cpu = energest_type_time(ENERGEST_TYPE_CPU) - last.cpu;
+ diff.lpm = energest_type_time(ENERGEST_TYPE_LPM) - last.lpm;
+ diff.transmit = energest_type_time(ENERGEST_TYPE_TRANSMIT) - last.transmit;
+ diff.listen = energest_type_time(ENERGEST_TYPE_LISTEN) - last.listen;
+ last.cpu = energest_type_time(ENERGEST_TYPE_CPU);
+ last.lpm = energest_type_time(ENERGEST_TYPE_LPM);
+ last.transmit = energest_type_time(ENERGEST_TYPE_TRANSMIT);
+ last.listen = energest_type_time(ENERGEST_TYPE_LISTEN);
+
+ send++;
+/* printf("%i SICS %i %i %li %li %li %li\n", node_id, send, */
+/* diff.source, diff.cpu, diff.lpm, diff.transmit, diff.listen); */
+
+ rimebuf_copyfrom((char*)&diff, sizeof(diff));
+
+ mac->on();
+ abc_send(&abc);
+
+ if(sending) {
+ mac->off();
+ do_sending();
+ } else if(radio_off) {
+ mac->off();
+ } else {
+ mac->off();
+ etimer_set(&et2, sleep_cycles);
+ PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et2));
+ mac->on();
+ }
+
+ etimer_reset(&et);
+ }
+
+ PROCESS_END();
+}
+/*---------------------------------------------------------------------------*/
+static enum states
+next_state(enum states current_state)
+{
+ return current_state == 7 ? current_state = 1 : current_state + 1;
+}
+/*---------------------------------------------------------------------------*/
+static void
+show_state(enum states current_state)
+{
+ printf("state = %d\n", current_state);
+ switch(current_state) {
+ case 1:
+ leds_off(LEDS_BLUE);leds_off(LEDS_GREEN);leds_on(LEDS_RED);
+ break;
+
+ case 2:
+ leds_off(LEDS_BLUE);leds_on(LEDS_GREEN);leds_off(LEDS_RED);
+ break;
+
+ case 3:
+ leds_off(LEDS_BLUE);leds_on(LEDS_GREEN);leds_on(LEDS_RED);
+ break;
+
+ case 4:
+ leds_on(LEDS_BLUE);leds_off(LEDS_GREEN);leds_off(LEDS_RED);
+ break;
+
+ case 5:
+ leds_on(LEDS_BLUE);leds_off(LEDS_GREEN);leds_on(LEDS_RED);
+ break;
+
+ case 6:
+ leds_on(LEDS_BLUE);leds_on(LEDS_GREEN);leds_off(LEDS_RED);
+ break;
+
+ case 7:
+ leds_on(LEDS_BLUE);leds_on(LEDS_GREEN);leds_on(LEDS_RED);
+ break;
+
+ default:
+ printf("unknown state\n");
+ }
+}
+/*---------------------------------------------------------------------------*/
+static void
+run_state(enum states current_state)
+{
+ switch(current_state) {
+ case RADIO_OFF:
+ lpm_en = 1;
+ radio_off = 1;
+ sleep_cycles = 0;
+ computing = 0;
+ sending = 0;
+ break;
+
+ case RADIO_LOW:
+ lpm_en = 1;
+ radio_off = 0;
+ sleep_cycles = UPDATE_TICKS * 99 / 100;
+ computing = 0;
+ sending = 0;
+ break;
+
+ case RADIO_MID:
+ lpm_en = 1;
+ radio_off = 0;
+ sleep_cycles = UPDATE_TICKS * 90 / 100;
+ computing = 0;
+ sending = 0;
+ break;
+
+ case RADIO_FULL:
+ lpm_en = 1;
+ radio_off = 0;
+ sleep_cycles = 0;
+ computing = 0;
+ sending = 0;
+ break;
+
+ case LPM_OFF:
+ lpm_en = 0;
+ radio_off = 0;
+ sleep_cycles = UPDATE_TICKS * 90 / 100;
+ computing = 0;
+ sending = 0;
+ break;
+
+ case SENDING1k:
+ lpm_en = 1;
+ radio_off = 0;
+ sleep_cycles = UPDATE_TICKS * 99 / 100;
+ computing = 0;
+ sending = 1;
+ send_amount = 10;
+ send_length = 100;
+ break;
+
+ case SENDING12k:
+ lpm_en = 1;
+ radio_off = 0;
+ sleep_cycles = UPDATE_TICKS * 90 / 100;
+ computing = 0;
+ sending = 1;
+ send_amount = 100;
+ send_length = 100;
+ break;
+
+ default:
+ ;
+ }
+}
+/*---------------------------------------------------------------------------*/
+PROCESS_THREAD(user_process, ev, data)
+{
+ static enum states state;
+
+ PROCESS_BEGIN();
+
+ printf("Node id %d\n", node_id);
+
+ button_sensor.activate();
+ state = RADIO_OFF;
+
+ while(1) {
+ show_state(state);
+ run_state(state);
+
+ PROCESS_WAIT_EVENT();
+ if(ev == sensors_event && data == &button_sensor) {
+ state = next_state(state);
+ }
+
+ }
+
+ PROCESS_END();
+}
+/*---------------------------------------------------------------------------*/
diff --git a/examples/energest-demo/handouts/demo-handout.ppt b/examples/energest-demo/handouts/demo-handout.ppt
new file mode 100644
index 000000000..e8580f282
Binary files /dev/null and b/examples/energest-demo/handouts/demo-handout.ppt differ
diff --git a/examples/energest-demo/handouts/dunkels07demo.pdf b/examples/energest-demo/handouts/dunkels07demo.pdf
new file mode 100644
index 000000000..49afd40b6
Binary files /dev/null and b/examples/energest-demo/handouts/dunkels07demo.pdf differ
diff --git a/examples/energest-demo/handouts/dunkels07softwarebased.pdf b/examples/energest-demo/handouts/dunkels07softwarebased.pdf
new file mode 100644
index 000000000..563281001
Binary files /dev/null and b/examples/energest-demo/handouts/dunkels07softwarebased.pdf differ
diff --git a/examples/energest-demo/handouts/itea-handout.doc b/examples/energest-demo/handouts/itea-handout.doc
new file mode 100644
index 000000000..777957db5
Binary files /dev/null and b/examples/energest-demo/handouts/itea-handout.doc differ
diff --git a/examples/energest-demo/src/Demo.java b/examples/energest-demo/src/Demo.java
new file mode 100644
index 000000000..71b46825f
--- /dev/null
+++ b/examples/energest-demo/src/Demo.java
@@ -0,0 +1,679 @@
+/*
+ * Copyright (c) 2007, Swedish Institute of 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.
+ *
+ * $Id: Demo.java,v 1.1 2007/10/25 12:56:28 adamdunkels Exp $
+ */
+
+/**
+ * \file
+ * Java program showing energy estimates from a Contiki app
+ * \author
+ * Fredrik Österlind
+ */
+
+import java.awt.GraphicsEnvironment;
+import java.awt.GridLayout;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.awt.image.BufferedImage;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Vector;
+import javax.swing.ImageIcon;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.Timer;
+
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.ValueAxis;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.data.category.DefaultCategoryDataset;
+import org.jfree.data.general.DefaultPieDataset;
+import org.jfree.data.time.Second;
+import org.jfree.data.time.TimeSeries;
+import org.jfree.data.time.TimeSeriesCollection;
+
+public class Demo extends JPanel {
+ public static final boolean REPLAY_TEMP_DATA = false;
+
+ public static final int TOTAL_HEIGHT = 300;
+ public static final int TOTAL_WIDTH = 900;
+
+ public static final String SERIALDUMP_WINDOWS = "../bin/serialdump-windows.exe";
+ public static final String SERIALDUMP_LINUX = ""; /* TODO Add Linux serialdump */
+
+ public static final int HISTORY_MAX_SECONDS = 120;
+
+ public static final int NODE_HEIGHT = 300;
+ public static final int NODE_WIDTH = 450;
+
+ public static final int NUMBER_NODES = 7;
+ public static final int NODE_IDS[] = {42, 43, 44, 45, 46, 47, 48};
+ public static final String CATEGORIES[] = {"LPM", "CPU", "Radio listen", "Radio transmit"};
+
+ public static final int PARSE_NR_COMPONENTS = 8;
+ public static final int PARSE_POS_SINK_ID = 0;
+ public static final int PARSE_POS_SICS_ID = 1;
+ public static final int PARSE_POS_COUNT = 2;
+ public static final int PARSE_POS_SOURCE_ID = 3;
+ public static final int PARSE_POS_TIME_CPU = 4;
+ public static final int PARSE_POS_TIME_LPM = 5;
+ public static final int PARSE_POS_TIME_TRANSMIT = 6;
+ public static final int PARSE_POS_TIME_LISTEN = 7;
+ public static final String PARSE_SICS_ID = "SICS";
+
+ public static final double TICKS_PER_SECOND = 4096; /* TODO Convert from TimerB ticks to seconds */
+ public static final double UPDATE_PERIOD = 1; /* TODO Set update period (1 second?) */
+
+ /* CC2420 has 8.5 (-25dBm), 9.9 (-15dBm), 11 (-10dBm), 14 (-5dBm) and 17.4 (0dBm) */
+ public static final int CHARTS_MAX_MILLIWATTS = 70;
+ public static final double VOLTAGE = 3;
+ public static final double POWER_CPU = 1.800 * VOLTAGE; /* mW */
+ public static final double POWER_LPM = 0.0545 * VOLTAGE; /* mW */
+ public static final double POWER_TRANSMIT = 17.7 * VOLTAGE; /* mW */
+ public static final double POWER_LISTEN = 20.0 * VOLTAGE; /* mW */
+
+ public static final int MA_HISTORY_LENGTH = 40;
+
+ private Process serialDumpProcess;
+
+ private Vector historyLPM = new Vector();
+ private Vector historyCPU = new Vector();
+ private Vector historyListen = new Vector();
+ private Vector historyTransmit = new Vector();
+
+ private int trackedNodeIndex = 0; /* Currently tracked node index */
+
+ private String comPort;
+ private JFrame frame;
+
+ private TimeSeries nodeHistorySerie;
+ private JFreeChart nodeHistoryChart;
+ private JLabel nodeHistoryLabel;
+
+ private JFreeChart relativeChart;
+ private JLabel relativeLabel;
+ private DefaultPieDataset relativeDataset;
+
+ private JFreeChart totalChart;
+ private DefaultCategoryDataset totalDataset;
+ private JLabel totalLabel;
+ private int categoryOrder = 0;
+
+ public Demo(String comPort) {
+ this.comPort = comPort;
+
+ System.out.println("Demo application listening on COM port: " + comPort);
+
+ /* Make sure we have nice window decorations */
+ JFrame.setDefaultLookAndFeelDecorated(true);
+ JDialog.setDefaultLookAndFeelDecorated(true);
+ Rectangle maxSize = GraphicsEnvironment.getLocalGraphicsEnvironment()
+ .getMaximumWindowBounds();
+
+ /* Create and set up the window */
+ frame = new JFrame("Contiki Energy Estimation Demo (ACM SenSys 2007)");
+ if (maxSize != null) {
+ frame.setMaximizedBounds(maxSize);
+ }
+ frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+
+ frame.addWindowListener(new WindowListener() {
+ public void windowDeactivated(WindowEvent e) {
+ }
+
+ public void windowIconified(WindowEvent e) {
+ }
+
+ public void windowDeiconified(WindowEvent e) {
+ }
+
+ public void windowOpened(WindowEvent e) {
+ }
+
+ public void windowClosed(WindowEvent e) {
+ }
+
+ public void windowActivated(WindowEvent e) {
+ }
+
+ public void windowClosing(WindowEvent e) {
+ /* TODO Clean up resources */
+ if (serialDumpProcess != null) {
+ try {
+ serialDumpProcess.destroy();
+ } catch (Exception ex) {
+ System.err.println("Serialdump process exception: " + ex.getMessage());
+ }
+ }
+ System.exit(0);
+ }
+ });
+
+ frame.setContentPane(this);
+
+ /* Create charts */
+ createAllCharts();
+
+ /* Add charts */
+ this.setLayout(new GridLayout(2, 1));
+ JPanel upperPanel = new JPanel(new GridLayout());
+ totalLabel.setAlignmentX(JPanel.CENTER_ALIGNMENT);
+ upperPanel.add(totalLabel);
+ add(upperPanel);
+
+ JPanel lowerPanel = new JPanel(new GridLayout(1, 2));
+ relativeLabel.setAlignmentX(JPanel.CENTER_ALIGNMENT);
+ lowerPanel.add(relativeLabel);
+ nodeHistoryLabel.setAlignmentX(JPanel.CENTER_ALIGNMENT);
+ lowerPanel.add(nodeHistoryLabel);
+ add(lowerPanel);
+
+ /* Display the window */
+ frame.pack();
+ frame.setLocationRelativeTo(null);
+ frame.setVisible(true);
+
+ if (!REPLAY_TEMP_DATA) {
+ connectToCOMPort();
+ }
+ Timer updateTimer = new Timer(500, null);
+ updateTimer.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+// parseIncomingLine(TEMP_NODE_DATA[TEMP_COUNTER]);
+// TEMP_COUNTER = (TEMP_COUNTER + 1) % TEMP_NODE_DATA.length;
+ try {
+ updateCharts();
+ } catch(Exception eeeee) {}
+ }
+ });
+ updateTimer.start();
+
+ if (REPLAY_TEMP_DATA) {
+ // Timer updateTimer = new Timer(1000, null);
+ updateTimer.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ parseIncomingLine(TEMP_NODE_DATA[TEMP_COUNTER]);
+ TEMP_COUNTER = (TEMP_COUNTER + 1) % TEMP_NODE_DATA.length;
+ updateCharts();
+ }
+ });
+ updateTimer.start();
+ }
+ }
+
+ public void connectToCOMPort() {
+ /* Connect to COM using external serialdump application */
+ String osName = System.getProperty("os.name").toLowerCase();
+ String fullCommand;
+ if (osName.startsWith("win")) {
+ fullCommand = SERIALDUMP_WINDOWS + " " + "-b115200" + " " + comPort;
+ } else {
+ fullCommand = SERIALDUMP_LINUX + " " + "-b115200" + " " + comPort;
+ }
+
+ try {
+ String[] cmd = fullCommand.split(" ");
+
+ serialDumpProcess = Runtime.getRuntime().exec(cmd);
+ final BufferedReader input = new BufferedReader(new InputStreamReader(serialDumpProcess.getInputStream()));
+ final BufferedReader err = new BufferedReader(new InputStreamReader(serialDumpProcess.getErrorStream()));
+
+ /* Start thread listening on stdout */
+ Thread readInput = new Thread(new Runnable() {
+ public void run() {
+ String line;
+ try {
+ while ((line = input.readLine()) != null) {
+ parseIncomingLine(line);
+ }
+ input.close();
+ System.out.println("Serialdump process shut down, exiting");
+ System.exit(1);
+ } catch (IOException e) {
+ System.err.println("Exception when reading from serialdump");
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+ }, "read input stream thread");
+
+ /* Start thread listening on stderr */
+ Thread readError = new Thread(new Runnable() {
+ public void run() {
+ String line;
+ try {
+ while ((line = err.readLine()) != null) {
+ System.err.println("Serialdump error stream> " + line);
+ }
+ err.close();
+ } catch (IOException e) {
+ System.err.println("Exception when reading from serialdump");
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+ }, "read error stream thread");
+
+ readInput.start();
+ readError.start();
+
+ } catch (Exception e) {
+ System.err.println("Exception when executing '" + fullCommand + "'");
+ System.err.println("Exiting demo application");
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ public void createAllCharts() {
+ BufferedImage image;
+
+ /* Create total power history chart for tracked node */
+ nodeHistoryLabel = new JLabel();
+ createHistoryChartForNode(nodeHistoryLabel, trackedNodeIndex);
+
+ /* Create moving average relative power distribution chart */
+ relativeDataset = new DefaultPieDataset();
+ for (String category: CATEGORIES) {
+ relativeDataset.setValue(category, 0);
+ }
+ relativeChart = ChartFactory.createPieChart("Moving Average: Relative power distribution", relativeDataset, false, false, false);
+ image = relativeChart.createBufferedImage(NODE_WIDTH,NODE_HEIGHT);
+ relativeLabel = new JLabel();
+ relativeLabel.setIcon(new ImageIcon(image));
+
+ /* Create chart with power of all nodes */
+ totalDataset = new DefaultCategoryDataset();
+ for (int i=0; i < NUMBER_NODES; i++) {
+ for (String category: CATEGORIES) {
+ totalDataset.addValue(0, category, getNodeNameFromIndex(i));
+ }
+ }
+ totalChart = ChartFactory.createStackedBarChart(null, null, "Power usage (mW)", totalDataset, PlotOrientation.VERTICAL, true, true, true);
+ ValueAxis rangeAxis = totalChart.getCategoryPlot().getRangeAxis();
+ // rangeAxis.setRange(0, CHARTS_MAX_MILLIWATTS);
+
+ image = totalChart.createBufferedImage(TOTAL_WIDTH,TOTAL_HEIGHT);
+ totalLabel = new JLabel();
+ totalLabel.setIcon(new ImageIcon(image));
+
+ MouseListener categoryChangeListener = new MouseListener() {
+ public void mouseClicked(MouseEvent e) {
+ System.out.println("Toggling category order");
+
+ categoryOrder++;
+ totalDataset.clear();
+ for (int i=0; i < NUMBER_NODES; i++) {
+ for (int j=0; j < CATEGORIES.length; j++) {
+ totalDataset.addValue(0, CATEGORIES[(j + categoryOrder) % CATEGORIES.length], getNodeNameFromIndex(i));
+ }
+ }
+ totalChart = ChartFactory.createStackedBarChart(null, null, "Power usage (mW)", totalDataset, PlotOrientation.VERTICAL, true, true, true);
+ ValueAxis rangeAxis = totalChart.getCategoryPlot().getRangeAxis();
+// rangeAxis.setRange(0, CHARTS_MAX_MILLIWATTS);
+
+ relativeDataset.clear();
+ for (int i=0; i < NUMBER_NODES; i++) {
+ for (int j=0; j < CATEGORIES.length; j++) {
+ relativeDataset.setValue(CATEGORIES[(j + categoryOrder) % CATEGORIES.length], 0.00001);
+ }
+ }
+ relativeChart = ChartFactory.createPieChart("Moving Average: Relative power distribution", relativeDataset, false, false, false);
+
+ updateCharts();
+ }
+ public void mousePressed(MouseEvent e) {
+ }
+ public void mouseReleased(MouseEvent e) {
+ }
+ public void mouseEntered(MouseEvent e) {
+ }
+ public void mouseExited(MouseEvent e) {
+ }
+ };
+ totalLabel.addMouseListener(categoryChangeListener);
+ relativeLabel.addMouseListener(categoryChangeListener);
+
+ MouseListener toggleTrackedListener = new MouseListener() {
+ public void mouseClicked(MouseEvent e) {
+ trackedNodeIndex = (trackedNodeIndex + 1) % NODE_IDS.length;
+ System.out.println("Tracking " + getNodeNameFromIndex(trackedNodeIndex));
+
+ createHistoryChartForNode(nodeHistoryLabel, trackedNodeIndex);
+
+ updateCharts();
+ }
+ public void mousePressed(MouseEvent e) {
+ }
+ public void mouseReleased(MouseEvent e) {
+ }
+ public void mouseEntered(MouseEvent e) {
+ }
+ public void mouseExited(MouseEvent e) {
+ }
+ };
+ nodeHistoryLabel.addMouseListener(toggleTrackedListener);
+ }
+
+ public void createHistoryChartForNode(JLabel label, int index) {
+ BufferedImage image;
+
+ /* Create history */
+ nodeHistorySerie = new TimeSeries("", Second.class);
+ nodeHistorySerie.removeAgedItems(true);
+ nodeHistorySerie.setMaximumItemCount(HISTORY_MAX_SECONDS);
+ TimeSeriesCollection historyData = new TimeSeriesCollection(nodeHistorySerie);
+ nodeHistoryChart = ChartFactory.createTimeSeriesChart(getNodeNameFromIndex(index) + ": Total power usage (mW)", null, null, historyData, false, false, false);
+ ValueAxis rangeAxis = nodeHistoryChart.getXYPlot().getRangeAxis();
+ rangeAxis.setRange(0, CHARTS_MAX_MILLIWATTS);
+ image = nodeHistoryChart.createBufferedImage(NODE_WIDTH,NODE_HEIGHT);
+ label.setIcon(new ImageIcon(image));
+ }
+
+ public void addHistoryPower(double newPower) {
+ if (nodeHistorySerie != null) {
+ nodeHistorySerie.addOrUpdate(new Second(), newPower);
+ }
+ }
+
+ public void updateTotalPower(String category, String nodeName, double newValue) {
+ if (totalDataset != null) {
+ totalDataset.addValue(newValue, category, nodeName);
+ }
+ }
+
+ public void updateTotalPowers(String nodeName, double lpm, double cpu, double listen, double transmit) {
+ updateTotalPower(CATEGORIES[0], nodeName, lpm);
+ updateTotalPower(CATEGORIES[1], nodeName, cpu);
+ updateTotalPower(CATEGORIES[2], nodeName, listen);
+ updateTotalPower(CATEGORIES[3], nodeName, transmit);
+ }
+
+ public void setRelativePower(String category, double newVal) {
+ if (relativeDataset != null) {
+ relativeDataset.setValue(category, newVal);
+ }
+ }
+
+ public void setRelativePowers(double lpm, double cpu, double listen, double transmit) {
+ setRelativePower(CATEGORIES[0], lpm);
+ setRelativePower(CATEGORIES[1], cpu);
+ setRelativePower(CATEGORIES[2], listen);
+ setRelativePower(CATEGORIES[3], transmit);
+ }
+
+ public void updateMARelativePowers(double lpm, double cpu, double listen, double transmit) {
+ /* Add new values */
+ historyLPM.add(lpm);
+ historyCPU.add(cpu);
+ historyListen.add(listen);
+ historyTransmit.add(transmit);
+
+ /* Remove old values (if any) */
+ if (historyLPM.size() > MA_HISTORY_LENGTH) {
+ historyLPM.remove(0);
+ }
+ if (historyCPU.size() > MA_HISTORY_LENGTH) {
+ historyCPU.remove(0);
+ }
+ if (historyListen.size() > MA_HISTORY_LENGTH) {
+ historyListen.remove(0);
+ }
+ if (historyTransmit.size() > MA_HISTORY_LENGTH) {
+ historyTransmit.remove(0);
+ }
+
+ /* Calculate average */
+ double lpmMA = 0;
+ for (double power: historyLPM) {
+ lpmMA += power;
+ }
+ lpmMA /= historyLPM.size();
+
+ double cpuMA = 0;
+ for (double power: historyCPU) {
+ cpuMA += power;
+ }
+ cpuMA /= historyCPU.size();
+
+ double transmitMA = 0;
+ for (double power: historyTransmit) {
+ transmitMA += power;
+ }
+ transmitMA /= historyTransmit.size();
+
+ double listenMA = 0;
+ for (double power: historyListen) {
+ listenMA += power;
+ }
+ listenMA /= historyListen.size();
+
+ setRelativePowers(lpmMA, cpuMA, listenMA, transmitMA);
+ }
+
+
+ public void parseIncomingLine(String line) {
+ if (line == null) {
+ System.err.println("Parsing null line");
+ return;
+ }
+
+ /* Split line into components */
+ String[] components = line.split(" ");
+ if (components.length != PARSE_NR_COMPONENTS) {
+ System.err.println("Parsing wrong components count (" + components.length + "): '" + line + "'");
+ return;
+ }
+
+ /* Parse source and components times */
+ int sinkNodeID=-1, sourceNodeID=-1, timeCPU=-1, timeLPM=-1, timeTransmit=-1, timeListen=-1;
+ try {
+ sinkNodeID = Integer.parseInt(components[PARSE_POS_SINK_ID]);
+ if (!components[PARSE_POS_SICS_ID].equals(PARSE_SICS_ID)) {
+ throw new Exception("Parsing non-demo data: '" + line + "'");
+ }
+ /*Integer.parseInt(components[PARSE_POS_COUNT]);*/
+ sourceNodeID = Integer.parseInt(components[PARSE_POS_SOURCE_ID]);
+ timeCPU = Integer.parseInt(components[PARSE_POS_TIME_CPU]);
+ timeLPM = Integer.parseInt(components[PARSE_POS_TIME_LPM]);
+ timeTransmit = Integer.parseInt(components[PARSE_POS_TIME_TRANSMIT]);
+ /* TODO Too big transmit time? */
+ timeListen = Integer.parseInt(components[PARSE_POS_TIME_LISTEN]);
+ } catch (Exception e) {
+ System.err.println(e.getMessage());
+ return;
+ }
+
+ /* Validate parsed values */
+ String nodeName = getNodeNameFromId(sourceNodeID);
+ if (nodeName == null) {
+ System.err.println("No registered node with ID " + sourceNodeID + ": '" + line + "'");
+ return;
+ }
+ if (timeCPU < 0) {
+ System.err.println("Parsed negative CPU time (" + timeCPU + "): '" + line + "'");
+ return;
+ }
+ if (timeLPM < 0) {
+ System.err.println("Parsed negative LPM time (" + timeLPM + "): '" + line + "'");
+ return;
+ }
+ if (timeTransmit < 0) {
+ System.err.println("Parsed negative transmit time (" + timeTransmit + "): '" + line + "'");
+ return;
+ }
+ if (timeListen < 0) {
+ System.err.println("Parsed negative listen time (" + timeListen + "): '" + line + "'");
+ return;
+ }
+
+ /* Calculate component specific powers using parsed times */
+ double powerCPU = (timeCPU / TICKS_PER_SECOND) * POWER_CPU / UPDATE_PERIOD;
+ double powerLPM = (timeLPM / TICKS_PER_SECOND)* POWER_LPM / UPDATE_PERIOD;
+ double powerTransmit = (timeTransmit / TICKS_PER_SECOND)* POWER_TRANSMIT / UPDATE_PERIOD;
+ double powerListen = (timeListen / TICKS_PER_SECOND) * POWER_LISTEN / UPDATE_PERIOD;
+
+ /* Update node history */
+ if (getNodeNameFromId(sourceNodeID).equals(getNodeNameFromIndex(trackedNodeIndex))) {
+ System.out.println("Parsed data from tracked " + nodeName);
+ addHistoryPower(powerCPU + powerLPM + powerTransmit + powerListen);
+ } else {
+ System.out.println("Parsed data from " + nodeName);
+ }
+
+ updateMARelativePowers(powerLPM, powerCPU, powerListen, powerTransmit);
+
+ updateTotalPowers(nodeName, powerLPM, powerCPU, powerListen, powerTransmit);
+
+ // updateCharts();
+ }
+
+
+ public void updateCharts() {
+ BufferedImage image;
+
+ /* Recreate all label icons */
+ /* TODO Only update changed charts: i */
+ if (relativeLabel != null) {
+ image = relativeChart.createBufferedImage(NODE_WIDTH,NODE_HEIGHT);
+ relativeLabel.setIcon(new ImageIcon(image));
+ }
+ if (nodeHistoryLabel != null) {
+ image = nodeHistoryChart.createBufferedImage(NODE_WIDTH,NODE_HEIGHT);
+ nodeHistoryLabel.setIcon(new ImageIcon(image));
+ }
+ if (totalLabel != null) {
+ image = totalChart.createBufferedImage(TOTAL_WIDTH,TOTAL_HEIGHT);
+ totalLabel.setIcon(new ImageIcon(image));
+ }
+
+ repaint();
+ }
+
+
+ public String getNodeNameFromIndex(int index) {
+ return "Node " + NODE_IDS[index];
+ }
+
+ public static String getNodeNameFromId(int id) {
+ boolean exists = false;
+ for (int existingID: NODE_IDS) {
+ if (existingID == id) {
+ exists = true;
+ break;
+ }
+ }
+
+ if (!exists) {
+ System.err.println("Node " + id + " is not registered!");
+ return null;
+ }
+ return "Node " + id;
+ }
+
+
+ public static void main(final String[] args) {
+ if (args.length != 1) {
+ System.err.println("Usage: java Demo COMPORT [TRACK_NODE_ID]");
+ return;
+ }
+
+ final String comPort = args[0];
+
+ javax.swing.SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ new Demo(comPort);
+ }
+ });
+ }
+
+ /* TEMPORARY DATA */
+ int TEMP_COUNTER = 0;
+ String[] TEMP_NODE_DATA = {
+ "33 S 1 33 3 0 4093 0",
+ "33 R 1 34 44 0 4052 0",
+ "33 S 2 33 77 0 4019 0",
+ "33 S 3 33 39 0 4057 0",
+ "33 R 2 34 39 0 4057 0",
+ "33 S 4 33 78 0 4018 0",
+ "33 R 3 34 80 0 4016 0",
+ "33 S 5 33 83 0 4013 0",
+ "33 R 4 34 80 0 4015 0",
+ "33 S 6 33 90 0 4006 0",
+ "33 S 7 33 40 0 4056 0",
+ "33 R 5 34 87 0 4009 0",
+ "33 S 8 33 80 0 4016 0",
+ "33 R 6 34 130 0 3965 0",
+ "33 S 9 33 81 0 4015 0",
+ "33 S 10 33 39 0 4057 0",
+ "33 R 7 34 87 0 4009 0",
+ "33 S 11 33 89 0 4007 0",
+ "33 R 8 34 94 0 4002 0",
+ "33 S 12 33 89 0 4007 0",
+ "33 R 9 34 47 0 4049 0",
+ "33 S 13 33 83 0 4013 0",
+ "33 R 10 34 82 0 4014 0",
+ "33 S 14 33 90 0 4006 0",
+ "33 R 11 34 94 0 3999 0",
+ "33 S 15 33 92 0 4004 0",
+ "33 S 16 33 46 0 4050 0",
+ "33 R 12 34 132 0 3964 0",
+ "33 R 13 34 46 0 4050 0",
+ "33 S 17 33 140 0 3956 0",
+ "33 R 14 34 86 0 4009 0",
+ "33 S 18 33 85 0 4010 0",
+ "33 R 15 34 94 0 4002 0",
+ "33 S 19 33 83 0 4013 0",
+ "33 S 20 33 41 0 4055 0",
+ "33 R 16 34 41 0 4055 0",
+ "33 S 21 33 86 0 4009 0",
+ "33 R 17 34 86 0 4010 0",
+ "33 R 18 34 84 0 4012 0",
+ "33 S 22 33 127 0 3969 0",
+ "33 R 19 34 84 0 4012 0",
+ "33 S 23 33 85 0 4011 0",
+ "33 S 24 33 44 0 4052 0",
+ "33 R 20 34 41 0 4055 0",
+ "33 S 25 33 86 0 4010 0",
+ "33 S 26 33 47 0 4048 0",
+ "33 R 21 34 94 0 4000 0",
+ "33 S 27 33 89 0 4004 0"
+ };
+}