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" + }; +}