Merge branch 'master' of ssh://contiki.git.sourceforge.net/gitroot/contiki/contiki

This commit is contained in:
Matthias Kovatsch 2012-03-21 21:51:03 +01:00
commit d716ee55e7
27 changed files with 1809 additions and 1751 deletions

View file

@ -543,7 +543,7 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr, struct rdc_buf_
PRINTF("contikimac: radio is turned off\n");
return MAC_TX_ERR_FATAL;
}
if(packetbuf_totlen() == 0) {
PRINTF("contikimac: send_packet data len 0\n");
return MAC_TX_ERR_FATAL;
@ -723,7 +723,7 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr, struct rdc_buf_
watchdog_periodic();
t0 = RTIMER_NOW();
seqno = packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO);
previous_txtime = RTIMER_NOW();
for(strobes = 0, collisions = 0;
got_strobe_ack == 0 && collisions == 0 &&
RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + STROBE_TIME); strobes++) {
@ -737,7 +737,7 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr, struct rdc_buf_
len = 0;
previous_txtime = RTIMER_NOW();
{
rtimer_clock_t wt;
rtimer_clock_t txtime;

View file

@ -781,6 +781,7 @@ input_packet(void)
{
struct lpp_hdr hdr;
clock_time_t reception_time;
int ret;
reception_time = clock_time();
@ -845,7 +846,7 @@ input_packet(void)
if(i->broadcast_flag == BROADCAST_FLAG_NONE ||
i->broadcast_flag == BROADCAST_FLAG_SEND) {
i->num_transmissions = 1;
NETSTACK_RADIO.send(queuebuf_dataptr(i->packet),
ret = NETSTACK_RADIO.send(queuebuf_dataptr(i->packet),
queuebuf_datalen(i->packet));
sent = 1;
PRINTF("%d.%d: got a probe from %d.%d, sent packet to %d.%d\n",
@ -860,7 +861,7 @@ input_packet(void)
}
#else /* WITH_PENDING_BROADCAST */
i->num_transmissions = 1;
NETSTACK_RADIO.send(queuebuf_dataptr(i->packet),
ret = NETSTACK_RADIO.send(queuebuf_dataptr(i->packet),
queuebuf_datalen(i->packet));
PRINTF("%d.%d: got a probe from %d.%d, sent packet to %d.%d\n",
rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
@ -879,12 +880,23 @@ input_packet(void)
neighbors, and are dequeued by the dutycycling function
instead, after the appropriate time. */
if(!rimeaddr_cmp(receiver, &rimeaddr_null)) {
#if RDC_CONF_HARDWARE_ACK
if(ret == RADIO_TX_OK) {
remove_queued_packet(i, 1);
} else {
remove_queued_packet(i, 0);
}
#else
if(detect_ack()) {
remove_queued_packet(i, 1);
} else {
remove_queued_packet(i, 0);
}
#endif /* RDC_CONF_HARDWARE_ACK */
#if WITH_PROBE_AFTER_TRANSMISSION
/* Send a probe packet to catch any reply from the other node. */
restart_dutycycle(PROBE_AFTER_TRANSMISSION_TIME);

View file

@ -454,6 +454,7 @@ send_packet(void)
rtimer_clock_t t;
rtimer_clock_t encounter_time = 0;
int strobes;
int ret;
#if 0
struct xmac_hdr *hdr;
#endif
@ -640,11 +641,11 @@ send_packet(void)
if(is_broadcast) {
#if WITH_STROBE_BROADCAST
NETSTACK_RADIO.send(strobe, strobe_len);
ret = NETSTACK_RADIO.send(strobe, strobe_len);
#else
/* restore the packet to send */
queuebuf_to_packetbuf(packet);
NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
ret = NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
#endif
off();
} else {
@ -652,7 +653,7 @@ send_packet(void)
rtimer_clock_t wt;
#endif
on();
NETSTACK_RADIO.send(strobe, strobe_len);
ret = NETSTACK_RADIO.send(strobe, strobe_len);
#if 0
/* Turn off the radio for a while to let the other side
respond. We don't need to keep our radio on when we know
@ -661,12 +662,20 @@ send_packet(void)
wt = RTIMER_NOW();
while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + WAIT_TIME_BEFORE_STROBE_ACK));
#endif /* 0 */
#if RDC_CONF_HARDWARE_ACK
if(ret == RADIO_TX_OK) {
got_strobe_ack = 1;
} else {
off();
}
#else
if(detect_ack()) {
got_strobe_ack = 1;
} else {
off();
}
#endif /* RDC_CONF_HARDWARE_ACK */
}
}
}
@ -693,12 +702,18 @@ send_packet(void)
/* Send the data packet. */
if((is_broadcast || got_strobe_ack || is_streaming) && collisions == 0) {
NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
ret = NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
if(!is_broadcast) {
#if RDC_CONF_HARDWARE_ACK
if(ret == RADIO_TX_OK) {
got_ack = 1;
}
#else
if(detect_ack()) {
got_ack = 1;
}
#endif /* RDC_CONF_HARDWARE_ACK */
}
}
off();

View file

@ -37,6 +37,8 @@
* Machine dependent STM32W radio code.
* \author
* Salvatore Pitrulli
* Chi-Anh La la@imag.fr
* Simon Duquennoy <simonduq@sics.se>
*/
/*---------------------------------------------------------------------------*/
@ -53,13 +55,26 @@
#include "net/packetbuf.h"
#include "net/rime/rimestats.h"
#include "sys/rtimer.h"
#define DEBUG 0
#include "dev/leds.h"
#define LED_ACTIVITY 0
#ifdef ST_CONF_RADIO_AUTOACK
#define ST_RADIO_AUTOACK ST_CONF_RADIO_AUTOACK
#else
#define ST_RADIO_AUTOACK 0
#endif /* ST_CONF_RADIO_AUTOACK */
#if RDC_CONF_DEBUG_LED
#define LED_RDC RDC_CONF_DEBUG_LED
#define LED_ACTIVITY 1
#else
#define LED_RDC 0
#endif
#if DEBUG > 0
#include <stdio.h>
@ -71,13 +86,37 @@
#if LED_ACTIVITY
#define LED_TX_ON() leds_on(LEDS_GREEN)
#define LED_TX_OFF() leds_off(LEDS_GREEN)
#define LED_RX_ON() leds_on(LEDS_RED)
#define LED_RX_OFF() leds_off(LEDS_RED)
#define LED_RX_ON() { \
if(LED_RDC == 0){ \
leds_on(LEDS_RED); \
} \
}
#define LED_RX_OFF() { \
if(LED_RDC == 0){ \
leds_off(LEDS_RED); \
} \
}
#define LED_RDC_ON() { \
if(LED_RDC == 1){ \
leds_on(LEDS_RED); \
} \
}
#define LED_RDC_OFF() { \
if(LED_RDC == 1){ \
leds_off(LEDS_RED); \
} \
}
#else
#define LED_TX_ON()
#define LED_TX_OFF()
#define LED_RX_ON()
#define LED_RX_OFF()
#define LED_RDC_ON()
#define LED_RDC_OFF()
#endif
#if RDC_CONF_HARDWARE_CSMA
#define MAC_RETRIES 0
#endif
#ifndef MAC_RETRIES
@ -113,16 +152,28 @@
ENERGEST_OFF(ENERGEST_TYPE_LISTEN); \
} \
}
#if RDC_CONF_HARDWARE_CSMA
#define ST_RADIO_CHECK_CCA FALSE
#define ST_RADIO_CCA_ATTEMPT_MAX 0
#define ST_BACKOFF_EXP_MIN 0
#define ST_BACKOFF_EXP_MAX 0
#else
#define ST_RADIO_CHECK_CCA TRUE
#define ST_RADIO_CCA_ATTEMPT_MAX 4
#define ST_BACKOFF_EXP_MIN 2
#define ST_BACKOFF_EXP_MAX 6
#endif
const RadioTransmitConfig radioTransmitConfig = {
TRUE, // waitForAck;
TRUE, // checkCca; // Set to FALSE with low-power MACs.
4, // ccaAttemptMax;
2, // backoffExponentMin;
6, // backoffExponentMax;
TRUE // appendCrc;
TRUE, // waitForAck;
ST_RADIO_CHECK_CCA, // checkCca; // Set to FALSE with low-power MACs.
ST_RADIO_CCA_ATTEMPT_MAX, // ccaAttemptMax;
ST_BACKOFF_EXP_MIN, // backoffExponentMin;
ST_BACKOFF_EXP_MAX, // backoffExponentMax;
TRUE // appendCrc;
};
#define MAC_RETRIES 0
/*
* The buffers which hold incoming data.
*/
@ -173,6 +224,20 @@ static uint8_t receiving_packet = 0;
static s8 last_rssi;
static volatile StStatus last_tx_status;
#define BUSYWAIT_UNTIL(cond, max_time) \
do { \
rtimer_clock_t t0; \
t0 = RTIMER_NOW(); \
while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))); \
} while(0)
static uint8_t locked;
#define GET_LOCK() locked++
static void RELEASE_LOCK(void) {
if(locked>0)
locked--;
}
static volatile uint8_t is_transmit_ack;
/*---------------------------------------------------------------------------*/
PROCESS(stm32w_radio_process, "STM32W radio driver");
/*---------------------------------------------------------------------------*/
@ -208,20 +273,26 @@ const struct radio_driver stm32w_radio_driver =
/*---------------------------------------------------------------------------*/
static int stm32w_radio_init(void)
{
// A channel needs also to be setted.
ST_RadioSetChannel(RF_CHANNEL);
// Initialize radio (analog section, digital baseband and MAC).
// Leave radio powered up in non-promiscuous rx mode.
ST_RadioInit(ST_RADIO_POWER_MODE_OFF);
onoroff = OFF;
ST_RadioSetNodeId(STM32W_NODE_ID); // To be deleted.
ST_RadioSetPanId(IEEE802154_PANID);
CLEAN_RXBUFS();
CLEAN_TXBUF();
#if ST_RADIO_AUTOACK && !(UIP_CONF_LL_802154 && RIMEADDR_CONF_SIZE==8)
#error "Autoack and address filtering can only be used with EUI 64"
#endif
ST_RadioEnableAutoAck(ST_RADIO_AUTOACK);
ST_RadioEnableAddressFiltering(ST_RADIO_AUTOACK);
locked = 0;
process_start(&stm32w_radio_process, NULL);
return 0;
@ -290,7 +361,11 @@ static int stm32w_radio_transmit(unsigned short payload_len)
ST_RadioWake();
ENERGEST_ON(ENERGEST_TYPE_LISTEN);
}
#if RADIO_WAIT_FOR_PACKET_SENT
GET_LOCK();
#endif /* RADIO_WAIT_FOR_PACKET_SENT */
last_tx_status = -1;
LED_TX_ON();
if(ST_RadioTransmit(stm32w_txbuf)==ST_SUCCESS){
@ -312,14 +387,21 @@ static int stm32w_radio_transmit(unsigned short payload_len)
PRINTF("stm32w: unknown tx error.\r\n");
TO_PREV_STATE();
LED_TX_OFF();
RELEASE_LOCK();
return RADIO_TX_ERR;
}
TO_PREV_STATE();
if(last_tx_status == ST_SUCCESS || last_tx_status == ST_PHY_ACK_RECEIVED){
return RADIO_TX_OK;
if(last_tx_status == ST_SUCCESS || last_tx_status == ST_PHY_ACK_RECEIVED || last_tx_status == ST_MAC_NO_ACK_RECEIVED){
RELEASE_LOCK();
if(last_tx_status == ST_PHY_ACK_RECEIVED){
return RADIO_TX_OK; /* ACK status */
}
else if (last_tx_status == ST_MAC_NO_ACK_RECEIVED || last_tx_status == ST_SUCCESS){
return RADIO_TX_NOACK;
}
}
LED_TX_OFF();
LED_TX_OFF();
RELEASE_LOCK();
return RADIO_TX_ERR;
#else /* RADIO_WAIT_FOR_PACKET_SENT */
@ -331,7 +413,10 @@ static int stm32w_radio_transmit(unsigned short payload_len)
#endif /* RADIO_WAIT_FOR_PACKET_SENT */
}
#if RADIO_WAIT_FOR_PACKET_SENT
RELEASE_LOCK();
#endif /* RADIO_WAIT_FOR_PACKET_SENT */
TO_PREV_STATE();
PRINTF("stm32w: transmission never started.\r\n");
@ -372,7 +457,14 @@ static int stm32w_radio_off(void)
/* Any transmit or receive packets in progress are aborted.
* Waiting for end of transmission or reception have to be done.
*/
if(onoroff == ON){
if(locked)
{
PRINTF("stm32w: try to off while sending/receiving (lock=%u).\r\n", locked);
return 0;
}
/* off only if there is no transmission or reception of packet. */
if(onoroff == ON && TXBUF_EMPTY() && !receiving_packet){
LED_RDC_OFF();
ST_RadioSleep();
onoroff = OFF;
CLEAN_TXBUF();
@ -386,7 +478,9 @@ static int stm32w_radio_off(void)
/*---------------------------------------------------------------------------*/
static int stm32w_radio_on(void)
{
PRINTF("stm32w: turn radio on\n");
if(onoroff == OFF){
LED_RDC_ON();
ST_RadioWake();
onoroff = ON;
@ -410,6 +504,7 @@ void ST_RadioReceiveIsrCallback(u8 *packet,
s8 rssi)
{
LED_RX_ON();
PRINTF("stm32w: incomming packet received\n");
receiving_packet = 0;
/* Copy packet into the buffer. It is better to do this here. */
if(add_to_rxbuf(packet)){
@ -417,6 +512,21 @@ void ST_RadioReceiveIsrCallback(u8 *packet,
last_rssi = rssi;
}
LED_RX_OFF();
GET_LOCK();
is_transmit_ack = 1;
/* Wait for sending ACK */
BUSYWAIT_UNTIL(!is_transmit_ack, RTIMER_SECOND / 1500);
RELEASE_LOCK();
}
void ST_RadioTxAckIsrCallback (void)
{
/* This callback is for simplemac 1.1.0.
Till now we block (RTIMER_SECOND / 1500)
to prevent radio off during ACK transmission */
is_transmit_ack = 0;
//RELEASE_LOCK();
}
@ -461,19 +571,19 @@ void ST_RadioTransmitCompleteIsrCallback(StStatus status,
/* Debug outputs. */
if(status == ST_SUCCESS || status == ST_PHY_ACK_RECEIVED){
PRINTF("TX_END");
PRINTF("stm32w: return status TX_END\r\n");
}
else if (status == ST_MAC_NO_ACK_RECEIVED){
PRINTF("TX_END_NOACK!!!");
PRINTF("stm32w: return status TX_END_NOACK\r\n");
}
else if (status == ST_PHY_TX_CCA_FAIL){
PRINTF("TX_END_CCA!!!");
PRINTF("stm32w: return status TX_END_CCA_FAIL\r\n");
}
else if(status == ST_PHY_TX_UNDERFLOW){
PRINTF("TX_END_UFL!!!");
PRINTF("stm32w: return status TX_END_UNDERFLOW\r\n");
}
else {
PRINTF("TX_END_INCOMPL!!!");
PRINTF("stm32w: return status TX_END_INCOMPLETE\r\n");
}
}
@ -533,7 +643,7 @@ static int stm32w_radio_read(void *buf, unsigned short bufsize)
/*---------------------------------------------------------------------------*/
void ST_RadioOverflowIsrCallback(void)
{
PRINTF("OVERFLOW\r\n");
PRINTF("stm32w: radio overflow\r\n");
}
/*---------------------------------------------------------------------------*/
void ST_RadioSfdSentIsrCallback(u32 sfdSentTime)

View file

@ -46,8 +46,12 @@
#include "sys/clock.h"
//#define RT_RESOLUTION RES_85US
#ifdef RT_CONF_RESOLUTION
#define RT_RESOLUTION RT_CONF_RESOLUTION
#else
#define RT_RESOLUTION RES_171US
#endif
#define RES_341US 0
#define RES_171US 1

View file

@ -37,130 +37,113 @@
* contiki-conf.h for MB851.
* \author
* Salvatore Pitrulli <salvopitru@users.sourceforge.net>
* Chi-Anh La <la@imag.fr>
* Simon Duquennoy <simonduq@sics.se>
*/
/*---------------------------------------------------------------------------*/
#ifndef __CONTIKI_CONF_H__
#define __CONTIKI_CONF_H__
#include PLATFORM_HEADER
#ifdef PLATFORM_CONF_H
#include PLATFORM_CONF_H
#else
#include "platform-conf.h"
#endif /* PLATFORM_CONF_H */
#include <inttypes.h>
#include <string.h> // For memcpm().
/* Radio and 802.15.4 params */
/* 802.15.4 radio channel */
#define RF_CHANNEL 16
/* 802.15.4 PAN ID */
#define IEEE802154_CONF_PANID 0x1234
/* Use EID 64, enable hardware autoack and address filtering */
#define RIMEADDR_CONF_SIZE 8
#define UIP_CONF_LL_802154 1
#define ST_CONF_RADIO_AUTOACK 1
/* Number of buffers for incoming frames */
#define RADIO_RXBUFS 2
/* Set to 0 for non ethernet links */
#define UIP_CONF_LLH_LEN 0
#define CC_CONF_REGISTER_ARGS 0
#define CC_CONF_FUNCTION_POINTER_ARGS 1
#define CC_CONF_FASTCALL
#define CC_CONF_VA_ARGS 1
#define CC_CONF_INLINE inline
/* RDC params */
/* TX routine passes the cca/ack result in the return parameter */
#define RDC_CONF_HARDWARE_ACK 1
/* TX routine does automatic cca and optional backoff */
#define RDC_CONF_HARDWARE_CSMA 0
/* RDC debug with LED */
#define RDC_CONF_DEBUG_LED 1
/* Channel check rate (per second) */
#define NETSTACK_CONF_RDC_CHANNEL_CHECK_RATE 8
/* Use ACK for optimization (LPP, XMAC) */
#define WITH_ACK_OPTIMIZATION 0
#define CCIF
#define CLIF
/* Netstack config */
#define NETSTACK_CONF_MAC csma_driver
#define NETSTACK_CONF_RDC contikimac_driver
#define NETSTACK_CONF_FRAMER framer_802154
#define NETSTACK_CONF_RADIO stm32w_radio_driver
/* These names are deprecated, use C99 names. */
typedef uint8_t u8_t;
typedef uint16_t u16_t;
typedef uint32_t u32_t;
typedef int32_t s32_t;
/* ContikiMAC config */
#define CONTIKIMAC_CONF_COMPOWER 1
#define CONTIKIMAC_CONF_BROADCAST_RATE_LIMIT 0
#define CONTIKIMAC_CONF_ANNOUNCEMENTS 0
typedef unsigned short uip_stats_t;
/* CXMAC config */
#define CXMAC_CONF_ANNOUNCEMENTS 0
#define CXMAC_CONF_COMPOWER 1
/* XMAC config */
#define XMAC_CONF_ANNOUNCEMENTS 0
#define XMAC_CONF_COMPOWER 1
//#define FIXED_NET_ADDRESS 1
//#define NET_ADDR_A 0x2001
//#define NET_ADDR_B 0xdb8
//#define NET_ADDR_C 0xbbbb
//#define NET_ADDR_D 0xabcd
/* Other */
#define ENERGEST_CONF_ON 0
#define QUEUEBUF_CONF_NUM 2
#define UART1_CONF_TX_WITH_INTERRUPT 0
#define WITH_SERIAL_LINE_INPUT 1
#define ENERGEST_CONF_ON 0
#define TELNETD_CONF_NUMLINES 6
#if WITH_UIP6
#define QUEUEBUF_CONF_NUM 2
/* Network setup for IPv6 */
#define NETSTACK_CONF_NETWORK sicslowpan_driver
/* Specify a minimum packet size for 6lowpan compression to be
enabled. This is needed for ContikiMAC, which needs packets to be
larger than a specified size, if no ContikiMAC header should be
used. */
#define SICSLOWPAN_CONF_COMPRESSION_THRESHOLD 63
#define CONTIKIMAC_CONF_WITH_CONTIKIMAC_HEADER 0
#define NETSTACK_CONF_RADIO stm32w_radio_driver
#define UIP_CONF_ROUTER 1
#define UIP_CONF_IPV6_RPL 1
#define UIP_CONF_ND6_SEND_RA 0
#if WITH_UIP6
#define UIP_CONF_IPV6 1
#define UIP_CONF_IPV6_QUEUE_PKT 0
#define UIP_CONF_IPV6_CHECKS 1
#define UIP_CONF_IPV6_REASSEMBLY 0
#define UIP_CONF_ND6_MAX_PREFIXES 2
#define UIP_CONF_ND6_MAX_NEIGHBORS 2
#define UIP_CONF_ND6_MAX_DEFROUTERS 1
#define UIP_CONF_IP_FORWARD 0
#define UIP_CONF_BUFFER_SIZE 140
#define UIP_CONF_MAX_CONNECTIONS 4
#define UIP_CONF_MAX_LISTENPORTS 8
#define UIP_CONF_UDP_CONNS 4
/* No radio cycling */
#define NETSTACK_CONF_NETWORK sicslowpan_driver
#define NETSTACK_CONF_MAC nullmac_driver
#define NETSTACK_CONF_RDC sicslowmac_driver
#define NETSTACK_CONF_FRAMER framer_802154
#define RIMEADDR_CONF_SIZE 8
#define UIP_CONF_LL_802154 1
#define UIP_CONF_ROUTER 1
#define UIP_CONF_IPV6_RPL 1
#define UIP_CONF_ND6_SEND_RA 0
//#define RPL_BORDER_ROUTER 0
/* A trick to resolve a compilation error with IAR. */
#ifdef __ICCARM__
#define UIP_CONF_DS6_AADDR_NBU 1
#endif
#define UIP_CONF_IPV6 1
#define UIP_CONF_IPV6_QUEUE_PKT 0 // This is a very costly feature as it increases the RAM usage by approximately UIP_ND6_MAX_NEIGHBORS * UIP_LINK_MTU bytes.
#define UIP_CONF_IPV6_CHECKS 1
#define UIP_CONF_IPV6_REASSEMBLY 0
#define UIP_CONF_ND6_MAX_PREFIXES 2
#define UIP_CONF_ND6_MAX_NEIGHBORS 2
#define UIP_CONF_ND6_MAX_DEFROUTERS 1
#define UIP_CONF_IP_FORWARD 0
#define UIP_CONF_BUFFER_SIZE 140
#define UIP_CONF_MAX_CONNECTIONS 6
#define UIP_CONF_MAX_LISTENPORTS 6
#define UIP_CONF_UDP_CONNS 3
#define SICSLOWPAN_CONF_COMPRESSION_IPV6 0
#define SICSLOWPAN_CONF_COMPRESSION_HC1 1
#define SICSLOWPAN_CONF_COMPRESSION_HC06 2
#include "net/sicslowpan.h"
#define SICSLOWPAN_CONF_COMPRESSION SICSLOWPAN_CONF_COMPRESSION_HC06
#define SICSLOWPAN_CONF_FRAG 1
#define SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS 2
#define SICSLOWPAN_CONF_MAXAGE 2
#define UIP_CONF_ICMP6 0
#else /* WITH_UIP6 */
/* Network setup for non-IPv6 (rime). */
#define NETSTACK_CONF_NETWORK rime_driver
#endif /* WITH_UIP6 */
#define UIP_CONF_UDP 1
#define UIP_CONF_TCP 1
#define IEEE802154_CONF_PANID 0x1234
#define STM32W_NODE_ID 0x5678 // to be deleted
#define RF_CHANNEL 16
#define RADIO_RXBUFS 2 // Set to a number greater than 1 to decrease packet loss probability at high rates (e.g, with fragmented packets)
#define UIP_CONF_LLH_LEN 0
typedef unsigned long clock_time_t;
#define CLOCK_CONF_SECOND 1000
typedef unsigned long long rtimer_clock_t;
#define RTIMER_CLOCK_LT(a,b) ((signed short)((a)-(b)) < 0)
/* LEDs ports MB851 */
#define LEDS_CONF_RED_PIN 5
#define LEDS_CONF_GREEN_PIN 6
#define LEDS_CONF_PORT PORTB
#define LEDS_CONF_RED (1<<LEDS_CONF_RED_PIN)
#define LEDS_CONF_GREEN (1<<LEDS_CONF_GREEN_PIN)
#define UIP_ARCH_ADD32 1
#define UIP_ARCH_CHKSUM 0
#define UIP_CONF_BYTE_ORDER UIP_LITTLE_ENDIAN
#ifdef PROJECT_CONF_H
#include PROJECT_CONF_H
#endif /* PROJECT_CONF_H */
#endif /* __CONTIKI_CONF_H__ */

View file

@ -37,6 +37,7 @@
* Contiki main file.
* \author
* Salvatore Pitrulli <salvopitru@users.sourceforge.net>
* Chi-Anh La <la@imag.fr>
*/
/*---------------------------------------------------------------------------*/
@ -82,9 +83,9 @@
#if UIP_CONF_IPV6
PROCINIT(&etimer_process, &tcpip_process, &sensors_process);
PROCINIT(&tcpip_process, &sensors_process);
#else
PROCINIT(&etimer_process, &sensors_process);
PROCINIT(&sensors_process);
#warning "No TCP/IP process!"
#endif
@ -108,9 +109,6 @@ set_rime_addr(void)
eui64.u8[c] = stm32w_eui64[7 - c];
}
}
PRINTF("\n\rRadio EUI-64:");
PRINTLLADDR(eui64);
PRINTF("\n\r");
#if UIP_CONF_IPV6
memcpy(&uip_lladdr.addr, &eui64, sizeof(uip_lladdr.addr));
@ -161,17 +159,25 @@ main(void)
uart1_set_input(serial_line_input_byte);
serial_line_init();
#endif
/* rtimer and ctimer should be initialized before radio duty cycling layers*/
rtimer_init();
/* etimer_process should be initialized before ctimer */
process_start(&etimer_process, NULL);
ctimer_init();
netstack_init();
#if !UIP_CONF_IPV6
ST_RadioEnableAutoAck(FALSE); // Because frames are not 802.15.4 compatible.
ST_RadioEnableAddressFiltering(FALSE);
#endif
set_rime_addr();
ctimer_init();
rtimer_init();
printf("%s %s, channel check rate %lu Hz\n",
NETSTACK_MAC.name, NETSTACK_RDC.name,
CLOCK_SECOND / (NETSTACK_RDC.channel_check_interval() == 0 ? 1:
NETSTACK_RDC.channel_check_interval()));
printf("802.15.4 PAN ID 0x%x, EUI-%d:",
IEEE802154_CONF_PANID, UIP_CONF_LL_802154?64:16);
uip_debug_lladdr_print(&rimeaddr_node_addr);
printf(", radio channel %u\n", RF_CHANNEL);
procinit_init();

View file

@ -0,0 +1,94 @@
/*
* Copyright (c) 2010, STMicroelectronics.
* 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. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 OS
*
*/
/*---------------------------------------------------------------------------*/
/**
* \file
* platform-conf.h for MB851.
* \author
* Salvatore Pitrulli <salvopitru@users.sourceforge.net>
* Chi-Anh La <la@imag.fr>
* Simon Duquennoy <simonduq@sics.se>
*/
/*---------------------------------------------------------------------------*/
#ifndef __PLATFORM_CONF_H__
#define __PLATFORM_CONF_H__
#include PLATFORM_HEADER
#include <inttypes.h>
#include <string.h> // For memcpm().
/* Platform-dependent definitions */
#define CC_CONF_REGISTER_ARGS 0
#define CC_CONF_FUNCTION_POINTER_ARGS 1
#define CC_CONF_FASTCALL
#define CC_CONF_VA_ARGS 1
#define CC_CONF_INLINE inline
#define CCIF
#define CLIF
typedef unsigned short uip_stats_t;
#define UART1_CONF_TX_WITH_INTERRUPT 0
#define WITH_SERIAL_LINE_INPUT 1
/* rtimer_second = 11719 */
#define RT_CONF_RESOLUTION 2
/* A trick to resolve a compilation error with IAR. */
#ifdef __ICCARM__
#define UIP_CONF_DS6_AADDR_NBU 1
#endif
typedef unsigned long clock_time_t;
#define CLOCK_CONF_SECOND 1000
typedef unsigned long rtimer_clock_t;
#define RTIMER_CLOCK_LT(a,b) ((signed short)((a)-(b)) < 0)
/* LEDs ports MB851 */
#define LEDS_CONF_RED_PIN 5
#define LEDS_CONF_GREEN_PIN 6
#define LEDS_CONF_PORT PORTB
#define LEDS_CONF_RED (1<<LEDS_CONF_RED_PIN)
#define LEDS_CONF_GREEN (1<<LEDS_CONF_GREEN_PIN)
#define UIP_ARCH_ADD32 1
#define UIP_ARCH_CHKSUM 0
#define UIP_CONF_BYTE_ORDER UIP_LITTLE_ENDIAN
#endif /* __PLATFORM_CONF_H__ */

View file

@ -29,135 +29,121 @@
*
* This file is part of the Contiki OS
*
* $Id: contiki-conf.h,v 1.2 2010/10/27 14:05:24 salvopitru Exp $
*/
/*---------------------------------------------------------------------------*/
/**
* \file
* contiki-conf.h for MBXXX.
* contiki-conf.h for MBXXX.
* \author
* Salvatore Pitrulli <salvopitru@users.sourceforge.net>
* Salvatore Pitrulli <salvopitru@users.sourceforge.net>
* Chi-Anh La <la@imag.fr>
* Simon Duquennoy <simonduq@sics.se>
*/
/*---------------------------------------------------------------------------*/
#ifndef __CONTIKI_CONF_H__
#define __CONTIKI_CONF_H__
#include PLATFORM_HEADER
#ifdef PLATFORM_CONF_H
#include PLATFORM_CONF_H
#else
#include "platform-conf.h"
#endif /* PLATFORM_CONF_H */
#include <inttypes.h>
#include <string.h> // For memcpm().
/* Radio and 802.15.4 params */
/* 802.15.4 radio channel */
#define RF_CHANNEL 16
/* 802.15.4 PAN ID */
#define IEEE802154_CONF_PANID 0x1234
/* Use EID 64, enable hardware autoack and address filtering */
#define RIMEADDR_CONF_SIZE 8
#define UIP_CONF_LL_802154 1
#define ST_CONF_RADIO_AUTOACK 1
/* Number of buffers for incoming frames */
#define RADIO_RXBUFS 2
/* Set to 0 for non ethernet links */
#define UIP_CONF_LLH_LEN 0
#define CC_CONF_REGISTER_ARGS 0
#define CC_CONF_FUNCTION_POINTER_ARGS 1
#define CC_CONF_FASTCALL
#define CC_CONF_VA_ARGS 1
#define CC_CONF_INLINE inline
/* RDC params */
/* TX routine passes the cca/ack result in the return parameter */
#define RDC_CONF_HARDWARE_ACK 1
/* TX routine does automatic cca and optional backoff */
#define RDC_CONF_HARDWARE_CSMA 0
/* RDC debug with LED */
#define RDC_CONF_DEBUG_LED 1
/* Channel check rate (per second) */
#define NETSTACK_CONF_RDC_CHANNEL_CHECK_RATE 8
/* Use ACK for optimization (LPP, XMAC) */
#define WITH_ACK_OPTIMIZATION 0
#define CCIF
#define CLIF
/* Netstack config */
#define NETSTACK_CONF_MAC csma_driver
#define NETSTACK_CONF_RDC contikimac_driver
#define NETSTACK_CONF_FRAMER framer_802154
#define NETSTACK_CONF_RADIO stm32w_radio_driver
/* These names are deprecated, use C99 names. */
typedef uint8_t u8_t;
typedef uint16_t u16_t;
typedef uint32_t u32_t;
typedef int32_t s32_t;
/* ContikiMAC config */
#define CONTIKIMAC_CONF_COMPOWER 1
#define CONTIKIMAC_CONF_BROADCAST_RATE_LIMIT 0
#define CONTIKIMAC_CONF_ANNOUNCEMENTS 0
typedef unsigned short uip_stats_t;
/* CXMAC config */
#define CXMAC_CONF_ANNOUNCEMENTS 0
#define CXMAC_CONF_COMPOWER 1
//#define FIXED_NET_ADDRESS 1
//#define NET_ADDR_A 0x2001
//#define NET_ADDR_B 0xdb8
//#define NET_ADDR_C 0xbbbb
//#define NET_ADDR_D 0xabcd
/* XMAC config */
#define XMAC_CONF_ANNOUNCEMENTS 0
#define XMAC_CONF_COMPOWER 1
#define UART1_CONF_TX_WITH_INTERRUPT 0
#define WITH_SERIAL_LINE_INPUT 1
#define ENERGEST_CONF_ON 0
#define TELNETD_CONF_NUMLINES 6
#define QUEUEBUF_CONF_NUM 2
#define NETSTACK_CONF_RADIO stm32w_radio_driver
/* Other */
#define ENERGEST_CONF_ON 0
#define QUEUEBUF_CONF_NUM 2
#if WITH_UIP6
/* No radio cycling */
#define NETSTACK_CONF_NETWORK sicslowpan_driver
#define NETSTACK_CONF_MAC nullmac_driver
#define NETSTACK_CONF_RDC sicslowmac_driver
#define NETSTACK_CONF_FRAMER framer_802154
/* Network setup for IPv6 */
#define NETSTACK_CONF_NETWORK sicslowpan_driver
#define RIMEADDR_CONF_SIZE 8
#define UIP_CONF_LL_802154 1
/* Specify a minimum packet size for 6lowpan compression to be
enabled. This is needed for ContikiMAC, which needs packets to be
larger than a specified size, if no ContikiMAC header should be
used. */
#define SICSLOWPAN_CONF_COMPRESSION_THRESHOLD 63
#define CONTIKIMAC_CONF_WITH_CONTIKIMAC_HEADER 0
#define UIP_CONF_ROUTER 1
#define UIP_CONF_IPV6_RPL 1
#define UIP_CONF_ND6_SEND_RA 0
//#define RPL_BORDER_ROUTER 0
#define UIP_CONF_ROUTER 1
#define UIP_CONF_IPV6_RPL 1
#define UIP_CONF_ND6_SEND_RA 0
/* A trick to resolve a compilation error with IAR. */
#ifdef __ICCARM__
#define UIP_CONF_DS6_AADDR_NBU 1
#endif
#define UIP_CONF_IPV6 1
#define UIP_CONF_IPV6_QUEUE_PKT 0
#define UIP_CONF_IPV6_CHECKS 1
#define UIP_CONF_IPV6_REASSEMBLY 0
#define UIP_CONF_ND6_MAX_PREFIXES 2
#define UIP_CONF_ND6_MAX_NEIGHBORS 2
#define UIP_CONF_ND6_MAX_DEFROUTERS 1
#define UIP_CONF_IP_FORWARD 0
#define UIP_CONF_BUFFER_SIZE 140
#define UIP_CONF_MAX_CONNECTIONS 4
#define UIP_CONF_MAX_LISTENPORTS 8
#define UIP_CONF_UDP_CONNS 4
#define UIP_CONF_IPV6 1
#define UIP_CONF_IPV6_QUEUE_PKT 0 // This is a very costly feature as it increases the RAM usage by approximately UIP_ND6_MAX_NEIGHBORS * UIP_LINK_MTU bytes.
#define UIP_CONF_IPV6_CHECKS 1
#define UIP_CONF_IPV6_REASSEMBLY 0
#define UIP_CONF_ND6_MAX_PREFIXES 2
#define UIP_CONF_ND6_MAX_NEIGHBORS 2
#define UIP_CONF_ND6_MAX_DEFROUTERS 1
#define UIP_CONF_IP_FORWARD 0
#define UIP_CONF_BUFFER_SIZE 140
#define UIP_CONF_MAX_CONNECTIONS 6
#define UIP_CONF_MAX_LISTENPORTS 6
#define UIP_CONF_UDP_CONNS 3
#define SICSLOWPAN_CONF_COMPRESSION_IPV6 0
#define SICSLOWPAN_CONF_COMPRESSION_HC1 1
#define SICSLOWPAN_CONF_COMPRESSION_HC06 2
#include "net/sicslowpan.h"
#define SICSLOWPAN_CONF_COMPRESSION SICSLOWPAN_CONF_COMPRESSION_HC06
#define SICSLOWPAN_CONF_FRAG 1
#define SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS 2
#define SICSLOWPAN_CONF_MAXAGE 2
#define UIP_CONF_ICMP6 0
#else /* WITH_UIP6 */
/* Network setup for non-IPv6 (rime). */
#define NETSTACK_CONF_NETWORK rime_driver
#endif /* WITH_UIP6 */
#define UIP_CONF_UDP 1
#define UIP_CONF_TCP 1
#define IEEE802154_CONF_PANID 0x1234
#define STM32W_NODE_ID 0x5678 // to be deleted
#define RF_CHANNEL 16
#define RADIO_RXBUFS 2 // Set to a number greater than 1 to decrease packet loss probability at high rates (e.g, with fragmented packets)
#define UIP_CONF_LLH_LEN 0
typedef unsigned long clock_time_t;
#define CLOCK_CONF_SECOND 1000
typedef unsigned long long rtimer_clock_t;
#define RTIMER_CLOCK_LT(a,b) ((signed short)((a)-(b)) < 0)
/* LEDs ports MB8xxx */
#define LEDS_CONF_GREEN LED_D1
#define LEDS_CONF_YELLOW LED_D3
#define LEDS_CONF_RED LED_D3
#define UIP_ARCH_ADD32 1
#define UIP_ARCH_CHKSUM 0
#define UIP_CONF_BYTE_ORDER UIP_LITTLE_ENDIAN
#ifdef PROJECT_CONF_H
#include PROJECT_CONF_H
#endif /* PROJECT_CONF_H */
#endif /* __CONTIKI_CONF_H__ */

View file

@ -36,6 +36,7 @@
* Contiki main file.
* \author
* Salvatore Pitrulli <salvopitru@users.sourceforge.net>
* Chi-Anh La <la@imag.fr>
*/
/*---------------------------------------------------------------------------*/
@ -65,8 +66,6 @@
#include "net/rime.h"
#include "net/rime/rime-udp.h"
#include "net/uip.h"
#define DEBUG 1
#if DEBUG
#include <stdio.h>
@ -81,9 +80,9 @@
#if UIP_CONF_IPV6
PROCINIT(&etimer_process, &tcpip_process, &sensors_process);
PROCINIT(&tcpip_process, &sensors_process);
#else
PROCINIT(&etimer_process, &sensors_process);
PROCINIT(&sensors_process);
#warning "No TCP/IP process!"
#endif
@ -107,9 +106,6 @@ set_rime_addr(void)
eui64.u8[c] = stm32w_eui64[7 - c];
}
}
PRINTF("\n\rRadio EUI-64:");
PRINTLLADDR(eui64);
PRINTF("\n\r");
#if UIP_CONF_IPV6
memcpy(&uip_lladdr.addr, &eui64, sizeof(uip_lladdr.addr));
@ -160,26 +156,32 @@ main(void)
uart1_set_input(serial_line_input_byte);
serial_line_init();
#endif
/* rtimer and ctimer should be initialized before radio duty cycling layers*/
rtimer_init();
/* etimer_process should be initialized before ctimer */
process_start(&etimer_process, NULL);
ctimer_init();
netstack_init();
#if !UIP_CONF_IPV6
ST_RadioEnableAutoAck(FALSE); // Because frames are not 802.15.4 compatible.
ST_RadioEnableAddressFiltering(FALSE);
#endif
set_rime_addr();
ctimer_init();
rtimer_init();
netstack_init();
set_rime_addr();
printf("%s %s, channel check rate %lu Hz\n",
NETSTACK_MAC.name, NETSTACK_RDC.name,
CLOCK_SECOND / (NETSTACK_RDC.channel_check_interval() == 0 ? 1:
NETSTACK_RDC.channel_check_interval()));
printf("802.15.4 PAN ID 0x%x, EUI-%d:",
IEEE802154_CONF_PANID, UIP_CONF_LL_802154?64:16);
uip_debug_lladdr_print(&rimeaddr_node_addr);
printf(", radio channel %u\n", RF_CHANNEL);
procinit_init();
energest_init();
ENERGEST_ON(ENERGEST_TYPE_CPU);
autostart_start(autostart_processes);
watchdog_start();
while(1){

View file

@ -0,0 +1,92 @@
/*
* Copyright (c) 2010, STMicroelectronics.
* 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. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 OS
*
*/
/*---------------------------------------------------------------------------*/
/**
* \file
* platform-conf.h for MBXXX.
* \author
* Salvatore Pitrulli <salvopitru@users.sourceforge.net>
* Chi-Anh La <la@imag.fr>
* Simon Duquennoy <simonduq@sics.se>
*/
/*---------------------------------------------------------------------------*/
#ifndef __PLATFORM_CONF_H__
#define __PLATFORM_CONF_H__
#include PLATFORM_HEADER
#include <inttypes.h>
#include <string.h> // For memcpm().
/* Platform-dependent definitions */
#define CC_CONF_REGISTER_ARGS 0
#define CC_CONF_FUNCTION_POINTER_ARGS 1
#define CC_CONF_FASTCALL
#define CC_CONF_VA_ARGS 1
#define CC_CONF_INLINE inline
#define CCIF
#define CLIF
typedef unsigned short uip_stats_t;
#define UART1_CONF_TX_WITH_INTERRUPT 0
#define WITH_SERIAL_LINE_INPUT 1
/* rtimer_second = 11719 */
#define RT_CONF_RESOLUTION 2
/* A trick to resolve a compilation error with IAR. */
#ifdef __ICCARM__
#define UIP_CONF_DS6_AADDR_NBU 1
#endif
typedef unsigned long clock_time_t;
#define CLOCK_CONF_SECOND 1000
typedef unsigned long rtimer_clock_t;
#define RTIMER_CLOCK_LT(a,b) ((signed short)((a)-(b)) < 0)
/* LEDs ports MB8xxx */
#define LEDS_CONF_GREEN LED_D1
#define LEDS_CONF_YELLOW LED_D3
#define LEDS_CONF_RED LED_D3
#define UIP_ARCH_ADD32 1
#define UIP_ARCH_CHKSUM 0
#define UIP_CONF_BYTE_ORDER UIP_LITTLE_ENDIAN
#endif /* __PLATFORM_CONF_H__ */

View file

@ -32,10 +32,10 @@
package se.sics.cooja.mspmote;
import java.io.File;
import org.apache.log4j.Logger;
import se.sics.cooja.MoteInterfaceHandler;
import se.sics.cooja.Simulation;
import se.sics.cooja.interfaces.*;
import se.sics.mspsim.platform.esb.ESBNode;
/**

View file

@ -31,12 +31,13 @@
package se.sics.cooja.mspmote;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Observable;
import org.apache.log4j.Logger;
@ -56,14 +57,12 @@ import se.sics.cooja.interfaces.IPAddress;
import se.sics.cooja.motes.AbstractEmulatedMote;
import se.sics.cooja.mspmote.interfaces.MspSerial;
import se.sics.cooja.mspmote.plugins.CodeVisualizerSkin;
import se.sics.cooja.mspmote.plugins.MspBreakpointContainer;
import se.sics.cooja.plugins.BufferListener.BufferAccess;
import se.sics.cooja.mspmote.plugins.MspBreakpoint;
import se.sics.cooja.plugins.Visualizer;
import se.sics.mspsim.cli.CommandContext;
import se.sics.mspsim.cli.CommandHandler;
import se.sics.mspsim.cli.LineListener;
import se.sics.mspsim.cli.LineOutputStream;
import se.sics.mspsim.core.CPUMonitor;
import se.sics.mspsim.core.EmulationException;
import se.sics.mspsim.core.MSP430;
import se.sics.mspsim.core.MSP430Constants;
@ -95,7 +94,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
private MspMoteMemory myMemory = null;
private MoteInterfaceHandler myMoteInterfaceHandler = null;
public ComponentRegistry registry = null;
/* Stack monitoring variables */
private boolean stopNextInstruction = false;
private boolean monitorStackUsage = false;
@ -103,15 +102,11 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
private int heapStartAddress;
private StackOverflowObservable stackOverflowObservable = new StackOverflowObservable();
private MspBreakpointContainer breakpointsContainer;
public MspMote() {
myMoteType = null;
myCpu = null;
myMemory = null;
myMoteInterfaceHandler = null;
/* Scheduled from setConfigXML */
}
public MspMote(MspMoteType moteType, Simulation simulation) {
@ -121,7 +116,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
/* Schedule us immediately */
requestImmediateWakeup();
}
protected void initMote() {
if (myMoteType != null) {
initEmulator(myMoteType.getContikiFirmwareFile());
@ -130,9 +125,8 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
/* TODO Setup COOJA-specific window manager */
registry.registerComponent("windowManager", new JFrameWindowManager());
/* Create watchpoint container */
try {
breakpointsContainer = new MspBreakpointContainer(this, ((MspMoteType)getType()).getFirmwareDebugInfo());
debuggingInfo = ((MspMoteType)getType()).getFirmwareDebugInfo();
} catch (IOException e) {
throw (RuntimeException) new RuntimeException("Error: " + e.getMessage()).initCause(e);
}
@ -300,10 +294,9 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
if (stopNextInstruction) {
stopNextInstruction = false;
/*sendCLICommandAndPrint("trace 1000");*/ /* TODO Enable */
scheduleNextWakeup(t);
throw new RuntimeException("MSPSim requested simulation stop");
}
}
if (lastExecute < 0) {
/* Always execute one microsecond the first time */
@ -312,12 +305,12 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
if (t < lastExecute) {
throw new RuntimeException("Bad event ordering: " + lastExecute + " < " + t);
}
/* Execute MSPSim-based mote */
/* TODO Try-catch overhead */
try {
nextExecute =
t + duration +
nextExecute =
t + duration +
myCpu.stepMicros(t - lastExecute, duration);
lastExecute = t;
} catch (EmulationException e) {
@ -332,8 +325,12 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
}
/*logger.debug(t + ": Schedule next wakeup at " + nextExecute);*/
scheduleNextWakeup(nextExecute);
if (stopNextInstruction) {
stopNextInstruction = false;
throw new RuntimeException("MSPSim requested simulation stop");
}
/* XXX TODO Reimplement stack monitoring using MSPSim internals */
/*if (monitorStackUsage) {
int newStack = cpu.reg[MSP430.SP];
@ -349,7 +346,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
}
}*/
}
public String getStackTrace() {
return executeCLICommand("stacktrace");
}
@ -357,7 +354,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
public int executeCLICommand(String cmd, CommandContext context) {
return commandHandler.executeCommand(cmd, context);
}
public String executeCLICommand(String cmd) {
final StringBuilder sb = new StringBuilder();
LineListener ll = new LineListener() {
@ -369,14 +366,14 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
CommandContext c = new CommandContext(commandHandler, null, "", new String[0], 1, null);
c.out = po;
c.err = po;
if (0 != executeCLICommand(cmd, c)) {
sb.append("\nWarning: command failed");
}
return sb.toString();
}
public int getCPUFrequency() {
return myCpu.getDCOFrequency();
}
@ -384,16 +381,15 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
public int getID() {
return getInterfaces().getMoteID().getMoteID();
}
public boolean setConfigXML(Simulation simulation, Collection<Element> configXML, boolean visAvailable) {
setSimulation(simulation);
if (myMoteInterfaceHandler == null) {
myMoteInterfaceHandler = createMoteInterfaceHandler();
}
/* Create watchpoint container */
try {
breakpointsContainer = new MspBreakpointContainer(this, ((MspMoteType)getType()).getFirmwareDebugInfo());
debuggingInfo = ((MspMoteType)getType()).getFirmwareDebugInfo();
} catch (IOException e) {
throw (RuntimeException) new RuntimeException("Error: " + e.getMessage()).initCause(e);
}
@ -404,7 +400,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
if (name.equals("motetype_identifier")) {
/* Ignored: handled by simulation */
} else if ("breakpoints".equals(element.getName())) {
breakpointsContainer.setConfigXML(element.getChildren(), visAvailable);
setWatchpointConfigXML(element.getChildren(), visAvailable);
} else if (name.equals("interface_config")) {
String intfClass = element.getText().trim();
if (intfClass.equals("se.sics.cooja.mspmote.interfaces.MspIPAddress")) {
@ -440,7 +436,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
/* Breakpoints */
element = new Element("breakpoints");
element.addContent(breakpointsContainer.getConfigXML());
element.addContent(getWatchpointConfigXML());
config.add(element);
// Mote interfaces
@ -458,41 +454,15 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
return config;
}
/* Watchpoints: Forward to breakpoint container */
public void addWatchpointListener(ActionListener listener) {
breakpointsContainer.addWatchpointListener(listener);
}
public Watchpoint getLastWatchpoint() {
return breakpointsContainer.getLastWatchpoint();
}
public Mote getMote() {
return breakpointsContainer.getMote();
}
public ActionListener[] getWatchpointListeners() {
return breakpointsContainer.getWatchpointListeners();
}
public void removeWatchpointListener(ActionListener listener) {
breakpointsContainer.removeWatchpointListener(listener);
}
public MspBreakpointContainer getBreakpointsContainer() {
return breakpointsContainer;
}
public String getExecutionDetails() {
return executeCLICommand("stacktrace");
}
public String getPCString() {
int pc = myCpu.getPC();
ELF elf = (ELF)myCpu.getRegistry().getComponent(ELF.class);
ELF elf = myCpu.getRegistry().getComponent(ELF.class);
DebugInfo di = elf.getDebugInfo(pc);
/* Following code examples from MSPsim, DebugCommands.java */
if (di == null) {
di = elf.getDebugInfo(pc + 1);
@ -510,7 +480,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
}
}
String name = mapEntry.getName();
return file + ":?:" + name;
return file + ":?:" + name;
}
return String.format("*%02x", myCpu.reg[MSP430Constants.PC]);
} catch (Exception e) {
@ -525,7 +495,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
/* strip path */
file = file.substring(file.lastIndexOf('/')+1, file.length());
}
String function = di.getFunction();
function = function==null?"":function;
if (function.contains(":")) {
@ -536,7 +506,147 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
function = "?";
}
return file + ":" + lineNo + ":" + function;
/*return executeCLICommand("line " + myCpu.getPC());*/
}
/* WatchpointMote */
private ArrayList<WatchpointListener> watchpointListeners = new ArrayList<WatchpointListener>();
private ArrayList<MspBreakpoint> watchpoints = new ArrayList<MspBreakpoint>();
private Hashtable<File, Hashtable<Integer, Integer>> debuggingInfo = null;
public void addWatchpointListener(WatchpointListener listener) {
watchpointListeners.add(listener);
}
public void removeWatchpointListener(WatchpointListener listener) {
watchpointListeners.remove(listener);
}
public WatchpointListener[] getWatchpointListeners() {
return watchpointListeners.toArray(new WatchpointListener[0]);
}
public Watchpoint addBreakpoint(File codeFile, int lineNr, int address) {
MspBreakpoint bp = new MspBreakpoint(this, address, codeFile, new Integer(lineNr));
watchpoints.add(bp);
for (WatchpointListener listener: watchpointListeners) {
listener.watchpointsChanged();
}
return bp;
}
public void removeBreakpoint(Watchpoint watchpoint) {
((MspBreakpoint)watchpoint).unregisterBreakpoint();
watchpoints.remove(watchpoint);
for (WatchpointListener listener: watchpointListeners) {
listener.watchpointsChanged();
}
}
public Watchpoint[] getBreakpoints() {
return watchpoints.toArray(new Watchpoint[0]);
}
public boolean breakpointExists(int address) {
if (address < 0) {
return false;
}
for (Watchpoint watchpoint: watchpoints) {
if (watchpoint.getExecutableAddress() == address) {
return true;
}
}
return false;
}
public boolean breakpointExists(File file, int lineNr) {
for (Watchpoint watchpoint: watchpoints) {
if (watchpoint.getCodeFile() == null) {
continue;
}
if (watchpoint.getCodeFile().compareTo(file) != 0) {
continue;
}
if (watchpoint.getLineNumber() != lineNr) {
continue;
}
return true;
}
return false;
}
public Integer getExecutableAddressOf(File file, int lineNr) {
if (file == null || lineNr < 0 || debuggingInfo == null) {
return null;
}
/* Match file */
Hashtable<Integer, Integer> lineTable = debuggingInfo.get(file);
if (lineTable == null) {
Enumeration<File> fileEnum = debuggingInfo.keys();
while (fileEnum.hasMoreElements()) {
File f = fileEnum.nextElement();
if (f != null && f.getName().equals(file.getName())) {
lineTable = debuggingInfo.get(f);
break;
}
}
}
if (lineTable == null) {
return null;
}
/* Match line number */
Integer address = lineTable.get(lineNr);
if (address != null) {
Enumeration<Integer> lineEnum = lineTable.keys();
while (lineEnum.hasMoreElements()) {
Integer l = lineEnum.nextElement();
if (l != null && l.intValue() == lineNr) {
/* Found line address */
return lineTable.get(l);
}
}
}
return null;
}
public void signalBreakpointTrigger(MspBreakpoint b) {
if (b.stopsSimulation() && getSimulation().isRunning()) {
/* Stop simulation immediately */
stopNextInstruction();
}
/* Notify listeners */
WatchpointListener[] listeners = getWatchpointListeners();
for (WatchpointListener listener: listeners) {
listener.watchpointTriggered(b);
}
}
public Collection<Element> getWatchpointConfigXML() {
ArrayList<Element> config = new ArrayList<Element>();
Element element;
for (MspBreakpoint breakpoint: watchpoints) {
element = new Element("breakpoint");
element.addContent(breakpoint.getConfigXML());
config.add(element);
}
return config;
}
public boolean setWatchpointConfigXML(Collection<Element> configXML, boolean visAvailable) {
for (Element element : configXML) {
if (element.getName().equals("breakpoint")) {
MspBreakpoint breakpoint = new MspBreakpoint(this);
if (!breakpoint.setConfigXML(element.getChildren(), visAvailable)) {
logger.warn("Could not restore breakpoint: " + breakpoint);
} else {
watchpoints.add(breakpoint);
}
}
}
return true;
}
}

View file

@ -31,26 +31,32 @@
package se.sics.cooja.mspmote.plugins;
import java.awt.*;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JColorChooser;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
import org.apache.log4j.Logger;
import se.sics.cooja.GUI;
import se.sics.cooja.Mote;
import se.sics.cooja.MoteType;
import se.sics.cooja.Simulation;
import se.sics.cooja.mspmote.MspMote;
import se.sics.cooja.Watchpoint;
import se.sics.cooja.WatchpointMote;
/**
* Displays a set of breakpoints.
@ -60,27 +66,27 @@ import se.sics.cooja.mspmote.MspMote;
public class BreakpointsUI extends JPanel {
private static Logger logger = Logger.getLogger(BreakpointsUI.class);
private static final int COLUMN_INFO = 0;
private static final int COLUMN_ADDRESS = 1;
private static final int COLUMN_FILELINE = 2;
private static final int COLUMN_ADDRESS = 0;
private static final int COLUMN_FILELINE = 1;
private static final int COLUMN_INFO = 2;
private static final int COLUMN_STOP = 3;
private static final int COLUMN_REMOVE = 4;
private static final String[] COLUMN_NAMES = {
"Info",
"Address",
"File",
"Stop",
"Remove"
"Source",
"Info",
"Stops simulation"
};
private MspBreakpointContainer breakpoints = null;
private WatchpointMote mote;
private MspCodeWatcher codeWatcher;
private JTable table = null;
private MspBreakpoint popupBreakpoint = null;
private Watchpoint selectedWatchpoint = null;
public BreakpointsUI(MspBreakpointContainer breakpoints, final MspCodeWatcher codeWatcher) {
this.breakpoints = breakpoints;
public BreakpointsUI(WatchpointMote mote, final MspCodeWatcher codeWatcher) {
this.mote = mote;
this.codeWatcher = codeWatcher;
/* Breakpoints table */
table = new JTable(tableModel) {
@ -93,15 +99,20 @@ public class BreakpointsUI extends JPanel {
int realColumnIndex = table.convertColumnIndexToModel(colIndex);
if (realColumnIndex == COLUMN_FILELINE) {
MspBreakpoint[] allBreakpoints = BreakpointsUI.this.breakpoints.getBreakpoints();
Watchpoint[] allBreakpoints = BreakpointsUI.this.mote.getBreakpoints();
if (rowIndex < 0 || rowIndex >= allBreakpoints.length) {
return null;
}
File file = allBreakpoints[rowIndex].getCodeFile();
Watchpoint watchpoint = allBreakpoints[rowIndex];
File file = watchpoint.getCodeFile();
if (file == null) {
return null;
return String.format("[unknown @ 0x%04x]", watchpoint.getExecutableAddress());
}
return file.getPath() + ":" + allBreakpoints[rowIndex].getLineNumber();
Integer line = watchpoint.getLineNumber();
if (line == null) {
return file.getPath() + ":?";
}
return file.getPath() + ":" + line;
}
if (realColumnIndex == COLUMN_INFO) {
@ -111,53 +122,41 @@ public class BreakpointsUI extends JPanel {
if (realColumnIndex == COLUMN_STOP) {
return "Indicates whether the watchpoint will stop the simulation when triggered";
}
if (realColumnIndex == COLUMN_REMOVE) {
return "Remove breakpoint from this mote only. (Right-click for more options)";
}
return null;
}
};
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.getColumnModel().getColumn(COLUMN_ADDRESS).setPreferredWidth(60); /* XXX */
table.getColumnModel().getColumn(COLUMN_ADDRESS).setMaxWidth(60);
table.getColumnModel().getColumn(COLUMN_INFO).setPreferredWidth(60);
table.getColumnModel().getColumn(COLUMN_INFO).setMaxWidth(60);
table.getColumnModel().getColumn(COLUMN_INFO).setCellRenderer(
new DefaultTableCellRenderer() {
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
Component c = super.getTableCellRendererComponent(
table, value, isSelected, hasFocus, row, column);
if (column != COLUMN_INFO) {
return c;
}
MspBreakpoint[] allBreakpoints = BreakpointsUI.this.breakpoints.getBreakpoints();
if (row < 0 || row >= allBreakpoints.length) {
return c;
}
MspBreakpoint breakpoint = allBreakpoints[row];
if (breakpoint.getColor() == null) {
return c;
}
/* Use watchpoint color */
c.setForeground(breakpoint.getColor());
return c;
}
});
table.getColumnModel().getColumn(COLUMN_STOP).setPreferredWidth(60);
table.getColumnModel().getColumn(COLUMN_STOP).setMaxWidth(60);
table.getColumnModel().getColumn(COLUMN_REMOVE).setPreferredWidth(60);
table.getColumnModel().getColumn(COLUMN_REMOVE).setMaxWidth(60);
table.getColumnModel().getColumn(COLUMN_INFO).setCellRenderer(new DefaultTableCellRenderer() {
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
Component c = super.getTableCellRendererComponent(
table, value, isSelected, hasFocus, row, column);
if (column != COLUMN_INFO) {
return c;
}
Watchpoint[] allBreakpoints = BreakpointsUI.this.mote.getBreakpoints();
if (row < 0 || row >= allBreakpoints.length) {
return c;
}
Watchpoint breakpoint = allBreakpoints[row];
if (breakpoint.getColor() == null) {
return c;
}
/* Use watchpoint color */
c.setBackground(Color.WHITE);
c.setForeground(breakpoint.getColor());
return c;
}
});
/* Popup menu: register on all motes */
final JPopupMenu popupMenu = new JPopupMenu();
popupMenu.add(new JMenuItem(addToMoteTypeAction));
popupMenu.add(new JMenuItem(delFromMoteTypeAction));
popupMenu.add(new JMenuItem(gotoCodeAction));
popupMenu.add(new JSeparator());
popupMenu.add(new JMenuItem(removeWatchpointAction));
popupMenu.add(new JMenuItem(configureWatchpointAction));
/* Show source file on breakpoint mouse click */
table.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
java.awt.Point p = e.getPoint();
@ -167,63 +166,32 @@ public class BreakpointsUI extends JPanel {
if (realColumnIndex != COLUMN_ADDRESS
&& realColumnIndex != COLUMN_FILELINE
&& realColumnIndex != COLUMN_REMOVE
&& realColumnIndex != COLUMN_INFO) {
return;
}
MspBreakpoint[] allBreakpoints = BreakpointsUI.this.breakpoints.getBreakpoints();
Watchpoint[] allBreakpoints = BreakpointsUI.this.mote.getBreakpoints();
if (rowIndex < 0 || rowIndex >= allBreakpoints.length) {
return;
}
MspBreakpoint breakpoint = allBreakpoints[rowIndex];
Watchpoint breakpoint = allBreakpoints[rowIndex];
if (e.isPopupTrigger() || SwingUtilities.isRightMouseButton(e)) {
popupBreakpoint = breakpoint;
selectedWatchpoint = breakpoint;
popupMenu.show(table, e.getX(), e.getY());
return;
}
if (realColumnIndex == COLUMN_INFO) {
String msg = JOptionPane.showInputDialog(
GUI.getTopParentContainer(),
"Enter description",
"Watchpoint Description",
JOptionPane.QUESTION_MESSAGE);
if (msg != null) {
breakpoint.setUserMessage(msg);
}
Color newColor = JColorChooser.showDialog(
GUI.getTopParentContainer(),
"Watchpoint Color",
breakpoint.getColor());
if (newColor != null) {
breakpoint.setColor(newColor);
}
configureWatchpointInfo(breakpoint);
return;
}
File file = allBreakpoints[rowIndex].getCodeFile();
/*File file = allBreakpoints[rowIndex].getCodeFile();
int line = allBreakpoints[rowIndex].getLineNumber();
if (file == null) {
return;
}
/* Display source code */
codeWatcher.displaySourceFile(file, line);
}
});
/* Update when breakpoints are triggered/added/removed */
breakpoints.addWatchpointListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
MspBreakpoint triggered = BreakpointsUI.this.breakpoints.getLastWatchpoint();
if (triggered == null) {
table.repaint();
return;
}
flashBreakpoint(triggered);
}*/
}
});
@ -232,24 +200,41 @@ public class BreakpointsUI extends JPanel {
add(BorderLayout.CENTER, table);
}
private void flashBreakpoint(MspBreakpoint breakpoint) {
/* Locate breakpoints table index */
int index = -1;
MspBreakpoint[] all = breakpoints.getBreakpoints();
for (int i=0; i < breakpoints.getBreakpointsCount(); i++) {
if (breakpoint == all[i]) {
index = i;
break;
}
}
if (index < 0) {
private void configureWatchpointInfo(Watchpoint breakpoint) {
String msg = (String) JOptionPane.showInputDialog(
GUI.getTopParentContainer(),
"Enter description;",
"Watchpoint description",
JOptionPane.QUESTION_MESSAGE, null, null, breakpoint.getUserMessage());
if (msg == null) {
return;
}
breakpoint.setUserMessage(msg);
Color newColor = JColorChooser.showDialog(
GUI.getTopParentContainer(),
"Watchpoint color",
breakpoint.getColor());
if (newColor == null) {
return;
}
breakpoint.setColor(newColor);
}
final int breakpointIndex = index;
public void selectBreakpoint(final Watchpoint breakpoint) {
if (breakpoint == null) {
return;
}
/* Locate breakpoints table index */
SwingUtilities.invokeLater(new Runnable() {
public void run() {
table.setRowSelectionInterval(breakpointIndex, breakpointIndex);
Watchpoint[] watchpoints = mote.getBreakpoints();
for (int i=0; i < watchpoints.length; i++) {
if (breakpoint == watchpoints[i]) {
/* Select */
table.setRowSelectionInterval(i, i);
return;
}
}
}
});
}
@ -259,18 +244,18 @@ public class BreakpointsUI extends JPanel {
return COLUMN_NAMES[col].toString();
}
public int getRowCount() {
return breakpoints.getBreakpointsCount();
return mote.getBreakpoints().length;
}
public int getColumnCount() {
return COLUMN_NAMES.length;
}
public Object getValueAt(int row, int col) {
MspBreakpoint breakpoint = breakpoints.getBreakpoints()[row];
Watchpoint breakpoint = mote.getBreakpoints()[row];
/* Executable address in hexadecimal */
if (col == COLUMN_ADDRESS) {
Integer address = breakpoint.getExecutableAddress();
return "0x" + Integer.toHexString(address.intValue());
return String.format("0x%04x", address.intValue());
}
/* Source file + line number */
@ -300,7 +285,7 @@ public class BreakpointsUI extends JPanel {
return getColumnClass(col) == Boolean.class;
}
public void setValueAt(Object value, int row, int col) {
MspBreakpoint breakpoint = breakpoints.getBreakpoints()[row];
Watchpoint breakpoint = mote.getBreakpoints()[row];
if (col == COLUMN_STOP) {
/* Toggle stop state */
@ -308,109 +293,36 @@ public class BreakpointsUI extends JPanel {
fireTableCellUpdated(row, col);
return;
}
if (col == COLUMN_REMOVE) {
/* Remove breakpoint */
Integer address = breakpoint.getExecutableAddress();
breakpoints.removeBreakpoint(address);
fireTableCellUpdated(row, col);
return;
}
}
public Class<?> getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
};
private Action addToMoteTypeAction = new AbstractAction("Register on all motes (mote type)") {
private Action gotoCodeAction = new AbstractAction("Show in source code") {
public void actionPerformed(ActionEvent e) {
if (popupBreakpoint == null) {
logger.fatal("No breakpoint to add");
if (selectedWatchpoint == null) {
return;
}
/* Extract all motes of the same mote type */
Simulation sim = popupBreakpoint.getMote().getSimulation();
MoteType type = popupBreakpoint.getMote().getType();
ArrayList<MspMote> motes = new ArrayList<MspMote>();
for (Mote m: sim.getMotes()) {
if (m.getType() == type) {
if (!(m instanceof MspMote)) {
logger.fatal("At least one mote was not a MSP mote: " + m);
return;
}
motes.add((MspMote)m);
}
}
/* Register breakpoints */
int reregistered = 0;
for (MspMote m: motes) {
/* Avoid duplicates (match executable addresses) */
MspBreakpointContainer container = m.getBreakpointsContainer();
MspBreakpoint[] breakpoints = container.getBreakpoints();
for (MspBreakpoint w: breakpoints) {
if (popupBreakpoint.getExecutableAddress().intValue() ==
w.getExecutableAddress().intValue()) {
logger.info("Reregistering breakpoint at mote: " + m);
container.removeBreakpoint(w.getExecutableAddress());
reregistered++;
}
}
MspBreakpoint newBreakpoint = container.addBreakpoint(
popupBreakpoint.getCodeFile(),
popupBreakpoint.getLineNumber(),
popupBreakpoint.getExecutableAddress());
newBreakpoint.setUserMessage(popupBreakpoint.getUserMessage());
newBreakpoint.setColor(popupBreakpoint.getColor());
newBreakpoint.setStopsSimulation(popupBreakpoint.stopsSimulation());
}
JOptionPane.showMessageDialog(GUI.getTopParentContainer(),
"Registered " + motes.size() + " breakpoints (" + reregistered + " re-registered)",
"Breakpoints added", JOptionPane.INFORMATION_MESSAGE);
codeWatcher.displaySourceFile(selectedWatchpoint.getCodeFile(), selectedWatchpoint.getLineNumber(), false);
}
};
private Action delFromMoteTypeAction = new AbstractAction("Delete from all motes (mote type)") {
private Action removeWatchpointAction = new AbstractAction("Remove watchpoint") {
public void actionPerformed(ActionEvent e) {
if (popupBreakpoint == null) {
logger.fatal("No breakpoint to delete");
if (selectedWatchpoint == null) {
return;
}
/* Extract all motes of the same mote type */
Simulation sim = popupBreakpoint.getMote().getSimulation();
MoteType type = popupBreakpoint.getMote().getType();
ArrayList<MspMote> motes = new ArrayList<MspMote>();
for (Mote m: sim.getMotes()) {
if (m.getType() == type) {
if (!(m instanceof MspMote)) {
logger.fatal("At least one mote was not a MSP mote: " + m);
return;
}
motes.add((MspMote)m);
}
mote.removeBreakpoint(selectedWatchpoint);
table.invalidate();
table.repaint();
}
};
private Action configureWatchpointAction = new AbstractAction("Configure watchpoint information") {
public void actionPerformed(ActionEvent e) {
if (selectedWatchpoint == null) {
return;
}
/* Delete breakpoints */
int deleted = 0;
for (MspMote m: motes) {
/* Avoid duplicates (match executable addresses) */
MspBreakpointContainer container = m.getBreakpointsContainer();
MspBreakpoint[] breakpoints = container.getBreakpoints();
for (MspBreakpoint w: breakpoints) {
if (popupBreakpoint.getExecutableAddress().intValue() ==
w.getExecutableAddress().intValue()) {
container.removeBreakpoint(w.getExecutableAddress());
deleted++;
}
}
}
JOptionPane.showMessageDialog(GUI.getTopParentContainer(),
"Deleted " + deleted + " breakpoints",
"Breakpoints deleted", JOptionPane.INFORMATION_MESSAGE);
configureWatchpointInfo(selectedWatchpoint);
}
};
}

View file

@ -34,32 +34,33 @@ package se.sics.cooja.mspmote.plugins;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Vector;
import java.util.HashMap;
import javax.swing.AbstractListModel;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JEditorPane;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
import javax.swing.ListCellRenderer;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Highlighter;
import javax.swing.text.Highlighter.HighlightPainter;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.components.Markers.SimpleMarker;
import org.apache.log4j.Logger;
import se.sics.mspsim.extutil.highlight.CScanner;
import se.sics.mspsim.extutil.highlight.Token;
import se.sics.mspsim.extutil.highlight.TokenTypes;
import se.sics.cooja.Watchpoint;
import se.sics.cooja.WatchpointMote;
import se.sics.cooja.util.JSyntaxAddBreakpoint;
import se.sics.cooja.util.JSyntaxRemoveBreakpoint;
import se.sics.cooja.util.StringUtils;
/**
* Displays source code and allows a user to add and remove breakpoints.
@ -69,184 +70,231 @@ import se.sics.mspsim.extutil.highlight.TokenTypes;
public class CodeUI extends JPanel {
private static Logger logger = Logger.getLogger(CodeUI.class);
private JPanel panel = null;
private JList codeList = null;
{
DefaultSyntaxKit.initKit();
}
private MspBreakpointContainer breakpoints = null;
private JEditorPane codeEditor = null;
private HashMap<Integer, Integer> codeEditorLines = null;
protected File displayedFile = null;
private Token tokensArray[][] = null;
private int tokensStartPos[] = null;
private static final HighlightPainter CURRENT_LINE_MARKER = new SimpleMarker(Color.ORANGE);
private static final HighlightPainter SELECTED_LINE_MARKER = new SimpleMarker(Color.GREEN);
private static final HighlightPainter BREAKPOINTS_MARKER = new SimpleMarker(Color.LIGHT_GRAY);
private final Object currentLineTag;
private final Object selectedLineTag;
private final ArrayList<Object> breakpointsLineTags = new ArrayList<Object>();
/**
* @param breakpoints Breakpoints
*/
public CodeUI(MspBreakpointContainer breakpoints) {
this.breakpoints = breakpoints;
private JSyntaxAddBreakpoint actionAddBreakpoint = null;
private JSyntaxRemoveBreakpoint actionRemoveBreakpoint = null;
private WatchpointMote mote;
public CodeUI(WatchpointMote mote) {
this.mote = mote;
{
/* Workaround to configure jsyntaxpane */
JEditorPane e = new JEditorPane();
new JScrollPane(e);
e.setContentType("text/c");
DefaultSyntaxKit kit = (DefaultSyntaxKit) e.getEditorKit();
kit.setProperty("Action.addbreakpoint", JSyntaxAddBreakpoint.class.getName());
kit.setProperty("Action.removebreakpoint", JSyntaxRemoveBreakpoint.class.getName());
kit.setProperty("PopupMenu", "copy-to-clipboard,-,find,find-next,goto-line,-,addbreakpoint,removebreakpoint");
}
setLayout(new BorderLayout());
codeEditor = new JEditorPane();
add(new JScrollPane(codeEditor), BorderLayout.CENTER);
doLayout();
panel = new JPanel(new BorderLayout());
add(panel, BorderLayout.CENTER);
displayNoCode();
codeEditorLines = new HashMap<Integer, Integer>();
codeEditor.setContentType("text/c");
DefaultSyntaxKit kit = (DefaultSyntaxKit) codeEditor.getEditorKit();
kit.setProperty("Action.addbreakpoint", JSyntaxAddBreakpoint.class.getName());
kit.setProperty("Action.removebreakpoint", JSyntaxRemoveBreakpoint.class.getName());
kit.setProperty("PopupMenu", "copy-to-clipboard,-,find,find-next,goto-line,-,addbreakpoint,removebreakpoint");
breakpoints.addWatchpointListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
/* Only update code list if simulation is not running */
if (CodeUI.this.breakpoints.getMote().getSimulation().isRunning() ||
CodeUI.this.breakpoints.getLastWatchpoint() != null) {
JPopupMenu p = codeEditor.getComponentPopupMenu();
for (Component c: p.getComponents()) {
if (c instanceof JMenuItem) {
if (((JMenuItem) c).getAction() != null &&
((JMenuItem) c).getAction() instanceof JSyntaxAddBreakpoint) {
actionAddBreakpoint = (JSyntaxAddBreakpoint)(((JMenuItem) c).getAction());
actionAddBreakpoint.setMenuText("Add breakpoint");
}
if (((JMenuItem) c).getAction() != null &&
((JMenuItem) c).getAction() instanceof JSyntaxRemoveBreakpoint) {
actionRemoveBreakpoint = (JSyntaxRemoveBreakpoint)(((JMenuItem) c).getAction());
actionRemoveBreakpoint.setMenuText("Remove breakpoint");
}
}
}
codeEditor.setText("");
codeEditorLines.clear();
codeEditor.setEditable(false);
Highlighter hl = codeEditor.getHighlighter();
Object o = null;
try {
o = hl.addHighlight(0, 0, CURRENT_LINE_MARKER);
} catch (BadLocationException e1) {
}
currentLineTag = o;
o = null;
try {
o = hl.addHighlight(0, 0, SELECTED_LINE_MARKER);
} catch (BadLocationException e1) {
}
selectedLineTag = o;
codeEditor.getComponentPopupMenu().addPopupMenuListener(new PopupMenuListener() {
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
/* Disable breakpoint actions */
actionAddBreakpoint.setEnabled(false);
actionRemoveBreakpoint.setEnabled(false);
int line = getCodeEditorMouseLine();
if (line < 1) {
return;
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (codeList != null) {
codeList.updateUI();
}
}
});
/* Configure breakpoint menu options */
Integer address =
CodeUI.this.mote.getExecutableAddressOf(displayedFile, line);
if (address == null) {
return;
}
final int start = codeEditorLines.get(line);
int end = codeEditorLines.get(line+1);
Highlighter hl = codeEditor.getHighlighter();
try {
hl.changeHighlight(selectedLineTag, start, end);
} catch (BadLocationException e1) {
}
boolean hasBreakpoint =
CodeUI.this.mote.breakpointExists(address);
if (!hasBreakpoint) {
actionAddBreakpoint.setEnabled(true);
actionAddBreakpoint.putValue("WatchpointMote", CodeUI.this.mote);
actionAddBreakpoint.putValue("WatchpointFile", displayedFile);
actionAddBreakpoint.putValue("WatchpointLine", new Integer(line));
actionAddBreakpoint.putValue("WatchpointAddress", new Integer(address));
} else {
actionRemoveBreakpoint.setEnabled(true);
actionRemoveBreakpoint.putValue("WatchpointMote", CodeUI.this.mote);
actionRemoveBreakpoint.putValue("WatchpointFile", displayedFile);
actionRemoveBreakpoint.putValue("WatchpointLine", new Integer(line));
actionRemoveBreakpoint.putValue("WatchpointAddress", new Integer(address));
}
}
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
Highlighter hl = codeEditor.getHighlighter();
try {
hl.changeHighlight(selectedLineTag, 0, 0);
} catch (BadLocationException e1) {
}
}
public void popupMenuCanceled(PopupMenuEvent e) {
}
});
displayNoCode(true);
}
public void updateBreakpoints() {
Highlighter hl = codeEditor.getHighlighter();
for (Object breakpointsLineTag: breakpointsLineTags) {
hl.removeHighlight(breakpointsLineTag);
}
breakpointsLineTags.clear();
for (Watchpoint w: mote.getBreakpoints()) {
if (!w.getCodeFile().equals(displayedFile)) {
continue;
}
final int start = codeEditorLines.get(w.getLineNumber());
int end = codeEditorLines.get(w.getLineNumber()+1);
try {
breakpointsLineTags.add(hl.addHighlight(start, end, BREAKPOINTS_MARKER));
} catch (BadLocationException e1) {
}
}
}
private int getCodeEditorMouseLine() {
if (codeEditorLines == null) {
return -1;
}
Point mousePos = codeEditor.getMousePosition();
if (mousePos == null) {
return -1;
}
int modelPos = codeEditor.viewToModel(mousePos);
int line = 1;
while (codeEditorLines.containsKey(line+1)) {
int next = codeEditorLines.get(line+1);
if (modelPos < next) {
return line;
}
line++;
}
return -1;
}
/**
* Remove any shown source code.
*/
public void displayNoCode() {
// Display "no code" message
public void displayNoCode(final boolean markCurrent) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
panel.removeAll();
panel.repaint();
displayedFile = null;
codeEditor.setText(null);
codeEditorLines.clear();
displayLine(-1, markCurrent);
}
});
displayedFile = null;
return;
}
private void createTokens(String[] codeData) {
/* Merge code lines */
StringBuilder sb = new StringBuilder();
for (String line: codeData) {
sb.append(line);
sb.append('\n');
}
String code = sb.toString();
/* Scan code */
CScanner cScanner = new CScanner();
cScanner.change(0, 0, code.length());
int nrTokens;
nrTokens = cScanner.scan(code.toCharArray(), 0, code.length());
/* Extract tokens */
ArrayList<Token> codeTokensVector = new ArrayList<Token>();
for (int i=0; i < nrTokens; i++) {
Token token = cScanner.getToken(i);
codeTokensVector.add(token);
}
/* Create new line token array */
Token newTokensArray[][] = new Token[codeData.length][];
int[] newTokensStartPos = new int[codeData.length];
int lineStart=0, lineEnd=-1;
Iterator<Token> tokens = codeTokensVector.iterator();
Token currentToken = tokens.next();
for (int i=0; i < newTokensArray.length; i++) {
lineStart = lineEnd + 1;
lineEnd = lineStart + codeData[i].length();
newTokensStartPos[i] = lineStart;;
/* Advance tokens until correct line */
while (currentToken.position + currentToken.symbol.name.length() < lineStart) {
if (!tokens.hasNext()) {
break;
}
currentToken = tokens.next();
}
/* Advance tokens until last token on line */
Vector<Token> lineTokens = new Vector<Token>();
while (currentToken.position < lineEnd) {
lineTokens.add(currentToken);
if (!tokens.hasNext()) {
break;
}
currentToken = tokens.next();
}
if (currentToken == null) {
break;
}
/* Store line tokens */
Token[] lineTokensArray = new Token[lineTokens.size()];
for (int j=0; j < lineTokens.size(); j++) {
lineTokensArray[j] = lineTokens.get(j);
}
newTokensArray[i] = lineTokensArray;
}
/* Start using tokens array */
tokensArray = newTokensArray;
tokensStartPos = newTokensStartPos;
}
/**
* Display given source code and mark given line.
*
* @param codeFile Source code file
* @param codeData Source code
* @param lineNr Line numer
*/
public void displayNewCode(File codeFile, String[] codeData, final int lineNr) {
displayedFile = codeFile;
public void displayNewCode(final File codeFile, final int lineNr, final boolean markCurrent) {
if (!codeFile.equals(displayedFile)) {
/* Read from disk */
final String data = StringUtils.loadFromFile(codeFile);
if (data == null || data.length() == 0) {
displayNoCode(markCurrent);
return;
}
if (codeData == null || codeData.length == 0) {
displayNoCode();
return;
String[] lines = data.split("\n");
logger.info("Opening " + codeFile + " (" + lines.length + " lines)");
int length = 0;
codeEditorLines.clear();
for (int line=1; line-1 < lines.length; line++) {
codeEditorLines.put(line, length);
length += lines[line-1].length()+1;
}
codeEditor.setText(data.toString());
displayedFile = codeFile;
updateBreakpoints();
}
logger.info("Opening " + codeFile + " (" + codeData.length + " lines)");
/* Create new list */
final JList newList = new JList(new CodeListModel(codeData));
newList.setBackground(Color.WHITE);
newList.setFont(new Font("courier", 0, 12));
newList.setCellRenderer(new CodeCellRenderer(lineNr));
((CodeCellRenderer)newList.getCellRenderer()).setNice(false);
newList.setFixedCellHeight(12);
newList.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
handleMouseEvent(e);
}
public void mouseReleased(MouseEvent e) {
handleMouseEvent(e);
}
public void mouseEntered(MouseEvent e) {
handleMouseEvent(e);
}
public void mouseExited(MouseEvent e) {
handleMouseEvent(e);
}
public void mouseClicked(MouseEvent e) {
handleMouseEvent(e);
}
});
createTokens(codeData);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
panel.removeAll();
codeList = newList;
panel.add(codeList);
panel.validate();
displayLine(lineNr);
displayLine(lineNr, markCurrent);
}
});
}
/**
@ -255,290 +303,35 @@ public class CodeUI extends JPanel {
*
* @param lineNumber Line number
*/
public void displayLine(int lineNumber) {
if (codeList == null) {
return;
}
((CodeCellRenderer) codeList.getCellRenderer()).setNice(false);
((CodeCellRenderer) codeList.getCellRenderer()).changeCurrentLine(lineNumber);
((CodeCellRenderer) codeList.getCellRenderer()).validate();
if (lineNumber > 0) {
int index = lineNumber - 1;
codeList.setSelectedIndex(index);
codeList.ensureIndexIsVisible(Math.max(0, index-3));
codeList.ensureIndexIsVisible(Math.min(index+3, codeList.getModel().getSize()));
codeList.ensureIndexIsVisible(index);
}
codeList.updateUI();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
((CodeCellRenderer) codeList.getCellRenderer()).setNice(true);
codeList.repaint();
}
});
}
private void handleMouseEvent(MouseEvent event) {
if (event.isPopupTrigger()) {
Point menuLocation = codeList.getPopupLocation(event);
if (menuLocation == null) {
menuLocation = new Point(
codeList.getLocationOnScreen().x + event.getX(),
codeList.getLocationOnScreen().y + event.getY());
private void displayLine(int lineNumber, boolean markCurrent) {
try {
if (markCurrent) {
/* remove previous highlight */
Highlighter hl = codeEditor.getHighlighter();
hl.changeHighlight(currentLineTag, 0, 0);
}
final int currentLine = codeList.locationToIndex(new Point(event.getX(), event.getY())) + 1;
codeList.setSelectedIndex(currentLine - 1);
JPopupMenu popupMenu = createPopupMenu(displayedFile, currentLine);
popupMenu.setLocation(menuLocation);
popupMenu.setInvoker(codeList);
popupMenu.setVisible(true);
}
}
private JPopupMenu createPopupMenu(final File codeFile, final int lineNr) {
final Integer executableAddress = breakpoints.getExecutableAddressOf(codeFile, lineNr);
boolean breakpointExists = breakpoints.breakpointExists(codeFile, lineNr);
JPopupMenu menuMotePlugins = new JPopupMenu();
JMenuItem headerMenuItem = new JMenuItem("Breakpoints:");
headerMenuItem.setEnabled(false);
menuMotePlugins.add(headerMenuItem);
menuMotePlugins.add(new JSeparator());
JMenuItem addBreakpointMenuItem = new JMenuItem("Add breakpoint on line " + lineNr);
if (executableAddress == null || breakpointExists) {
addBreakpointMenuItem.setEnabled(false);
} else {
addBreakpointMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
breakpoints.addBreakpoint(codeFile, lineNr, executableAddress);
if (lineNumber >= 0) {
final int start = codeEditorLines.get(lineNumber);
int end = codeEditorLines.get(lineNumber+1);
if (markCurrent) {
/* highlight code */
Highlighter hl = codeEditor.getHighlighter();
hl.changeHighlight(currentLineTag, start, end);
}
});
}
menuMotePlugins.add(addBreakpointMenuItem);
JMenuItem delBreakpointMenuItem = new JMenuItem("Delete breakpoint on line " + lineNr);
if (executableAddress == null || !breakpointExists) {
delBreakpointMenuItem.setEnabled(false);
} else {
delBreakpointMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
breakpoints.removeBreakpoint(executableAddress);
}
});
}
menuMotePlugins.add(delBreakpointMenuItem);
return menuMotePlugins;
}
private class CodeListModel extends AbstractListModel {
private String[] codeData;
public CodeListModel(String[] codeData) {
super();
this.codeData = codeData;
}
public int getSize() {
if (codeData == null || codeData.length == 0) {
return 0;
}
return codeData.length;
}
public Object getElementAt(int index) {
if (codeData == null || codeData.length == 0) {
return "No code to display";
}
return codeData[index];
}
}
/* FROM: http://www.rgagnon.com/javadetails/java-0306.html, 03/19/2008 */
private static String stringToHTMLString(String string) {
StringBuffer sb = new StringBuffer(string.length());
boolean lastWasBlankChar = false;
int len = string.length();
char c;
for (int i = 0; i < len; i++)
{
c = string.charAt(i);
if (c == ' ') {
if (lastWasBlankChar) {
lastWasBlankChar = false;
sb.append("&nbsp;");
}
else {
lastWasBlankChar = true;
sb.append(' ');
}
}
else {
lastWasBlankChar = false;
//
// HTML Special Chars
if (c == '"') {
sb.append("&quot;");
} else if (c == '&') {
sb.append("&amp;");
} else if (c == '<') {
sb.append("&lt;");
} else if (c == '>') {
sb.append("&gt;");
} else if (c == '\n') {
// Handle Newline
sb.append("&lt;br/&gt;");
} else {
int ci = 0xffff & c;
if (ci < 160 ) {
// nothing special only 7 Bit
sb.append(c);
} else {
// Not 7 Bit use the unicode system
sb.append("&#");
sb.append(new Integer(ci).toString());
sb.append(';');
/* ensure visible */
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
codeEditor.scrollRectToVisible(codeEditor.modelToView(start));
} catch (BadLocationException e) {
}
}
}
});
}
} catch (Exception e) {
logger.warn("Error when highlighting current line: " + e.getMessage(), e);
}
return sb.toString();
}
private class CodeCellRenderer extends JLabel implements ListCellRenderer {
private int currentIndex;
private boolean nice = true;
public CodeCellRenderer(int currentLineNr) {
this.currentIndex = currentLineNr - 1;
}
public void setNice(boolean b) {
nice = b;
}
public void changeCurrentLine(int currentLineNr) {
this.currentIndex = currentLineNr - 1;
}
private String getColoredLabelText(int lineNr, int lineStartPos, Token[] tokens, String code) {
StringBuilder sb = new StringBuilder();
sb.append("<html>");
/* Add line number */
String lineString = "0000" + Integer.toString(lineNr);
lineString = lineString.substring(lineString.length() - 4);
sb.append("<font color=\"333333\">");
sb.append(lineString);
sb.append(": </font>");
/* Add code */
if (tokens == null || tokens.length == 0 || lineStartPos < 0) {
sb.append("<font color=\"000000\">");
sb.append(code);
sb.append("</font>");
} else {
for (int i=tokens.length-1; i >= 0; i--) {
Token subToken = tokens[i];
String colorString = "000000";
/* Determine code color */
final int type = subToken.symbol.type;
switch (type) {
case TokenTypes.COMMENT:
case TokenTypes.START_COMMENT:
case TokenTypes.MID_COMMENT:
case TokenTypes.END_COMMENT:
colorString = "00AA00";
break;
case TokenTypes.STRING:
colorString = "0000AA";
break;
case TokenTypes.KEYWORD:
case TokenTypes.KEYWORD2:
colorString = "AA0000";
break;
}
/* Extract part of token residing in current line */
int tokenLinePos;
String subCode;
if (subToken.position < lineStartPos) {
subCode = subToken.symbol.name.substring(lineStartPos - subToken.position);
tokenLinePos = 0;
} else if (subToken.position + subToken.symbol.name.length() > lineStartPos + code.length()) {
subCode = subToken.symbol.name.substring(0, code.length() + lineStartPos - subToken.position);
tokenLinePos = subToken.position - lineStartPos;
} else {
subCode = subToken.symbol.name;
tokenLinePos = subToken.position - lineStartPos;
}
subCode = stringToHTMLString(subCode);
String firstPart = code.substring(0, tokenLinePos);
String coloredSubCode = "<font color=\"" + colorString + "\">" + subCode + "</font>";
String lastPart =
tokenLinePos + subToken.symbol.name.length() >= code.length()?
"":code.substring(tokenLinePos + subToken.symbol.name.length());
code = firstPart + coloredSubCode + lastPart;
}
code = code.replace(" ", " &nbsp;");
sb.append(code);
}
sb.append("</html>");
return sb.toString();
}
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus)
{
int lineNr = index + 1;
if (!nice) {
setText((String) value);
} else if (tokensArray != null && index < tokensArray.length && tokensArray[index] != null) {
setText(getColoredLabelText(lineNr, tokensStartPos[index], tokensArray[index], (String) value));
} else {
setText(getColoredLabelText(lineNr, 0, null, (String) value));
}
if (index == currentIndex) {
setBackground(Color.green);
} else if (isSelected) {
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
} else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
setEnabled(list.isEnabled());
if (breakpoints.breakpointExists(displayedFile, lineNr)) {
setFont(list.getFont().deriveFont(Font.BOLD));
} else {
setFont(list.getFont());
}
setOpaque(true);
return this;
}
}
}

View file

@ -34,129 +34,151 @@ package se.sics.cooja.mspmote.plugins;
import java.awt.Color;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Vector;
import org.apache.log4j.Logger;
import org.jdom.Element;
import se.sics.cooja.Watchpoint;
import se.sics.cooja.mspmote.MspMote;
import se.sics.cooja.util.StringUtils;
import se.sics.mspsim.core.CPUMonitor;
/**
* Breakpoint.
* Contains meta data such source code file and line number.
* Mspsim watchpoint.
*
* @author Fredrik Osterlind
*/
public class MspBreakpoint implements Watchpoint {
private static Logger logger = Logger.getLogger(MspBreakpoint.class);
private MspBreakpointContainer breakpoints;
private MspMote mspMote;
private int address = -1; /* Binary address */
private File codeFile = null; /* Source code, may be null*/
private int lineNr = -1; /* Source code line number, may be null */
private CPUMonitor cpuMonitor = null;
private boolean stopsSimulation = true;
private Integer address = null; /* Binary address */
private File codeFile = null; /* Source code, may be null*/
private Integer lineNr = null; /* Source code line number, may be null */
private String msg = null;
private Color color = Color.BLACK;
public MspBreakpoint(MspBreakpointContainer breakpoints, MspMote mote) {
this.breakpoints = breakpoints;
private String contikiCode = null;
public MspBreakpoint(MspMote mote) {
this.mspMote = mote;
/* expects setConfigXML(..) */
}
public MspBreakpoint(MspBreakpointContainer breakpoints, MspMote mote, Integer address) {
this(breakpoints, mote);
public MspBreakpoint(MspMote mote, Integer address, File codeFile, Integer lineNr) {
this(mote);
this.address = address;
this.codeFile = codeFile;
this.lineNr = lineNr;
createMonitor();
}
public MspBreakpoint(MspBreakpointContainer breakpoints, MspMote mote, Integer address, File codeFile, Integer lineNr) {
this(breakpoints, mote, address);
this.codeFile = codeFile;
this.lineNr = lineNr;
}
/**
* @return MSP mote
*/
public MspMote getMote() {
return mspMote;
}
/**
* @return Executable address
*/
public Integer getExecutableAddress() {
return address;
public Color getColor() {
return color;
}
/**
* @return Source code file
*/
public void setColor(Color color) {
this.color = color;
}
public String getDescription() {
String desc = "";
if (codeFile != null) {
desc += codeFile.getPath() + ":" + lineNr + " (0x" + Integer.toHexString(address) + ")";
} else if (address >= 0) {
desc += "0x" + Integer.toHexString(address);
}
if (msg != null) {
desc += "\n\n" + msg;
}
return desc;
}
public void setUserMessage(String msg) {
this.msg = msg;
}
public String getUserMessage() {
return msg;
}
public File getCodeFile() {
return codeFile;
}
/**
* @return Source code file line number
*/
public Integer getLineNumber() {
public int getLineNumber() {
return lineNr;
}
public boolean stopsSimulation() {
return stopsSimulation;
public int getExecutableAddress() {
return address;
}
public void setStopsSimulation(boolean stops) {
stopsSimulation = stops;
}
public boolean stopsSimulation() {
return stopsSimulation;
}
private void createMonitor() {
cpuMonitor = new CPUMonitor() {
public void cpuAction(int type, int adr, int data) {
breakpoints.signalBreakpointTrigger(MspBreakpoint.this);
if (type != CPUMonitor.EXECUTE) {
return;
}
mspMote.signalBreakpointTrigger(MspBreakpoint.this);
}
};
mspMote.getCPU().addWatchPoint(address, cpuMonitor);
/* Remember Contiki code, to verify it when reloaded */
if (contikiCode == null) {
final String code = StringUtils.loadFromFile(codeFile);
if (code != null) {
String[] lines = code.split("\n");
if (lineNr-1 < lines.length) {
contikiCode = lines[lineNr-1].trim();
}
}
}
}
public void unregisterBreakpoint() {
mspMote.getCPU().removeWatchPoint(address, cpuMonitor);
}
public Collection<Element> getConfigXML() {
Vector<Element> config = new Vector<Element>();
ArrayList<Element> config = new ArrayList<Element>();
Element element;
element = new Element("address");
element.setText(address.toString());
config.add(element);
element = new Element("stops");
element.setText("" + stopsSimulation);
config.add(element);
if (codeFile != null) {
element = new Element("codefile");
File file = mspMote.getSimulation().getGUI().createPortablePath(codeFile);
element.setText(file.getPath().replaceAll("\\\\", "/"));
config.add(element);
}
element = new Element("codefile");
File file = mspMote.getSimulation().getGUI().createPortablePath(codeFile);
element.setText(file.getPath().replaceAll("\\\\", "/"));
config.add(element);
if (lineNr != null) {
element = new Element("line");
element.setText(lineNr.toString());
element = new Element("line");
element.setText("" + lineNr);
config.add(element);
if (contikiCode != null) {
element = new Element("contikicode");
element.setText(contikiCode);
config.add(element);
}
@ -177,7 +199,7 @@ public class MspBreakpoint implements Watchpoint {
public boolean setConfigXML(Collection<Element> configXML, boolean visAvailable) {
/* Already knows mote and breakpoints */
for (Element element : configXML) {
if (element.getName().equals("codefile")) {
File file = new File(element.getText());
@ -193,8 +215,23 @@ public class MspBreakpoint implements Watchpoint {
}
} else if (element.getName().equals("line")) {
lineNr = Integer.parseInt(element.getText());
} else if (element.getName().equals("address")) {
address = Integer.parseInt(element.getText());
} else if (element.getName().equals("contikicode")) {
String lastContikiCode = element.getText().trim();
/* Verify that Contiki code did not change */
final String code = StringUtils.loadFromFile(codeFile);
if (code != null) {
String[] lines = code.split("\n");
if (lineNr-1 < lines.length) {
contikiCode = lines[lineNr-1].trim();
}
}
if (!lastContikiCode.equals(contikiCode)) {
logger.warn("Detected modified Contiki code at breakpoint: " + codeFile.getPath() + ":" + lineNr + ".");
logger.warn("From: '" + lastContikiCode + "'");
logger.warn(" To: '" + contikiCode + "'");
}
} else if (element.getName().equals("msg")) {
msg = element.getText();
} else if (element.getName().equals("color")) {
@ -204,51 +241,18 @@ public class MspBreakpoint implements Watchpoint {
}
}
if (address == null) {
/* Update executable address */
address = mspMote.getExecutableAddressOf(codeFile, lineNr);
if (address < 0) {
logger.fatal("Could not restore breakpoint, did source code change?");
return false;
}
/* TODO Save source code line */
if (codeFile != null && lineNr != null) {
/* Update executable address */
address = mspMote.getBreakpointsContainer().getExecutableAddressOf(codeFile, lineNr);
if (address == null) {
logger.fatal("Could not restore breakpoint, did source code change?");
address = 0;
}
}
createMonitor();
return true;
}
public void setUserMessage(String msg) {
this.msg = msg;
public String toString() {
return getMote() + ": " + getDescription();
}
public String getUserMessage() {
return msg;
}
public void setColor(Color color) {
this.color = color;
}
public String getDescription() {
String desc = "";
if (codeFile != null) {
desc += codeFile.getPath() + ":" + lineNr + " (0x" + Integer.toHexString(address.intValue()) + ")";
} else if (address != null) {
desc += "0x" + Integer.toHexString(address.intValue());
}
if (msg != null) {
desc += "\n\n" + msg;
}
return desc;
}
public Color getColor() {
return color;
}
}

View file

@ -1,280 +0,0 @@
/*
* Copyright (c) 2009, 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: MspBreakpointContainer.java,v 1.3 2010/01/21 22:32:32 fros4943 Exp $
*/
package se.sics.cooja.mspmote.plugins;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import org.apache.log4j.Logger;
import org.jdom.Element;
import se.sics.cooja.WatchpointMote;
import se.sics.cooja.mspmote.MspMote;
/**
* Breakpoint collection
*
* @author Fredrik Osterlind
*/
public class MspBreakpointContainer implements WatchpointMote {
private static Logger logger = Logger.getLogger(MspBreakpointContainer.class);
private Hashtable<File, Hashtable<Integer, Integer>> debuggingInfo = null;
private MspMote mspMote;
private ArrayList<MspBreakpoint> breakpoints = new ArrayList<MspBreakpoint>();
private ArrayList<ActionListener> listeners = new ArrayList<ActionListener>();
private MspBreakpoint lastTriggeredBreakpoint = null;
/**
* @param debuggingInfo Debugging information read from firmware file
* @param mote Mote
*/
public MspBreakpointContainer(MspMote mote, Hashtable<File, Hashtable<Integer, Integer>> debuggingInfo) {
this.mspMote = mote;
this.debuggingInfo = debuggingInfo;
}
/**
* Add breakpoint at given address.
*
* @param address Executable address
*/
public void addBreakpoint(Integer address) {
addBreakpoint((File) null, (Integer) null, address);
}
/**
* Add breakpoint at given address with given meta data.
*
* @param codeFile Source code file
* @param lineNr Source code file line number
* @param address Executable address
* @return Added breakpoint
*/
public MspBreakpoint addBreakpoint(File codeFile, int lineNr, Integer address) {
MspBreakpoint bp = new MspBreakpoint(this, mspMote, address, codeFile, new Integer(lineNr));
breakpoints.add(bp);
/* Notify listeners */
lastTriggeredBreakpoint = null;
for (ActionListener listener: listeners) {
listener.actionPerformed(null);
}
return bp;
}
/**
* Remove breakpoint at given address.
*
* @param address Executable address
*/
public MspBreakpoint removeBreakpoint(Integer address) {
MspBreakpoint breakpointToRemove = null;
for (MspBreakpoint breakpoint: breakpoints) {
if (breakpoint.getExecutableAddress().intValue() == address.intValue()) {
breakpointToRemove = breakpoint;
break;
}
}
if (breakpointToRemove == null) {
return null;
}
breakpointToRemove.unregisterBreakpoint();
breakpoints.remove(breakpointToRemove);
/* Notify listeners */
lastTriggeredBreakpoint = null;
for (ActionListener listener: listeners) {
listener.actionPerformed(null);
}
return breakpointToRemove;
}
/**
* Checks if a breakpoint exists at given address.
*
* @param address Executable address
* @return True if breakpoint exists, false otherwise
*/
public boolean breakpointExists(Integer address) {
if (address == null) {
return false;
}
for (MspBreakpoint breakpoint: breakpoints) {
if (breakpoint.getExecutableAddress().intValue() == address.intValue()) {
return true;
}
}
return false;
}
public boolean breakpointExists(File file, int lineNr) {
for (MspBreakpoint breakpoint: breakpoints) {
if (breakpoint.getCodeFile() == null) {
continue;
}
if (breakpoint.getCodeFile().compareTo(file) != 0) {
continue;
}
if (breakpoint.getLineNumber().intValue() != lineNr) {
continue;
}
return true;
}
return false;
}
/**
* @return All breakpoints
*/
public MspBreakpoint[] getBreakpoints() {
return breakpoints.toArray(new MspBreakpoint[0]);
}
public int getBreakpointsCount() {
return breakpoints.size();
}
public void addWatchpointListener(ActionListener listener) {
listeners.add(listener);
}
public void removeWatchpointListener(ActionListener listener) {
listeners.remove(listener);
}
public ActionListener[] getWatchpointListeners() {
return listeners.toArray(new ActionListener[0]);
}
protected void signalBreakpointTrigger(MspBreakpoint b) {
if (b.stopsSimulation() && mspMote.getSimulation().isRunning()) {
/* Stop simulation immediately */
mspMote.stopNextInstruction();
}
/* Notify listeners */
lastTriggeredBreakpoint = b;
ActionListener[] arr = getWatchpointListeners();
for (ActionListener listener: arr) {
listener.actionPerformed(null);
}
}
public MspMote getMote() {
return mspMote;
}
public MspBreakpoint getLastWatchpoint() {
return lastTriggeredBreakpoint;
}
/**
* Tries to calculate the executable address of given file.
* Using debugging information from firmware file,
*
* @param file Source code file
* @param lineNr Source code file line number
* @return Executable address or null if not found
*/
public Integer getExecutableAddressOf(File file, int lineNr) {
if (file == null || lineNr < 0 || debuggingInfo == null) {
return null;
}
/* Match file */
Hashtable<Integer, Integer> lineTable = debuggingInfo.get(file);
if (lineTable == null) {
Enumeration<File> fileEnum = debuggingInfo.keys();
while (fileEnum.hasMoreElements()) {
File f = fileEnum.nextElement();
if (f != null && f.getName().equals(file.getName())) {
lineTable = debuggingInfo.get(f);
break;
}
}
}
if (lineTable == null) {
return null;
}
/* Match line number */
Integer address = lineTable.get(lineNr);
if (address != null) {
Enumeration<Integer> lineEnum = lineTable.keys();
while (lineEnum.hasMoreElements()) {
Integer l = lineEnum.nextElement();
if (l != null && l.intValue() == lineNr) {
/* Found line address */
return lineTable.get(l);
}
}
}
return null;
}
public Collection<Element> getConfigXML() {
Vector<Element> config = new Vector<Element>();
Element element;
for (MspBreakpoint breakpoint: breakpoints) {
element = new Element("breakpoint");
element.addContent(breakpoint.getConfigXML());
config.add(element);
}
return config;
}
public boolean setConfigXML(Collection<Element> configXML, boolean visAvailable) {
for (Element element : configXML) {
if (element.getName().equals("breakpoint")) {
MspBreakpoint breakpoint = new MspBreakpoint(this, mspMote);
if (!breakpoint.setConfigXML(element.getChildren(), visAvailable)) {
logger.warn("Could not restore breakpoint: " + breakpoint);
} else {
breakpoints.add(breakpoint);
}
}
}
return true;
}
}

View file

@ -30,18 +30,16 @@
package se.sics.cooja.mspmote.plugins;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Observable;
import java.util.Observer;
import java.util.Vector;
import javax.swing.AbstractAction;
import javax.swing.Action;
@ -54,8 +52,7 @@ import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileFilter;
@ -72,11 +69,12 @@ import se.sics.cooja.MotePlugin;
import se.sics.cooja.PluginType;
import se.sics.cooja.Simulation;
import se.sics.cooja.VisPlugin;
import se.sics.cooja.Watchpoint;
import se.sics.cooja.WatchpointMote;
import se.sics.cooja.WatchpointMote.WatchpointListener;
import se.sics.cooja.mspmote.MspMote;
import se.sics.cooja.mspmote.MspMoteType;
import se.sics.cooja.util.StringUtils;
import se.sics.mspsim.core.EmulationException;
import se.sics.mspsim.core.MSP430;
import se.sics.mspsim.ui.DebugUI;
import se.sics.mspsim.util.DebugInfo;
import se.sics.mspsim.util.ELFDebug;
@ -85,25 +83,31 @@ import se.sics.mspsim.util.ELFDebug;
@PluginType(PluginType.MOTE_PLUGIN)
public class MspCodeWatcher extends VisPlugin implements MotePlugin {
private static final long serialVersionUID = -8463196456352243367L;
private static final int SOURCECODE = 0;
private static final int BREAKPOINTS = 2;
private static Logger logger = Logger.getLogger(MspCodeWatcher.class);
private Simulation simulation;
private Observer simObserver;
private MspMote mspMote;
private File currentCodeFile = null;
private int currentLineNumber = -1;
private JSplitPane leftSplitPane, rightSplitPane;
private DebugUI assCodeUI;
private CodeUI sourceCodeUI;
private BreakpointsUI breakpointsUI;
private MspBreakpointContainer breakpoints = null;
private MspMote mspMote; /* currently the only supported mote */
private WatchpointMote watchpointMote;
private WatchpointListener watchpointListener;
private JComboBox fileComboBox;
private String[] debugInfoMap = null;
private File[] sourceFiles;
private JTabbedPane mainPane;
/**
* Mini-debugger for MSP Motes.
* Visualizes instructions, source code and allows a user to manipulate breakpoints.
@ -113,15 +117,13 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
* @param gui Simulator
*/
public MspCodeWatcher(Mote mote, Simulation simulationToVisualize, GUI gui) {
super("Msp Code Watcher", gui);
this.mspMote = (MspMote) mote;
super("Msp Code Watcher - " + mote, gui);
simulation = simulationToVisualize;
this.mspMote = (MspMote) mote;
this.watchpointMote = (WatchpointMote) mote;
getContentPane().setLayout(new BorderLayout());
/* Breakpoints */
breakpoints = mspMote.getBreakpointsContainer();
/* Create source file list */
fileComboBox = new JComboBox();
fileComboBox.addActionListener(new ActionListener() {
@ -149,58 +151,68 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
}
});
updateFileComboBox();
/* Browse code control (north) */
JButton currentFileButton = new JButton(currentFileAction);
JButton mapButton = new JButton(mapAction);
Box browseBox = Box.createHorizontalBox();
browseBox.add(Box.createHorizontalStrut(10));
browseBox.add(new JLabel("Program counter: "));
browseBox.add(currentFileButton);
browseBox.add(Box.createHorizontalGlue());
browseBox.add(new JLabel("Browse: "));
browseBox.add(fileComboBox);
browseBox.add(Box.createHorizontalStrut(10));
browseBox.add(mapButton);
browseBox.add(Box.createHorizontalStrut(10));
Box sourceCodeControl = Box.createHorizontalBox();
sourceCodeControl.add(new JButton(stepAction));
sourceCodeControl.add(Box.createHorizontalStrut(10));
sourceCodeControl.add(new JLabel("Current location: "));
sourceCodeControl.add(new JButton(currentFileAction));
sourceCodeControl.add(Box.createHorizontalGlue());
sourceCodeControl.add(new JLabel("Source files: "));
sourceCodeControl.add(fileComboBox);
sourceCodeControl.add(Box.createHorizontalStrut(5));
sourceCodeControl.add(new JButton(mapAction));
sourceCodeControl.add(Box.createHorizontalStrut(10));
/* Execution control panel (south) */
JPanel controlPanel = new JPanel();
JButton button = new JButton(stepAction);
controlPanel.add(button);
/* Execution control panel (south of source code panel) */
/* Layout */
mainPane = new JTabbedPane();
sourceCodeUI = new CodeUI(watchpointMote);
JPanel sourceCodePanel = new JPanel(new BorderLayout());
sourceCodePanel.add(BorderLayout.CENTER, sourceCodeUI);
sourceCodePanel.add(BorderLayout.SOUTH, sourceCodeControl);
mainPane.addTab("Source code", null, sourceCodePanel, null); /* SOURCECODE */
/* Main components: assembler and C code + breakpoints (center) */
assCodeUI = new DebugUI(this.mspMote.getCPU(), true);
breakpointsUI = new BreakpointsUI(breakpoints, this);
sourceCodeUI = new CodeUI(breakpoints);
leftSplitPane = new JSplitPane(
JSplitPane.HORIZONTAL_SPLIT,
new JScrollPane(assCodeUI),
new JScrollPane(breakpointsUI)
);
leftSplitPane.setOneTouchExpandable(true);
leftSplitPane.setDividerLocation(0.0);
rightSplitPane = new JSplitPane(
JSplitPane.HORIZONTAL_SPLIT,
leftSplitPane,
new JScrollPane(sourceCodeUI)
);
rightSplitPane.setOneTouchExpandable(true);
rightSplitPane.setDividerLocation(0.0);
for (Component c: assCodeUI.getComponents()) {
c.setBackground(Color.WHITE);
}
mainPane.addTab("Instructions", null, assCodeUI, null);
add(BorderLayout.NORTH, browseBox);
add(BorderLayout.CENTER, rightSplitPane);
add(BorderLayout.SOUTH, controlPanel);
breakpointsUI = new BreakpointsUI(mspMote, this);
mainPane.addTab("Breakpoints", null, breakpointsUI, "Right-click source code to add"); /* BREAKPOINTS */
add(BorderLayout.CENTER, mainPane);
/* Listen for breakpoint changes */
watchpointMote.addWatchpointListener(watchpointListener = new WatchpointListener() {
public void watchpointTriggered(final Watchpoint watchpoint) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
logger.info("Watchpoint triggered: " + watchpoint);
if (simulation.isRunning()) {
return;
}
breakpointsUI.selectBreakpoint(watchpoint);
sourceCodeUI.updateBreakpoints();
showCurrentPC();
}
});
}
public void watchpointsChanged() {
sourceCodeUI.updateBreakpoints();
}
});
/* Observe when simulation starts/stops */
simulation.addObserver(simObserver = new Observer() {
public void update(Observable obs, Object obj) {
if (!simulation.isRunning()) {
stepAction.setEnabled(true);
updateInfo();
showCurrentPC();
} else {
stepAction.setEnabled(false);
}
@ -208,7 +220,7 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
});
setSize(750, 500);
updateInfo();
showCurrentPC();
}
private void updateFileComboBox() {
@ -221,25 +233,12 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
fileComboBox.setSelectedIndex(0);
}
public void displaySourceFile(File file, final int line) {
if (file != null &&
sourceCodeUI.displayedFile != null &&
file.compareTo(sourceCodeUI.displayedFile) == 0) {
/* No need to reload source file */
SwingUtilities.invokeLater(new Runnable() {
public void run() {
sourceCodeUI.displayLine(line);
}
});
return;
}
/* Load source file from disk */
String[] codeData = readTextFile(file);
if (codeData == null) {
return;
}
sourceCodeUI.displayNewCode(file, codeData, line);
public void displaySourceFile(final File file, final int line, final boolean markCurrent) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
mainPane.setSelectedIndex(SOURCECODE); /* code */
sourceCodeUI.displayNewCode(file, line, markCurrent);
}});
}
private void sourceFileSelectionChanged() {
@ -249,32 +248,40 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
}
File selectedFile = sourceFiles[index-1];
displaySourceFile(selectedFile, -1);
displaySourceFile(selectedFile, -1, false);
}
private void updateInfo() {
private void showCurrentPC() {
/* Instructions */
assCodeUI.updateRegs();
assCodeUI.repaint();
/* Source */
updateCurrentSourceCodeFile();
if (currentCodeFile == null) {
File file = currentCodeFile;
Integer line = currentLineNumber;
if (file == null || line == null) {
currentFileAction.setEnabled(false);
currentFileAction.putValue(Action.NAME, "[unknown]");
currentFileAction.putValue(Action.SHORT_DESCRIPTION, null);
return;
}
currentFileAction.setEnabled(true);
currentFileAction.putValue(Action.NAME, currentCodeFile.getName() + ":" + currentLineNumber);
currentFileAction.putValue(Action.SHORT_DESCRIPTION, currentCodeFile.getAbsolutePath() + ":" + currentLineNumber);
fileComboBox.setSelectedItem(currentCodeFile.getName());
currentFileAction.putValue(Action.NAME, file.getName() + ":" + line);
currentFileAction.putValue(Action.SHORT_DESCRIPTION, file.getAbsolutePath() + ":" + line);
fileComboBox.setSelectedItem(file.getName());
displaySourceFile(currentCodeFile, currentLineNumber);
displaySourceFile(file, line, true);
}
public void closePlugin() {
watchpointMote.removeWatchpointListener(watchpointListener);
watchpointListener = null;
simulation.deleteObserver(simObserver);
simObserver = null;
/* TODO XXX Unregister breakpoints? */
}
private void updateCurrentSourceCodeFile() {
@ -285,8 +292,12 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
if (debug == null) {
return;
}
DebugInfo debugInfo = debug.getDebugInfo(mspMote.getCPU().reg[MSP430.PC]);
int pc = mspMote.getCPU().getPC();
DebugInfo debugInfo = debug.getDebugInfo(pc);
if (debugInfo == null) {
if (pc != 0) {
logger.warn("No sourcecode info at " + String.format("0x%04x", mspMote.getCPU().getPC()));
}
return;
}
@ -321,6 +332,7 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
private void tryMapDebugInfo() {
final String[] debugFiles;
try {
ELFDebug debug = ((MspMoteType)mspMote.getType()).getELF().getDebug();
debugFiles = debug != null ? debug.getSourceFiles() : null;
if (debugFiles == null) {
@ -343,7 +355,7 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
"\"Next File\" proceeds to the next source file in the debug info.\n\n" +
debugFiles[counter] + " (" + (counter+1) + '/' + debugFiles.length + ')',
"Select source file to locate", JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE, null,
JOptionPane.QUESTION_MESSAGE, null,
new String[] { "Next File", "Locate File", "Cancel"}, "Next File");
if (n == JOptionPane.CANCEL_OPTION || n == JOptionPane.CLOSED_OPTION) {
return null;
@ -421,14 +433,14 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
optionPane.setOptions(new String[] { "OK" });
optionPane.setInitialValue("OK");
JDialog dialog = optionPane.createDialog(
GUI.getTopParentContainer(),
"Mapping debug info to real sources");
GUI.getTopParentContainer(),
"Mapping debug info to real sources");
dialog.setVisible(true);
replace = replaceInput.getText();
replacement = replacementInput.getText();
}
replace = replace.replace('\\', '/');
replacement = replacement.replace('\\', '/');
return new String[] { replace, replacement };
@ -444,7 +456,7 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
updateFileComboBox();
}
}
private static File[] getSourceFiles(MspMote mote, String[] map) {
final String[] sourceFiles;
try {
@ -465,7 +477,7 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
} catch (IOException e1) {
}
}
/* Verify that files exist */
ArrayList<File> existing = new ArrayList<File>();
for (String sourceFile: sourceFiles) {
@ -512,7 +524,7 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
"Make sure the source files were not moved after the firmware compilation.\n" +
"\n" +
"If you want to manually locate the sources, click \"Map\" button.",
"No source files found",
"No source files found",
JOptionPane.WARNING_MESSAGE);
return true;
}
@ -530,7 +542,7 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
}
sorted.add(index, file);
}
/* Add Contiki source first */
if (contikiSource != null && contikiSource.exists()) {
sorted.add(0, contikiSource);
@ -539,63 +551,21 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
return sorted.toArray(new File[0]);
}
/**
* Tries to open and read given text file.
*
* @param file File
* @return Line-by-line text in file
*/
public static String[] readTextFile(File file) {
if (GUI.isVisualizedInApplet()) {
/* Download from web server instead */
String path = file.getPath();
/* Extract Contiki build path */
String contikiBuildPath = GUI.getExternalToolsSetting("PATH_CONTIKI_BUILD");
String contikiWebPath = GUI.getExternalToolsSetting("PATH_CONTIKI_WEB");
if (!path.startsWith(contikiBuildPath)) {
return null;
}
try {
/* Replace Contiki parent path with web server code base */
path = contikiWebPath + '/' + path.substring(contikiBuildPath.length());
path = path.replace('\\', '/');
URL url = new URL(GUI.getAppletCodeBase(), path);
String data = StringUtils.loadFromURL(url);
return data!=null?data.split("\n"):null;
} catch (MalformedURLException e) {
logger.warn("Failure to read source code: " + e);
return null;
}
}
String data = StringUtils.loadFromFile(file);
return data!=null?data.split("\n"):null;
}
public Collection<Element> getConfigXML() {
Vector<Element> config = new Vector<Element>();
ArrayList<Element> config = new ArrayList<Element>();
Element element;
element = new Element("split_1");
element.addContent("" + leftSplitPane.getDividerLocation());
element = new Element("tab");
element.addContent("" + mainPane.getSelectedIndex());
config.add(element);
element = new Element("split_2");
element.addContent("" + rightSplitPane.getDividerLocation());
config.add(element);
return config;
}
public boolean setConfigXML(Collection<Element> configXML, boolean visAvailable) {
for (Element element : configXML) {
if (element.getName().equals("split_1")) {
leftSplitPane.setDividerLocation(Integer.parseInt(element.getText()));
} else if (element.getName().equals("split_2")) {
rightSplitPane.setDividerLocation(Integer.parseInt(element.getText()));
if (element.getName().equals("tab")) {
mainPane.setSelectedIndex(Integer.parseInt(element.getText()));
}
}
return true;
@ -608,11 +578,11 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
if (currentCodeFile == null) {
return;
}
displaySourceFile(currentCodeFile, currentLineNumber);
displaySourceFile(currentCodeFile, currentLineNumber, true);
}
};
private AbstractAction mapAction = new AbstractAction("Map") {
private AbstractAction mapAction = new AbstractAction("Locate sources") {
private static final long serialVersionUID = -3929432830596292495L;
public void actionPerformed(ActionEvent e) {
@ -622,14 +592,13 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
private AbstractAction stepAction = new AbstractAction("Step instruction") {
private static final long serialVersionUID = 3520750710757816575L;
public void actionPerformed(ActionEvent e) {
try {
mspMote.getCPU().stepInstructions(1);
} catch (EmulationException ex) {
logger.fatal("Error: ", ex);
}
updateInfo();
showCurrentPC();
}
};

View file

@ -50,6 +50,7 @@ The COOJA Simulator
<pathelement path="${build}"/>
<pathelement location="lib/jdom.jar"/>
<pathelement location="lib/log4j.jar"/>
<pathelement location="lib/jsyntaxpane.jar"/>
</classpath>
</java>
</target>
@ -62,6 +63,7 @@ The COOJA Simulator
<classpath>
<pathelement location="lib/jdom.jar"/>
<pathelement location="lib/log4j.jar"/>
<pathelement location="lib/jsyntaxpane.jar"/>
</classpath>
</javadoc>
</target>
@ -74,6 +76,7 @@ The COOJA Simulator
<pathelement path="."/>
<pathelement location="lib/jdom.jar"/>
<pathelement location="lib/log4j.jar"/>
<pathelement location="lib/jsyntaxpane.jar"/>
</classpath>
</javac>
</target>
@ -104,6 +107,7 @@ The COOJA Simulator
<pathelement path="${build}"/>
<pathelement location="lib/jdom.jar"/>
<pathelement location="lib/log4j.jar"/>
<pathelement location="lib/jsyntaxpane.jar"/>
</classpath>
</java>
</target>
@ -118,6 +122,7 @@ The COOJA Simulator
<pathelement path="${build}"/>
<pathelement location="lib/jdom.jar"/>
<pathelement location="lib/log4j.jar"/>
<pathelement location="lib/jsyntaxpane.jar"/>
</classpath>
</java>
</target>
@ -131,6 +136,7 @@ The COOJA Simulator
<pathelement path="${build}"/>
<pathelement location="lib/jdom.jar"/>
<pathelement location="lib/log4j.jar"/>
<pathelement location="lib/jsyntaxpane.jar"/>
</classpath>
</java>
</target>
@ -144,6 +150,7 @@ The COOJA Simulator
<pathelement path="${build}"/>
<pathelement location="lib/jdom.jar"/>
<pathelement location="lib/log4j.jar"/>
<pathelement location="lib/jsyntaxpane.jar"/>
</classpath>
</java>
</target>
@ -156,6 +163,7 @@ The COOJA Simulator
<pathelement path="${build}"/>
<pathelement location="lib/jdom.jar"/>
<pathelement location="lib/log4j.jar"/>
<pathelement location="lib/jsyntaxpane.jar"/>
<pathelement location="../mspsim/lib/jfreechart-1.0.11.jar"/>
<pathelement location="../mspsim/lib/jcommon-1.0.14.jar"/>
</classpath>
@ -170,6 +178,7 @@ The COOJA Simulator
<pathelement path="${build}"/>
<pathelement location="lib/jdom.jar"/>
<pathelement location="lib/log4j.jar"/>
<pathelement location="lib/jsyntaxpane.jar"/>
</classpath>
</java>
</target>
@ -190,6 +199,7 @@ The COOJA Simulator
<pathelement path="${build}"/>
<pathelement location="lib/jdom.jar"/>
<pathelement location="lib/log4j.jar"/>
<pathelement location="lib/jsyntaxpane.jar"/>
</classpath>
</java>
</target>
@ -214,7 +224,7 @@ The COOJA Simulator
<jar destfile="${dist}/cooja.jar" basedir="${build}">
<manifest>
<attribute name="Main-Class" value="se.sics.cooja.GUI"/>
<attribute name="Class-Path" value=". lib/log4j.jar lib/jdom.jar"/>
<attribute name="Class-Path" value=". lib/log4j.jar lib/jdom.jar lib/jsyntaxpane.jar"/>
</manifest>
</jar>
<mkdir dir="${dist}/lib"/>

View file

@ -32,24 +32,26 @@
package se.sics.cooja;
import java.awt.Color;
import java.io.File;
/**
* @author Fredrik Osterlind
*/
public interface Watchpoint {
/**
* @return Short watchpoint description
*/
public String getDescription();
/**
* @return Mote
*/
public Mote getMote();
/**
* @return Color
*/
public WatchpointMote getMote();
public Color getColor();
public void setColor(Color newColor);
public String getDescription();
public void setUserMessage(String msg);
public String getUserMessage();
public File getCodeFile();
public int getLineNumber();
public int getExecutableAddress();
public void setStopsSimulation(boolean b);
public boolean stopsSimulation();
}

View file

@ -31,12 +31,17 @@
package se.sics.cooja;
import java.awt.event.ActionListener;
import java.io.File;
/**
* @author Fredrik Osterlind
*/
public interface WatchpointMote {
public interface WatchpointMote extends Mote {
public interface WatchpointListener {
public void watchpointTriggered(Watchpoint watchpoint);
public void watchpointsChanged();
}
/**
* Adds a breakpoint listener.
@ -44,28 +49,27 @@ public interface WatchpointMote {
*
* @param listener Action listener
*/
public void addWatchpointListener(ActionListener listener);
public void addWatchpointListener(WatchpointListener listener);
/**
* Removes previously registered listener.
*
*
* @param listener Listeners
*/
public void removeWatchpointListener(ActionListener listener);
public void removeWatchpointListener(WatchpointListener listener);
/**
* @return All registered listeners
*/
public ActionListener[] getWatchpointListeners();
public WatchpointListener[] getWatchpointListeners();
/**
* @return Last triggered watchpoint
*/
public Watchpoint getLastWatchpoint();
public Watchpoint addBreakpoint(File codeFile, int lineNr, int address);
public void removeBreakpoint(Watchpoint watchpoint);
public Watchpoint[] getBreakpoints();
/**
* @return Mote
*/
public Mote getMote();
public boolean breakpointExists(int address);
public boolean breakpointExists(File file, int lineNr);
public Integer getExecutableAddressOf(File file, int lineNr);
}

View file

@ -32,6 +32,7 @@
package se.sics.cooja.plugins;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Window;
@ -53,9 +54,12 @@ import java.util.Observer;
import javax.script.ScriptException;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JFileChooser;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
@ -63,8 +67,10 @@ import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileFilter;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.actions.DefaultSyntaxAction;
import org.apache.log4j.Logger;
import org.jdom.Element;
@ -83,6 +89,10 @@ public class ScriptRunner extends VisPlugin {
private static final long serialVersionUID = 7614358340336799109L;
private static Logger logger = Logger.getLogger(ScriptRunner.class);
{
DefaultSyntaxKit.initKit();
}
final String[] EXAMPLE_SCRIPTS = new String[] {
"basic.js", "Various commands",
"helloworld.js", "Wait for 'Hello, world'",
@ -97,24 +107,19 @@ public class ScriptRunner extends VisPlugin {
private static BufferedWriter logWriter = null; /* For non-GUI tests */
private JTextArea scriptTextArea = null;
private JEditorPane codeEditor = null;
private JTextArea logTextArea = null;
private JButton toggleButton = null;
private JButton examplesButton = null;
private int scriptFirstLinesNumber;
private JSyntaxLinkFile actionLinkFile = null;
private File linkedFile = null;
public ScriptRunner(Simulation simulation, GUI gui) {
super("Contiki Test Editor", gui, false);
this.simulation = simulation;
final JTextArea lineTextArea = new JTextArea();
lineTextArea.setEnabled(false);
lineTextArea.setMargin(new Insets(5,0,5,0));
scriptFirstLinesNumber = 1;
/* Examples popup menu */
final JPopupMenu popupMenu = new JPopupMenu();
JMenuItem moteItem;
@ -148,65 +153,19 @@ public class ScriptRunner extends VisPlugin {
}
});
{
/* Workaround to configure jsyntaxpane */
JEditorPane e = new JEditorPane();
new JScrollPane(e);
e.setContentType("text/javascript");
DefaultSyntaxKit kit = (DefaultSyntaxKit) e.getEditorKit();
kit.setProperty("PopupMenu", "copy-to-clipboard,-,find,find-next,goto-line,-,linkfile");
kit.setProperty("Action.linkfile", JSyntaxLinkFile.class.getName());
}
/* Script area */
scriptTextArea = new JTextArea(12,50);
scriptTextArea.getDocument().addDocumentListener(new DocumentListener() {
private int lastLines = -1;
private void update() {
int lines = scriptTextArea.getLineCount() + scriptFirstLinesNumber;
if (lines == lastLines) {
return;
}
lastLines = lines;
String txt = "";
for (int i=scriptFirstLinesNumber; i < 10; i++) {
if (i > lines) {
break;
}
txt += "00" + i + "\n";
}
for (int i=10; i < 100; i++) {
if (i > lines) {
break;
}
txt += "0" + i + "\n";
}
for (int i=100; i < 1000; i++) {
if (i > lines) {
break;
}
txt += i + "\n";
}
lineTextArea.setText(txt);
/*ScriptParser parser;
try {
parser = new ScriptParser(scriptTextArea.getText());
String tooltip = parser.getJSCode();
tooltip = tooltip.replaceAll("\n", "<br>");
tooltip = "<html><b>Generated code:</b><p>" + tooltip + "</html>";
lineTextArea.setToolTipText(tooltip);
} catch (ScriptSyntaxErrorException e) {
lineTextArea.setToolTipText("Unable to generate code: " + e.getMessage());
}*/
}
public void changedUpdate(DocumentEvent e) {
update();
}
public void insertUpdate(DocumentEvent e) {
update();
}
public void removeUpdate(DocumentEvent e) {
update();
}
});
scriptTextArea.setMargin(new Insets(5,0,5,5));
scriptTextArea.setEditable(true);
scriptTextArea.setCursor(null);
scriptTextArea.setTabSize(1);
setLayout(new BorderLayout());
codeEditor = new JEditorPane();
logTextArea = new JTextArea(12,50);
logTextArea.setMargin(new Insets(5,5,5,5));
@ -231,22 +190,36 @@ public class ScriptRunner extends VisPlugin {
}
});
JPanel scriptArea = new JPanel(new BorderLayout());
scriptArea.setEnabled(false);
scriptArea.add(BorderLayout.WEST, lineTextArea);
scriptArea.add(BorderLayout.CENTER, scriptTextArea);
doLayout();
JSplitPane centerPanel = new JSplitPane(
JSplitPane.VERTICAL_SPLIT,
new JScrollPane(scriptArea),
new JScrollPane(codeEditor),
new JScrollPane(logTextArea)
);
codeEditor.setContentType("text/javascript");
DefaultSyntaxKit kit = (DefaultSyntaxKit) codeEditor.getEditorKit();
kit.setProperty("PopupMenu", "copy-to-clipboard,-,find,find-next,goto-line,-,linkfile");
kit.setProperty("Action.linkfile", JSyntaxLinkFile.class.getName());
JPopupMenu p = codeEditor.getComponentPopupMenu();
for (Component c: p.getComponents()) {
if (c instanceof JMenuItem) {
if (((JMenuItem) c).getAction() != null &&
((JMenuItem) c).getAction() instanceof JSyntaxLinkFile) {
actionLinkFile = (JSyntaxLinkFile)(((JMenuItem) c).getAction());
actionLinkFile.setMenuText("Link script to disk file");
actionLinkFile.putValue("ScriptRunner", this);
}
}
}
centerPanel.setOneTouchExpandable(true);
centerPanel.setResizeWeight(0.5);
JPanel buttonPanel = new JPanel(new BorderLayout());
buttonPanel.add(BorderLayout.CENTER, toggleButton);
buttonPanel.add(BorderLayout.WEST, examplesButton);
buttonPanel.add(BorderLayout.WEST, examplesButton);
buttonPanel.add(BorderLayout.EAST, runTestButton);
JPanel southPanel = new JPanel(new BorderLayout());
@ -271,21 +244,43 @@ public class ScriptRunner extends VisPlugin {
}
}
public void setScriptActive(boolean active) {
/* Reload script from file */
if (scriptFile != null) {
String script = StringUtils.loadFromFile(scriptFile);
if (script == null) {
logger.fatal("Failed to load script from: " + scriptFile.getAbsolutePath());
} else {
updateScript(script);
}
public void setLinkFile(File source) {
linkedFile = source;
if (source == null) {
updateScript("");
actionLinkFile.setMenuText("Link script to disk file");
actionLinkFile.putValue("JavascriptSource", null);
codeEditor.setEditable(true);
} else {
updateScript(linkedFile);
actionLinkFile.setMenuText("Unlink script: " + source.getName());
actionLinkFile.putValue("JavascriptSource", source);
codeEditor.setEditable(false);
}
updateTitle();
}
public void setScriptActive(boolean active) {
if (active) {
/* setScriptActive(true) */
/* Free any resources */
setScriptActive(false);
/* Reload script from file */
if (linkedFile != null) {
String script = StringUtils.loadFromFile(linkedFile);
if (script == null) {
logger.fatal("Failed to load script from: " + linkedFile.getAbsolutePath());
} else {
updateScript(script);
}
}
/* Create new engine */
engine = new LogScriptEngine(simulation);
if (GUI.isVisualized()) {
@ -331,14 +326,14 @@ public class ScriptRunner extends VisPlugin {
/* Activate engine */
try {
engine.activateScript(scriptTextArea.getText());
engine.activateScript(codeEditor.getText());
actionLinkFile.setEnabled(false);
toggleButton.setText("Deactivate");
examplesButton.setEnabled(false);
logTextArea.setText("");
scriptTextArea.setEnabled(false);
setTitle("Contiki Test Editor (ACTIVE) "
+ (scriptFile==null?"":" (" + scriptFile.getName() + ")"));
codeEditor.setEnabled(false);
updateTitle();
logger.info("Test script activated");
@ -355,19 +350,19 @@ public class ScriptRunner extends VisPlugin {
}
} else {
if (engine == null) {
return;
}
/* setScriptActive(false) */
/* Deactivate script */
engine.deactivateScript();
engine.setScriptLogObserver(null);
engine = null;
if (engine != null) {
/* Deactivate script */
engine.deactivateScript();
engine.setScriptLogObserver(null);
engine = null;
}
if (logWriter != null) {
try {
logWriter.write(
"Test ended at simulation time: " +
"Test ended at simulation time: " +
(simulation!=null?simulation.getSimulationTime():"?") + "\n");
logWriter.flush();
logWriter.close();
@ -376,15 +371,26 @@ public class ScriptRunner extends VisPlugin {
logWriter = null;
}
actionLinkFile.setEnabled(true);
toggleButton.setText("Activate");
examplesButton.setEnabled(true);
scriptTextArea.setEnabled(scriptFile==null?true:false);
examplesButton.setEnabled(linkedFile==null?true:false);
codeEditor.setEnabled(true);
logger.info("Test script deactivated");
setTitle("Contiki Test Editor"
+ (scriptFile==null?"":" (" + scriptFile.getName() + ")"));
updateTitle();
}
}
private void updateTitle() {
String title = "Contiki Test Editor ";
if (linkedFile != null) {
title += ": " + linkedFile.getName() + " ";
}
if (isActive()) {
title += "(ACTIVE) ";
}
setTitle(title);
}
private void exportAndRun() {
/* Save simulation config */
File configFile = simulation.getGUI().doSaveConfig(true);
@ -432,7 +438,7 @@ public class ScriptRunner extends VisPlugin {
String s1 = "Start";
String s2 = "Cancel";
int n = JOptionPane.showOptionDialog(GUI.getTopParentContainer(),
"Starting COOJA in " + coojaBuild.getPath() + ":\n" +
"Starting COOJA in " + coojaBuild.getPath() + ":\n" +
" " + command[0] + " " + command[1] + " " + command[2] + " " + command[3] + "\n",
"Starting COOJA without GUI", JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE, null, new Object[] { s1, s2 }, s1);
@ -558,7 +564,7 @@ public class ScriptRunner extends VisPlugin {
return;
}
scriptTextArea.setText(script);
codeEditor.setText(script);
logTextArea.setText("");
}
@ -566,29 +572,32 @@ public class ScriptRunner extends VisPlugin {
ArrayList<Element> config = new ArrayList<Element>();
Element element;
if (scriptFile != null) {
if (linkedFile != null) {
element = new Element("scriptfile");
element.setText(simulation.getGUI().createPortablePath(scriptFile).getPath().replace('\\', '/'));
element.setText(simulation.getGUI().createPortablePath(linkedFile).getPath().replace('\\', '/'));
config.add(element);
/*StringUtils.saveToFile(scriptFile, scriptTextArea.getText());*/
} else {
element = new Element("script");
element.setText(scriptTextArea.getText());
element.setText(codeEditor.getText());
config.add(element);
}
element = new Element("active");
element.setText("" + (engine != null));
element.setText("" + isActive());
config.add(element);
return config;
}
public boolean isActive() {
return engine != null;
}
public void closePlugin() {
setScriptActive(false);
}
private File scriptFile = null;
public boolean setConfigXML(Collection<Element> configXML, boolean visAvailable) {
for (Element element : configXML) {
String name = element.getName();
@ -598,14 +607,7 @@ public class ScriptRunner extends VisPlugin {
}
} else if ("scriptfile".equals(name)) {
File file = simulation.getGUI().restorePortablePath(new File(element.getText().trim()));
String script = StringUtils.loadFromFile(file);
if (script == null) {
logger.fatal("Failed to load script from: " + file.getAbsolutePath());
} else {
updateScript(script);
}
scriptFile = file;
scriptTextArea.setEnabled(false);
setLinkFile(file);
} else if ("active".equals(name)) {
boolean active = Boolean.parseBoolean(element.getText());
if (GUI.isVisualized()) {
@ -627,4 +629,45 @@ public class ScriptRunner extends VisPlugin {
return StringUtils.loadFromURL(ScriptRunner.class.getResource("/scripts/" + file));
}
public static class JSyntaxLinkFile extends DefaultSyntaxAction {
private static Logger logger = Logger.getLogger(JSyntaxLinkFile.class);
public JSyntaxLinkFile() {
super("linkfile");
}
public void actionPerformed(ActionEvent e) {
JMenuItem menuItem = (JMenuItem) e.getSource();
Action action = menuItem.getAction();
ScriptRunner scriptRunner = (ScriptRunner) action.getValue("ScriptRunner");
File currentSource = (File) action.getValue("JavascriptSource");
if (currentSource != null) {
scriptRunner.setLinkFile(null);
return;
}
JFileChooser fileChooser = new JFileChooser();
fileChooser.setCurrentDirectory(new java.io.File("."));
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
fileChooser.setDialogTitle("Select script file");
fileChooser.setFileFilter(new FileFilter() {
public boolean accept(File file) {
if (file.isDirectory()) { return true; }
if (file.getName().endsWith(".js")) {
return true;
}
return false;
}
public String getDescription() {
return "Javascript";
}
});
if (fileChooser.showOpenDialog(scriptRunner) != JFileChooser.APPROVE_OPTION) {
logger.debug("cancel");
return;
}
scriptRunner.setLinkFile(fileChooser.getSelectedFile());
}
}
}

View file

@ -88,11 +88,12 @@ import se.sics.cooja.GUI;
import se.sics.cooja.Mote;
import se.sics.cooja.Plugin;
import se.sics.cooja.PluginType;
import se.sics.cooja.SimEventCentral.MoteCountListener;
import se.sics.cooja.Simulation;
import se.sics.cooja.VisPlugin;
import se.sics.cooja.Watchpoint;
import se.sics.cooja.WatchpointMote;
import se.sics.cooja.SimEventCentral.MoteCountListener;
import se.sics.cooja.WatchpointMote.WatchpointListener;
import se.sics.cooja.interfaces.LED;
import se.sics.cooja.interfaces.Radio;
import se.sics.cooja.interfaces.Radio.RadioEvent;
@ -100,7 +101,7 @@ import se.sics.cooja.motes.AbstractEmulatedMote;
/**
* Shows events such as mote logs, LEDs, and radio transmissions, in a timeline.
*
*
* @author Fredrik Osterlind
*/
@ClassDescription("Timeline")
@ -118,13 +119,13 @@ public class TimeLine extends VisPlugin {
private double currentPixelDivisor = 200;
private static final long[] ZOOM_LEVELS = {
1, 2, 5, 10,
20, 50, 100, 200, 500, 1000,
2000, 5000, 10000, 20000, 50000, 100000 };
private static final long[] ZOOM_LEVELS = {
1, 2, 5, 10,
20, 50, 100, 200, 500, 1000,
2000, 5000, 10000, 20000, 50000, 100000 };
private boolean needZoomOut = false;
private static Logger logger = Logger.getLogger(TimeLine.class);
private int paintedMoteHeight = EVENT_PIXEL_HEIGHT;
@ -137,7 +138,7 @@ public class TimeLine extends VisPlugin {
private JComponent timeline;
private Box eventCheckboxes;
private JSplitPane splitPane;
private Observer moteHighlightObserver = null;
private ArrayList<Mote> highlightedMotes = new ArrayList<Mote>();
private final static Color HIGHLIGHT_COLOR = Color.CYAN;
@ -162,9 +163,9 @@ public class TimeLine extends VisPlugin {
public TimeLine(final Simulation simulation, final GUI gui) {
super("Timeline (Add motes to observe by clicking +)", gui);
this.simulation = simulation;
currentPixelDivisor = ZOOM_LEVELS[ZOOM_LEVELS.length/2];
/* Box: events to observe */
eventCheckboxes = Box.createVerticalBox();
JCheckBox eventCheckBox;
@ -281,7 +282,7 @@ public class TimeLine extends VisPlugin {
for (Mote m: simulation.getMotes()) {
addMote(m);
}
/* Update timeline for the duration of the plugin */
repaintTimelineTimer.start();
@ -351,12 +352,12 @@ public class TimeLine extends VisPlugin {
public void actionPerformed(ActionEvent e) {
JComponent b = (JComponent) e.getSource();
Mote m = (Mote) b.getClientProperty("mote");
/* Sort by distance */
ArrayList<MoteEvents> sortedMoteEvents = new ArrayList<MoteEvents>();
for (MoteEvents me: allMoteEvents.toArray(new MoteEvents[0])) {
double d = me.mote.getInterfaces().getPosition().getDistanceTo(m);
int i=0;
for (i=0; i < sortedMoteEvents.size(); i++) {
double d2 = m.getInterfaces().getPosition().getDistanceTo(sortedMoteEvents.get(i).mote);
@ -365,7 +366,7 @@ public class TimeLine extends VisPlugin {
}
}
sortedMoteEvents.add(i, me);
}
allMoteEvents = sortedMoteEvents;
numberMotesWasUpdated();
@ -376,7 +377,7 @@ public class TimeLine extends VisPlugin {
public void actionPerformed(ActionEvent e) {
JComponent b = (JComponent) e.getSource();
Mote m = (Mote) b.getClientProperty("mote");
/* Sort by distance */
MoteEvents mEvent = null;
for (MoteEvents me: allMoteEvents.toArray(new MoteEvents[0])) {
@ -441,7 +442,7 @@ public class TimeLine extends VisPlugin {
int leftPixel = (int) (focusTime/currentPixelDivisor - focusCenter*w);
Rectangle r = new Rectangle(
leftPixel, 0,
leftPixel, 0,
w, 1
);
@ -456,7 +457,7 @@ public class TimeLine extends VisPlugin {
}
});
}
private Action zoomInAction = new AbstractAction("Zoom in (Ctrl+)") {
private static final long serialVersionUID = -2592452356547803615L;
public void actionPerformed(ActionEvent e) {
@ -476,13 +477,13 @@ public class TimeLine extends VisPlugin {
if (currentPixelDivisor <= ZOOM_LEVELS[zoomLevel]) break;
zoomLevel++;
}
if (zoomLevel > 0) {
zoomLevel--; /* zoom in */
}
currentPixelDivisor = ZOOM_LEVELS[zoomLevel];
logger.info("Zoom level: " + currentPixelDivisor + " microseconds/pixel " + ((zoomLevel==0)?"(MIN)":""));
forceRepaintAndFocus(centerTime, 0.5);
}
};
@ -516,7 +517,7 @@ public class TimeLine extends VisPlugin {
forceRepaintAndFocus(centerTime, 0.5);
}
};
private Action zoomSliderAction = new AbstractAction("Zoom slider (Ctrl+Mouse)") {
private static final long serialVersionUID = -4288046377707363837L;
public void actionPerformed(ActionEvent e) {
@ -532,27 +533,27 @@ public class TimeLine extends VisPlugin {
zoomSlider.setPaintLabels(false);
final long centerTime = (long) (popupLocation.x*currentPixelDivisor);
zoomSlider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
int zoomLevel = zoomSlider.getValue();
currentPixelDivisor = ZOOM_LEVELS[zoomLevel];
logger.info("Zoom level: " + currentPixelDivisor + " microseconds/pixel " + ((zoomLevel==ZOOM_LEVELS.length-1)?"(MAX)":""));
forceRepaintAndFocus(centerTime, 0.5);
}
});
final JPopupMenu zoomPopup = new JPopupMenu();
zoomPopup.add(zoomSlider);
zoomPopup.show(TimeLine.this, TimeLine.this.getWidth()/2, 0);
zoomSlider.requestFocus();
}
};
/**
* Save logged raw data to file for post-processing.
* Save logged raw data to file for post-processing.
*/
private Action saveDataAction = new AbstractAction("Save raw data to file") {
private static final long serialVersionUID = 975176793514425718L;
@ -641,15 +642,15 @@ public class TimeLine extends VisPlugin {
}
repaint();
}
private class MoteStatistics {
Mote mote;
long onTimeRedLED = 0, onTimeGreenLED = 0, onTimeBlueLED = 0;
int nrLogs = 0;
long radioOn = 0;
long onTimeRX = 0, onTimeTX = 0, onTimeInterfered = 0;
public String toString() {
return toString(true, true, true, true);
}
@ -685,7 +686,7 @@ public class TimeLine extends VisPlugin {
logger.info(extractStatistics());
}
};
public String extractStatistics() {
return extractStatistics(true, true, true, true);
}
@ -743,7 +744,7 @@ public class TimeLine extends VisPlugin {
stats.nrLogs++;
}
}
/* TODO Radio channels */
if (radioHW) {
@ -760,7 +761,7 @@ public class TimeLine extends VisPlugin {
}
}
}
if (radioRXTX) {
for (MoteEvent ev: moteEvents.radioRXTXEvents) {
if (!(ev instanceof RadioRXTXEvent)) continue;
@ -790,7 +791,7 @@ public class TimeLine extends VisPlugin {
}
}
}
/* TODO Watchpoints */
output.append(stats.toString(logs, leds, radioHW, radioRXTX));
@ -799,7 +800,7 @@ public class TimeLine extends VisPlugin {
if (allStats.size() == 0) {
return output.toString();
}
/* Average */
MoteStatistics average = new MoteStatistics();
for (MoteStatistics stats: allStats) {
@ -822,7 +823,7 @@ public class TimeLine extends VisPlugin {
output.append(average.toString(logs, leds, radioHW, radioRXTX));
return output.toString();
}
public void trySelectTime(final long toTime) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
@ -841,23 +842,23 @@ public class TimeLine extends VisPlugin {
forceRepaintAndFocus(toTime, 0.5, false);
}
});
});
}
private Action radioLoggerAction = new AbstractAction("in Radio Logger") {
private static final long serialVersionUID = 7690116136861949864L;
public void actionPerformed(ActionEvent e) {
if (popupLocation == null) {
return;
}
long time = (long) ((double)popupLocation.x*currentPixelDivisor);
long time = (long) (popupLocation.x*currentPixelDivisor);
Plugin[] plugins = simulation.getGUI().getStartedPlugins();
for (Plugin p: plugins) {
if (!(p instanceof RadioLogger)) {
continue;
}
/* Select simulation time */
RadioLogger plugin = (RadioLogger) p;
plugin.trySelectTime(time);
@ -870,14 +871,14 @@ public class TimeLine extends VisPlugin {
if (popupLocation == null) {
return;
}
long time = (long) ((double)popupLocation.x*currentPixelDivisor);
long time = (long) (popupLocation.x*currentPixelDivisor);
Plugin[] plugins = simulation.getGUI().getStartedPlugins();
for (Plugin p: plugins) {
if (!(p instanceof LogListener)) {
continue;
}
/* Select simulation time */
LogListener plugin = (LogListener) p;
plugin.trySelectTime(time);
@ -929,8 +930,8 @@ public class TimeLine extends VisPlugin {
private Mote mote;
private WatchpointMote watchpointMote; /* XXX */
private ActionListener watchpointListener; /* XXX */
private WatchpointListener watchpointListener; /* XXX */
public MoteObservation(Mote mote, Observable observable, Observer observer) {
this.mote = mote;
this.observable = observable;
@ -938,12 +939,12 @@ public class TimeLine extends VisPlugin {
}
/* XXX Special case, should be generalized */
public MoteObservation(Mote mote, WatchpointMote watchpointMote, ActionListener listener) {
public MoteObservation(Mote mote, WatchpointMote watchpointMote, WatchpointListener listener) {
this.mote = mote;
this.watchpointMote = watchpointMote;
this.watchpointListener = listener;
}
public Mote getMote() {
return mote;
}
@ -958,7 +959,7 @@ public class TimeLine extends VisPlugin {
observable = null;
observer = null;
}
/* XXX */
if (watchpointMote != null) {
watchpointMote.removeWatchpointListener(watchpointListener);
@ -971,7 +972,7 @@ public class TimeLine extends VisPlugin {
private void addMoteObservers(final Mote mote, final MoteEvents moteEvents) {
/* TODO Log: final Log moteLog = mote.getInterfaces().getLog(); */
/* TODO Unknown state event */
/* LEDs */
final LED moteLEDs = mote.getInterfaces().getLED();
if (moteLEDs != null) {
@ -1021,7 +1022,7 @@ public class TimeLine extends VisPlugin {
return;
}
lastChannel = nowChannel;
RadioHWEvent ev = new RadioHWEvent(
simulation.getSimulationTime(), moteRadio.isReceiverOn());
if (radioChannels) {
@ -1067,7 +1068,7 @@ public class TimeLine extends VisPlugin {
radioEv == RadioEvent.RECEPTION_STARTED ||
radioEv == RadioEvent.RECEPTION_INTERFERED ||
radioEv == RadioEvent.RECEPTION_FINISHED) {
RadioRXTXEvent ev;
/* Override events, instead show state */
if (moteRadio.isTransmitting()) {
@ -1086,9 +1087,9 @@ public class TimeLine extends VisPlugin {
ev = new RadioRXTXEvent(
simulation.getSimulationTime(), RXTXRadioEvent.IDLE);
}
moteEvents.addRadioRXTX(ev);
if (executionDetails && mote instanceof AbstractEmulatedMote) {
String details = ((AbstractEmulatedMote) mote).getExecutionDetails();
if (details != null) {
@ -1106,22 +1107,26 @@ public class TimeLine extends VisPlugin {
moteRadio.addObserver(observer);
activeMoteObservers.add(new MoteObservation(mote, moteRadio, observer));
}
/* XXX Experimental: Watchpoints */
if (mote instanceof WatchpointMote) {
final WatchpointMote watchpointMote = ((WatchpointMote)mote);
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (watchpointMote.getLastWatchpoint() == null) {
return;
WatchpointListener listener = new WatchpointListener() {
public void watchpointTriggered(Watchpoint watchpoint) {
WatchpointEvent ev = new WatchpointEvent(simulation.getSimulationTime(), watchpoint);
if (executionDetails && mote instanceof AbstractEmulatedMote) {
String details = ((AbstractEmulatedMote) mote).getExecutionDetails();
if (details != null) {
details = "<br>" + details.replace("\n", "<br>");
ev.details = details;
}
}
WatchpointEvent ev = new WatchpointEvent(
simulation.getSimulationTime(),
watchpointMote.getLastWatchpoint()
);
moteEvents.addWatchpoint(ev);
}
public void watchpointsChanged() {
}
};
watchpointMote.addWatchpointListener(listener);
@ -1209,7 +1214,7 @@ public class TimeLine extends VisPlugin {
}
simulation.getEventCentral().removeMoteCountListener(newMotesListener);
/* Remove active mote interface observers */
for (MoteObservation o: activeMoteObservers) {
o.dispose();
@ -1295,7 +1300,7 @@ public class TimeLine extends VisPlugin {
for (MoteEvents moteEvents: allMoteEventsArr) {
removeMote(moteEvents.mote);
}
for (Element element : configXML) {
String name = element.getName();
if ("mote".equals(name)) {
@ -1349,20 +1354,20 @@ public class TimeLine extends VisPlugin {
return true;
}
private int mousePixelPositionX = -1;
private int mousePixelPositionY = -1;
private int mouseDownPixelPositionX = -1;
private int mouseDownPixelPositionX = -1;
class Timeline extends JComponent {
private static final long serialVersionUID = 2206491823778169359L;
public Timeline() {
setLayout(null);
setToolTipText(null);
setBackground(COLOR_BACKGROUND);
addMouseListener(mouseAdapter);
addMouseMotionListener(mouseAdapter);
/* Popup menu */
final JPopupMenu popupMenu = new JPopupMenu();
@ -1379,7 +1384,7 @@ public class TimeLine extends VisPlugin {
popupMenu.add(new JMenuItem(saveDataAction));
popupMenu.add(new JMenuItem(statisticsAction));
popupMenu.add(new JMenuItem(clearAction));
popupMenu.addSeparator();
JMenu focusMenu = new JMenu("Show in");
@ -1417,7 +1422,7 @@ public class TimeLine extends VisPlugin {
popupLocation = e.getPoint();
showInAllAction.actionPerformed(null);
long time = (long) ((double)popupLocation.x*currentPixelDivisor);
long time = (long) (popupLocation.x*currentPixelDivisor);
Plugin[] plugins = simulation.getGUI().getStartedPlugins();
for (Plugin p: plugins) {
if (!(p instanceof TimeLine)) {
@ -1486,7 +1491,7 @@ public class TimeLine extends VisPlugin {
forceRepaintAndFocus(zoomCenterTime, zoomCenter);
return;
}
if (mousePixelPositionX >= 0) {
mousePixelPositionX = e.getX();
mousePixelPositionY = e.getY();
@ -1507,7 +1512,7 @@ public class TimeLine extends VisPlugin {
zoomCenterTime = (long) (e.getX()*currentPixelDivisor);
return;
}
if (popUpToolTip != null) {
popUpToolTip.hide();
popUpToolTip = null;
@ -1524,7 +1529,34 @@ public class TimeLine extends VisPlugin {
if (t.getTipText() == null || t.getTipText().equals("")) {
return;
}
popUpToolTip = PopupFactory.getSharedInstance().getPopup(timeline, t, e.getXOnScreen(), e.getYOnScreen());
t.validate();
/* Check tooltip width */
Rectangle screenBounds = timeline.getGraphicsConfiguration().getBounds();
int x;
{
int tooltip = e.getLocationOnScreen().x + t.getPreferredSize().width;
int screen = screenBounds.x + screenBounds.width;
if (tooltip > screen) {
x = e.getLocationOnScreen().x - (tooltip-screen);
} else {
x = e.getLocationOnScreen().x;
}
}
/* Check tooltip height */
int y;
{
int tooltip = e.getLocationOnScreen().y + t.getPreferredSize().height;
int screen = screenBounds.y + screenBounds.height;
if (tooltip > screen) {
y = e.getLocationOnScreen().y - (tooltip-screen);
} else {
y = e.getLocationOnScreen().y;
}
}
popUpToolTip = PopupFactory.getSharedInstance().getPopup(null, t, x, y);
popUpToolTip.show();
}
}
@ -1544,7 +1576,7 @@ public class TimeLine extends VisPlugin {
public void paintComponent(Graphics g) {
Rectangle bounds = g.getClipBounds();
/*logger.info("Clip bounds: " + bounds);*/
if (needZoomOut) {
/* Need zoom out */
g.setColor(Color.RED);
@ -1556,12 +1588,12 @@ public class TimeLine extends VisPlugin {
FontMetrics fm = g.getFontMetrics();
int msgWidth = fm.stringWidth(msg);
int msgHeight = fm.getHeight();
g.drawString(msg,
g.drawString(msg,
vis.x + vis.width/2 - msgWidth/2,
vis.y + vis.height/2 + msgHeight/2);
return;
}
long intervalStart = (long)(bounds.x*currentPixelDivisor);
long intervalEnd = (long) (intervalStart + bounds.width*currentPixelDivisor);
@ -1584,12 +1616,12 @@ public class TimeLine extends VisPlugin {
int lineHeightOffset = FIRST_MOTE_PIXEL_OFFSET;
boolean dark = true;
for (int mIndex = 0; mIndex < allMoteEvents.size(); mIndex++) {
/* Mote separators */
if (dark) {
g.setColor(SEPARATOR_COLOR);
g.fillRect(
0, lineHeightOffset-2,
0, lineHeightOffset-2,
getWidth(), paintedMoteHeight
);
}
@ -1680,23 +1712,23 @@ public class TimeLine extends VisPlugin {
while (time <= end) {
if (time % (100*Simulation.MILLISECOND) == 0) {
g.drawLine(
(int) (time/currentPixelDivisor), (int)0,
(int) (time/currentPixelDivisor), (int)TIME_MARKER_PIXEL_HEIGHT);
(int) (time/currentPixelDivisor), 0,
(int) (time/currentPixelDivisor), TIME_MARKER_PIXEL_HEIGHT);
} else {
g.drawLine(
(int) (time/currentPixelDivisor), (int)0,
(int) (time/currentPixelDivisor), (int)TIME_MARKER_PIXEL_HEIGHT/2);
}
(int) (time/currentPixelDivisor), 0,
(int) (time/currentPixelDivisor), TIME_MARKER_PIXEL_HEIGHT/2);
}
time += (10*Simulation.MILLISECOND);
}
}
private void drawMouseTime(Graphics g, long start, long end) {
if (mousePixelPositionX >= 0) {
long time = (long) ((double)mousePixelPositionX*currentPixelDivisor);
long diff = (long) ((double)Math.abs(mouseDownPixelPositionX-mousePixelPositionX)*currentPixelDivisor);
String str =
"Time (ms): " + (double)time/Simulation.MILLISECOND +
long time = (long) (mousePixelPositionX*currentPixelDivisor);
long diff = (long) (Math.abs(mouseDownPixelPositionX-mousePixelPositionX)*currentPixelDivisor);
String str =
"Time (ms): " + (double)time/Simulation.MILLISECOND +
" (" + (double)diff/Simulation.MILLISECOND + ")";
int h = g.getFontMetrics().getHeight();
@ -1707,21 +1739,21 @@ public class TimeLine extends VisPlugin {
/* Line */
g.setColor(Color.GRAY);
g.drawLine(
mousePixelPositionX, 0,
mousePixelPositionX, 0,
mousePixelPositionX, getHeight());
/* Text box */
g.setColor(Color.DARK_GRAY);
g.fillRect(
mousePixelPositionX-delta, y,
mousePixelPositionX-delta, y,
w, h);
g.setColor(Color.BLACK);
g.drawRect(
mousePixelPositionX-delta, y,
mousePixelPositionX-delta, y,
w, h);
g.setColor(Color.WHITE);
g.drawString(str,
mousePixelPositionX+3-delta,
g.drawString(str,
mousePixelPositionX+3-delta,
y+h-1);
}
}
@ -1738,7 +1770,7 @@ public class TimeLine extends VisPlugin {
int mote = (event.getPoint().y-FIRST_MOTE_PIXEL_OFFSET)/paintedMoteHeight;
if (mote < 0 || mote >= allMoteEvents.size()) {
return null;
}
}
String tooltip = "<html>Mote: " + allMoteEvents.get(mote).mote + "<br>";
/* Time */
@ -1789,7 +1821,7 @@ public class TimeLine extends VisPlugin {
MoteEvent ev = getFirstIntervalEvent(events, time);
if (ev != null && time >= ev.time) {
tooltip += ev + "<br>";
if (ev.details != null) {
tooltip += "Details:<br>" + ev.details;
}
@ -1846,7 +1878,7 @@ public class TimeLine extends VisPlugin {
private Mote getMote(Point p) {
if (p.y < FIRST_MOTE_PIXEL_OFFSET) {
return null;
return null;
}
int m = (p.y-FIRST_MOTE_PIXEL_OFFSET)/paintedMoteHeight;
if (m < allMoteEvents.size()) {
@ -1899,9 +1931,9 @@ public class TimeLine extends VisPlugin {
/**
* Used by the default paint method to color events.
* The event is not painted if the returned color is null.
*
*
* @see #paintInterval(Graphics, int, long)
* @return Event color or null
* @return Event color or null
*/
public abstract Color getEventColor();
@ -1937,7 +1969,7 @@ public class TimeLine extends VisPlugin {
g.setColor(color);
g.fillRect(
(int)(ev.time/currentPixelDivisor), lineHeightOffset,
(int)(ev.time/currentPixelDivisor), lineHeightOffset,
w, EVENT_PIXEL_HEIGHT
);
@ -1987,7 +2019,7 @@ public class TimeLine extends VisPlugin {
if (state == RXTXRadioEvent.IDLE) {
return "Radio idle from " + time + "<br>";
} else if (state == RXTXRadioEvent.TRANSMITTING) {
return "Radio transmitting from " + time + "<br>";
return "Radio transmitting from " + time + "<br>";
} else if (state == RXTXRadioEvent.RECEIVING) {
return "Radio receiving from " + time + "<br>";
} else if (state == RXTXRadioEvent.INTERFERED) {
@ -2007,18 +2039,18 @@ public class TimeLine extends VisPlugin {
}
/* TODO Which colors? */
private final static Color[] CHANNEL_COLORS = new Color[] {
Color.decode("0x008080"), Color.decode("0x808080"), Color.decode("0xC00000"),
Color.decode("0x000020"), Color.decode("0x202000"), Color.decode("0x200020"),
private final static Color[] CHANNEL_COLORS = new Color[] {
Color.decode("0x008080"), Color.decode("0x808080"), Color.decode("0xC00000"),
Color.decode("0x000020"), Color.decode("0x202000"), Color.decode("0x200020"),
Color.decode("0x002020"), Color.decode("0x202020"), Color.decode("0x006060"),
Color.decode("0x606060"), Color.decode("0xA00000"), Color.decode("0x00A000"),
Color.decode("0x606060"), Color.decode("0xA00000"), Color.decode("0x00A000"),
Color.decode("0x0000A0"), Color.decode("0x400040"), Color.decode("0x004040"),
Color.decode("0x404040"), Color.decode("0x200000"), Color.decode("0x002000"),
Color.decode("0xA0A000"), Color.decode("0xA000A0"), Color.decode("0x00A0A0"),
Color.decode("0xA0A000"), Color.decode("0xA000A0"), Color.decode("0x00A0A0"),
Color.decode("0xA0A0A0"), Color.decode("0xE00000"), Color.decode("0x600000"),
Color.decode("0x000040"), Color.decode("0x404000"), Color.decode("0xFF0000"),
Color.decode("0x00FF00"), Color.decode("0x0000FF"), Color.decode("0xFFFF00"),
Color.decode("0xFF00FF"), Color.decode("0x808000"), Color.decode("0x800080"),
Color.decode("0x000040"), Color.decode("0x404000"), Color.decode("0xFF0000"),
Color.decode("0x00FF00"), Color.decode("0x0000FF"), Color.decode("0xFFFF00"),
Color.decode("0xFF00FF"), Color.decode("0x808000"), Color.decode("0x800080"),
};
class RadioHWEvent extends MoteEvent {
boolean on;
@ -2098,21 +2130,21 @@ public class TimeLine extends VisPlugin {
if (color.getRed() > 0) {
g.setColor(new Color(color.getRed(), 0, 0));
g.fillRect(
(int)(ev.time/currentPixelDivisor), lineHeightOffset,
(int)(ev.time/currentPixelDivisor), lineHeightOffset,
w, LED_PIXEL_HEIGHT
);
}
if (color.getGreen() > 0) {
g.setColor(new Color(0, color.getGreen(), 0));
g.fillRect(
(int)(ev.time/currentPixelDivisor), lineHeightOffset+LED_PIXEL_HEIGHT,
(int)(ev.time/currentPixelDivisor), lineHeightOffset+LED_PIXEL_HEIGHT,
w, LED_PIXEL_HEIGHT
);
}
if (color.getBlue() > 0) {
g.setColor(new Color(0, 0, color.getBlue()));
g.fillRect(
(int)(ev.time/currentPixelDivisor), lineHeightOffset+2*LED_PIXEL_HEIGHT,
(int)(ev.time/currentPixelDivisor), lineHeightOffset+2*LED_PIXEL_HEIGHT,
w, LED_PIXEL_HEIGHT
);
}
@ -2120,7 +2152,7 @@ public class TimeLine extends VisPlugin {
}
}
public String toString() {
return
return
"LED state:<br>" +
"Red = " + (red?"ON":"OFF") + "<br>" +
"Green = " + (green?"ON":"OFF") + "<br>" +
@ -2151,7 +2183,7 @@ public class TimeLine extends VisPlugin {
public String toString() {
String desc = watchpoint.getDescription();
desc = desc.replace("\n", "<br>");
return
return
"Watchpoint triggered at time (ms): " + time/Simulation.MILLISECOND + ".<br>"
+ desc + "<br>";
}
@ -2171,7 +2203,7 @@ public class TimeLine extends VisPlugin {
g.setColor(color);
g.fillRect(
(int)(ev.time/currentPixelDivisor), lineHeightOffset,
(int)(ev.time/currentPixelDivisor), lineHeightOffset,
w, EVENT_PIXEL_HEIGHT
);
@ -2184,7 +2216,7 @@ public class TimeLine extends VisPlugin {
ArrayList<MoteEvent> radioRXTXEvents;
ArrayList<MoteEvent> radioChannelEvents;
ArrayList<MoteEvent> radioHWEvents;
ArrayList<MoteEvent> ledEvents;
ArrayList<MoteEvent> ledEvents;
ArrayList<MoteEvent> logEvents;
ArrayList<MoteEvent> watchpointEvents;
@ -2245,7 +2277,7 @@ public class TimeLine extends VisPlugin {
watchpointEvents.add(lastWatchpointEvent);
}
}
public void addRadioRXTX(RadioRXTXEvent ev) {
/* Link with previous events */
if (lastRadioRXTXEvent != null) {
@ -2317,7 +2349,7 @@ public class TimeLine extends VisPlugin {
if (now == lastRepaintSimulationTime) {
return;
}
lastRepaintSimulationTime = now;
lastRepaintSimulationTime = now;
/* Update timeline size */
int newWidth;
@ -2330,10 +2362,10 @@ public class TimeLine extends VisPlugin {
needZoomOut = false;
}
Rectangle visibleRectangle = timeline.getVisibleRect();
Rectangle visibleRectangle = timeline.getVisibleRect();
boolean isTracking = visibleRectangle.x + visibleRectangle.width >= timeline.getWidth();
int newHeight = (int) (FIRST_MOTE_PIXEL_OFFSET + paintedMoteHeight * allMoteEvents.size());
int newHeight = (FIRST_MOTE_PIXEL_OFFSET + paintedMoteHeight * allMoteEvents.size());
timeline.setPreferredSize(new Dimension(
newWidth,
newHeight
@ -2348,7 +2380,7 @@ public class TimeLine extends VisPlugin {
/* Update visible rectangle */
if (isTracking) {
Rectangle r = new Rectangle(
newWidth-1, visibleRectangle.y,
newWidth-1, visibleRectangle.y,
1, 1);
timeline.scrollRectToVisible(r);
}

View file

@ -0,0 +1,74 @@
/*
* Copyright (c) 2012, 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: CodeUI.java,v 1.8 2009/09/23 08:16:06 fros4943 Exp $
*/
package se.sics.cooja.util;
import java.awt.event.ActionEvent;
import java.io.File;
import javax.swing.Action;
import javax.swing.JMenuItem;
import javax.swing.text.JTextComponent;
import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.actions.DefaultSyntaxAction;
import org.apache.log4j.Logger;
import se.sics.cooja.WatchpointMote;
public class JSyntaxAddBreakpoint extends DefaultSyntaxAction {
private static Logger logger = Logger.getLogger(JSyntaxAddBreakpoint.class);
public JSyntaxAddBreakpoint() {
super("addbreakpoint");
}
public void actionPerformed(ActionEvent e) {
JMenuItem menuItem = (JMenuItem) e.getSource();
Action action = menuItem.getAction();
WatchpointMote watchpointMote = (WatchpointMote) action.getValue("WatchpointMote");
if (watchpointMote == null) {
logger.warn("Error: No source, cannot configure breakpoint");
return;
}
File file = (File) action.getValue("WatchpointFile");
Integer line = (Integer) action.getValue("WatchpointLine");
Integer address = (Integer) action.getValue("WatchpointAddress");
if (file == null || line == null || address == null) {
logger.warn("Error: Bad breakpoint info, cannot add breakpoint");
return;
}
watchpointMote.addBreakpoint(file, line, address);
}
}

View file

@ -0,0 +1,77 @@
/*
* Copyright (c) 2012, 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: CodeUI.java,v 1.8 2009/09/23 08:16:06 fros4943 Exp $
*/
package se.sics.cooja.util;
import java.awt.event.ActionEvent;
import java.io.File;
import javax.swing.Action;
import javax.swing.JMenuItem;
import jsyntaxpane.actions.DefaultSyntaxAction;
import org.apache.log4j.Logger;
import se.sics.cooja.Watchpoint;
import se.sics.cooja.WatchpointMote;
public class JSyntaxRemoveBreakpoint extends DefaultSyntaxAction {
private static Logger logger = Logger.getLogger(JSyntaxRemoveBreakpoint.class);
public JSyntaxRemoveBreakpoint() {
super("removebreakpoint");
}
public void actionPerformed(ActionEvent e) {
JMenuItem menuItem = (JMenuItem) e.getSource();
Action action = menuItem.getAction();
WatchpointMote watchpointMote = (WatchpointMote) action.getValue("WatchpointMote");
if (watchpointMote == null) {
logger.warn("Error: No source, cannot configure breakpoint");
return;
}
File file = (File) action.getValue("WatchpointFile");
Integer line = (Integer) action.getValue("WatchpointLine");
Integer address = (Integer) action.getValue("WatchpointAddress");
if (file == null || line == null || address == null) {
logger.warn("Error: Bad breakpoint info, cannot remove breakpoint");
return;
}
for (Watchpoint w: watchpointMote.getBreakpoints()) {
if (file.equals(w.getCodeFile()) && line.equals(w.getLineNumber()) && address.equals(w.getExecutableAddress())) {
watchpointMote.removeBreakpoint(w);
}
}
}
}

View file

@ -0,0 +1,4 @@
Downloaded from http://code.google.com/p/jsyntaxpane/.
Apache License 2.0:
http://www.apache.org/licenses/LICENSE-2.0

Binary file not shown.