diff --git a/core/net/mac/contikimac.c b/core/net/mac/contikimac.c index d9c83e118..93bf4f5ea 100644 --- a/core/net/mac/contikimac.c +++ b/core/net/mac/contikimac.c @@ -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; diff --git a/core/net/mac/lpp.c b/core/net/mac/lpp.c index 35987c9d8..4cd26971f 100644 --- a/core/net/mac/lpp.c +++ b/core/net/mac/lpp.c @@ -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); diff --git a/core/net/mac/xmac.c b/core/net/mac/xmac.c index 041685280..279981c71 100644 --- a/core/net/mac/xmac.c +++ b/core/net/mac/xmac.c @@ -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(); diff --git a/cpu/stm32w108/dev/stm32w-radio.c b/cpu/stm32w108/dev/stm32w-radio.c index 77f9d9b9d..883099d3e 100644 --- a/cpu/stm32w108/dev/stm32w-radio.c +++ b/cpu/stm32w108/dev/stm32w-radio.c @@ -37,6 +37,8 @@ * Machine dependent STM32W radio code. * \author * Salvatore Pitrulli +* Chi-Anh La la@imag.fr +* Simon Duquennoy */ /*---------------------------------------------------------------------------*/ @@ -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 @@ -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) diff --git a/cpu/stm32w108/rtimer-arch.h b/cpu/stm32w108/rtimer-arch.h index 586e37c16..71718877c 100644 --- a/cpu/stm32w108/rtimer-arch.h +++ b/cpu/stm32w108/rtimer-arch.h @@ -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 diff --git a/platform/mb851/contiki-conf.h b/platform/mb851/contiki-conf.h index 333b3e729..902d8dbe5 100644 --- a/platform/mb851/contiki-conf.h +++ b/platform/mb851/contiki-conf.h @@ -37,130 +37,113 @@ * contiki-conf.h for MB851. * \author * Salvatore Pitrulli +* Chi-Anh La +* Simon Duquennoy */ /*---------------------------------------------------------------------------*/ - #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 -#include // 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< +* Chi-Anh La */ /*---------------------------------------------------------------------------*/ @@ -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(); diff --git a/platform/mb851/platform-conf.h b/platform/mb851/platform-conf.h new file mode 100644 index 000000000..5ac5c19ff --- /dev/null +++ b/platform/mb851/platform-conf.h @@ -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 +* Chi-Anh La +* Simon Duquennoy +*/ +/*---------------------------------------------------------------------------*/ + +#ifndef __PLATFORM_CONF_H__ +#define __PLATFORM_CONF_H__ + +#include PLATFORM_HEADER + +#include +#include // 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< +* Salvatore Pitrulli +* Chi-Anh La +* Simon Duquennoy */ /*---------------------------------------------------------------------------*/ - #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 -#include // 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__ */ diff --git a/platform/mbxxx/contiki-main.c b/platform/mbxxx/contiki-main.c index 6c9c88ba1..d5b63b16b 100644 --- a/platform/mbxxx/contiki-main.c +++ b/platform/mbxxx/contiki-main.c @@ -36,6 +36,7 @@ * Contiki main file. * \author * Salvatore Pitrulli +* Chi-Anh La */ /*---------------------------------------------------------------------------*/ @@ -65,8 +66,6 @@ #include "net/rime.h" #include "net/rime/rime-udp.h" #include "net/uip.h" - - #define DEBUG 1 #if DEBUG #include @@ -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){ diff --git a/platform/mbxxx/platform-conf.h b/platform/mbxxx/platform-conf.h new file mode 100644 index 000000000..07bdf55e5 --- /dev/null +++ b/platform/mbxxx/platform-conf.h @@ -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 +* Chi-Anh La +* Simon Duquennoy +*/ +/*---------------------------------------------------------------------------*/ + +#ifndef __PLATFORM_CONF_H__ +#define __PLATFORM_CONF_H__ + +#include PLATFORM_HEADER + +#include +#include // 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__ */ diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/ESBMote.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/ESBMote.java index c3e5475e5..8c4fb6608 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/ESBMote.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/ESBMote.java @@ -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; /** diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMote.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMote.java index d2d2e154f..ecc77fafa 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMote.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMote.java @@ -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 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 watchpointListeners = new ArrayList(); + private ArrayList watchpoints = new ArrayList(); + private Hashtable> 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 lineTable = debuggingInfo.get(file); + if (lineTable == null) { + Enumeration 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 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 getWatchpointConfigXML() { + ArrayList config = new ArrayList(); + Element element; + + for (MspBreakpoint breakpoint: watchpoints) { + element = new Element("breakpoint"); + element.addContent(breakpoint.getConfigXML()); + config.add(element); + } + + return config; + } + public boolean setWatchpointConfigXML(Collection 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; + } } diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/BreakpointsUI.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/BreakpointsUI.java index 7a9d0bdb9..ede9fc111 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/BreakpointsUI.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/BreakpointsUI.java @@ -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 motes = new ArrayList(); - 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 motes = new ArrayList(); - 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); } }; } diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/CodeUI.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/CodeUI.java index c034d6f0a..e58257b66 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/CodeUI.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/CodeUI.java @@ -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 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 breakpointsLineTags = new ArrayList(); - /** - * @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(); + 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 codeTokensVector = new ArrayList(); - 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 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 lineTokens = new Vector(); - 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(" "); - } - else { - lastWasBlankChar = true; - sb.append(' '); - } - } - else { - lastWasBlankChar = false; - // - // HTML Special Chars - if (c == '"') { - sb.append("""); - } else if (c == '&') { - sb.append("&"); - } else if (c == '<') { - sb.append("<"); - } else if (c == '>') { - sb.append(">"); - } else if (c == '\n') { - // Handle Newline - sb.append("<br/>"); - } 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(""); - - /* Add line number */ - String lineString = "0000" + Integer.toString(lineNr); - lineString = lineString.substring(lineString.length() - 4); - sb.append(""); - sb.append(lineString); - sb.append(": "); - - /* Add code */ - if (tokens == null || tokens.length == 0 || lineStartPos < 0) { - sb.append(""); - sb.append(code); - sb.append(""); - } 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 = "" + subCode + ""; - String lastPart = - tokenLinePos + subToken.symbol.name.length() >= code.length()? - "":code.substring(tokenLinePos + subToken.symbol.name.length()); - - code = firstPart + coloredSubCode + lastPart; - } - - code = code.replace(" ", "  "); - sb.append(code); - } - - sb.append(""); - 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; - } - } - } diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspBreakpoint.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspBreakpoint.java index 7f2c18a81..e6d881e97 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspBreakpoint.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspBreakpoint.java @@ -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 getConfigXML() { - Vector config = new Vector(); + ArrayList config = new ArrayList(); 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 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; - } - } diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspBreakpointContainer.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspBreakpointContainer.java deleted file mode 100644 index 27c721615..000000000 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspBreakpointContainer.java +++ /dev/null @@ -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> debuggingInfo = null; - private MspMote mspMote; - - private ArrayList breakpoints = new ArrayList(); - private ArrayList listeners = new ArrayList(); - private MspBreakpoint lastTriggeredBreakpoint = null; - - /** - * @param debuggingInfo Debugging information read from firmware file - * @param mote Mote - */ - public MspBreakpointContainer(MspMote mote, Hashtable> 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 lineTable = debuggingInfo.get(file); - if (lineTable == null) { - Enumeration 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 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 getConfigXML() { - Vector config = new Vector(); - Element element; - - for (MspBreakpoint breakpoint: breakpoints) { - element = new Element("breakpoint"); - element.addContent(breakpoint.getConfigXML()); - config.add(element); - } - - return config; - } - - public boolean setConfigXML(Collection 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; - } -} diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspCodeWatcher.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspCodeWatcher.java index 4ad0ca2e1..a11e31592 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspCodeWatcher.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspCodeWatcher.java @@ -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 existing = new ArrayList(); 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 getConfigXML() { - Vector config = new Vector(); + ArrayList config = new ArrayList(); 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 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(); } }; diff --git a/tools/cooja/build.xml b/tools/cooja/build.xml index 3ad01fb00..ac98ecce7 100644 --- a/tools/cooja/build.xml +++ b/tools/cooja/build.xml @@ -50,6 +50,7 @@ The COOJA Simulator + @@ -62,6 +63,7 @@ The COOJA Simulator + @@ -74,6 +76,7 @@ The COOJA Simulator + @@ -104,6 +107,7 @@ The COOJA Simulator + @@ -118,6 +122,7 @@ The COOJA Simulator + @@ -131,6 +136,7 @@ The COOJA Simulator + @@ -144,6 +150,7 @@ The COOJA Simulator + @@ -156,6 +163,7 @@ The COOJA Simulator + @@ -170,6 +178,7 @@ The COOJA Simulator + @@ -190,6 +199,7 @@ The COOJA Simulator + @@ -214,7 +224,7 @@ The COOJA Simulator - + diff --git a/tools/cooja/java/se/sics/cooja/Watchpoint.java b/tools/cooja/java/se/sics/cooja/Watchpoint.java index f266d5194..c65182a94 100644 --- a/tools/cooja/java/se/sics/cooja/Watchpoint.java +++ b/tools/cooja/java/se/sics/cooja/Watchpoint.java @@ -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(); } diff --git a/tools/cooja/java/se/sics/cooja/WatchpointMote.java b/tools/cooja/java/se/sics/cooja/WatchpointMote.java index 970c96a40..ba5886213 100644 --- a/tools/cooja/java/se/sics/cooja/WatchpointMote.java +++ b/tools/cooja/java/se/sics/cooja/WatchpointMote.java @@ -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); } diff --git a/tools/cooja/java/se/sics/cooja/plugins/ScriptRunner.java b/tools/cooja/java/se/sics/cooja/plugins/ScriptRunner.java index 89fd6ca9e..278bde825 100644 --- a/tools/cooja/java/se/sics/cooja/plugins/ScriptRunner.java +++ b/tools/cooja/java/se/sics/cooja/plugins/ScriptRunner.java @@ -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", "
"); - tooltip = "Generated code:

" + tooltip + ""; - 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 config = new ArrayList(); 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 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()); + } + } } diff --git a/tools/cooja/java/se/sics/cooja/plugins/TimeLine.java b/tools/cooja/java/se/sics/cooja/plugins/TimeLine.java index 6244740a8..4aefbc074 100644 --- a/tools/cooja/java/se/sics/cooja/plugins/TimeLine.java +++ b/tools/cooja/java/se/sics/cooja/plugins/TimeLine.java @@ -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 highlightedMotes = new ArrayList(); 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 sortedMoteEvents = new ArrayList(); 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 = "
" + details.replace("\n", "
"); + 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 = "Mote: " + allMoteEvents.get(mote).mote + "
"; /* Time */ @@ -1789,7 +1821,7 @@ public class TimeLine extends VisPlugin { MoteEvent ev = getFirstIntervalEvent(events, time); if (ev != null && time >= ev.time) { tooltip += ev + "
"; - + if (ev.details != null) { tooltip += "Details:
" + 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 + "
"; } else if (state == RXTXRadioEvent.TRANSMITTING) { - return "Radio transmitting from " + time + "
"; + return "Radio transmitting from " + time + "
"; } else if (state == RXTXRadioEvent.RECEIVING) { return "Radio receiving from " + time + "
"; } 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:
" + "Red = " + (red?"ON":"OFF") + "
" + "Green = " + (green?"ON":"OFF") + "
" + @@ -2151,7 +2183,7 @@ public class TimeLine extends VisPlugin { public String toString() { String desc = watchpoint.getDescription(); desc = desc.replace("\n", "
"); - return + return "Watchpoint triggered at time (ms): " + time/Simulation.MILLISECOND + ".
" + desc + "
"; } @@ -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 radioRXTXEvents; ArrayList radioChannelEvents; ArrayList radioHWEvents; - ArrayList ledEvents; + ArrayList ledEvents; ArrayList logEvents; ArrayList 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); } diff --git a/tools/cooja/java/se/sics/cooja/util/JSyntaxAddBreakpoint.java b/tools/cooja/java/se/sics/cooja/util/JSyntaxAddBreakpoint.java new file mode 100644 index 000000000..b2e394c8c --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/util/JSyntaxAddBreakpoint.java @@ -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); + } +} diff --git a/tools/cooja/java/se/sics/cooja/util/JSyntaxRemoveBreakpoint.java b/tools/cooja/java/se/sics/cooja/util/JSyntaxRemoveBreakpoint.java new file mode 100644 index 000000000..85bb3245d --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/util/JSyntaxRemoveBreakpoint.java @@ -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); + } + } + + } +} diff --git a/tools/cooja/lib/JSYNTAXPANE_LICENSE b/tools/cooja/lib/JSYNTAXPANE_LICENSE new file mode 100644 index 000000000..01f0c7c35 --- /dev/null +++ b/tools/cooja/lib/JSYNTAXPANE_LICENSE @@ -0,0 +1,4 @@ +Downloaded from http://code.google.com/p/jsyntaxpane/. + +Apache License 2.0: +http://www.apache.org/licenses/LICENSE-2.0 diff --git a/tools/cooja/lib/jsyntaxpane.jar b/tools/cooja/lib/jsyntaxpane.jar new file mode 100644 index 000000000..8bca1f6ec Binary files /dev/null and b/tools/cooja/lib/jsyntaxpane.jar differ