Merge branch 'master' of ssh://contiki.git.sourceforge.net/gitroot/contiki/contiki
This commit is contained in:
commit
bef9b2bd36
|
@ -228,6 +228,12 @@ ifndef CUSTOM_RULE_LINK
|
||||||
$(LD) $(LDFLAGS) $(TARGET_STARTFILES) ${filter-out %.a,$^} ${filter %.a,$^} $(TARGET_LIBFILES) -o $@
|
$(LD) $(LDFLAGS) $(TARGET_STARTFILES) ${filter-out %.a,$^} ${filter %.a,$^} $(TARGET_LIBFILES) -o $@
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
%.ramprof: %.$(TARGET)
|
||||||
|
nm -S -td --size-sort $< | grep -i " [abdrw] " | cut -d' ' -f2,4
|
||||||
|
|
||||||
|
%.flashprof: %.$(TARGET)
|
||||||
|
nm -S -td --size-sort $< | grep -i " [t] " | cut -d' ' -f2,4
|
||||||
|
|
||||||
# Don't treat %.$(TARGET) as an intermediate file because it is
|
# Don't treat %.$(TARGET) as an intermediate file because it is
|
||||||
# in fact the primary target.
|
# in fact the primary target.
|
||||||
.PRECIOUS: %.$(TARGET)
|
.PRECIOUS: %.$(TARGET)
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "dev/watchdog.h"
|
#include "dev/watchdog.h"
|
||||||
|
|
||||||
#include "net/rime.h"
|
#include "net/rime.h"
|
||||||
|
#include "net/netstack.h"
|
||||||
#include "dev/cc2420.h"
|
#include "dev/cc2420.h"
|
||||||
#include "dev/leds.h"
|
#include "dev/leds.h"
|
||||||
#include "dev/sht11.h"
|
#include "dev/sht11.h"
|
||||||
|
@ -97,7 +98,7 @@ do_rssi(void)
|
||||||
static int sample;
|
static int sample;
|
||||||
int channel;
|
int channel;
|
||||||
|
|
||||||
rime_mac->off(0);
|
NETSTACK_MAC.off(0);
|
||||||
|
|
||||||
cc2420_on();
|
cc2420_on();
|
||||||
for(channel = 11; channel <= 26; ++channel) {
|
for(channel = 11; channel <= 26; ++channel) {
|
||||||
|
@ -105,7 +106,7 @@ do_rssi(void)
|
||||||
rssi_samples[sample].channel[channel - 11] = cc2420_rssi() + 53;
|
rssi_samples[sample].channel[channel - 11] = cc2420_rssi() + 53;
|
||||||
}
|
}
|
||||||
|
|
||||||
rime_mac->on();
|
NETSTACK_MAC.on();
|
||||||
|
|
||||||
sample = (sample + 1) % NUM_SAMPLES;
|
sample = (sample + 1) % NUM_SAMPLES;
|
||||||
|
|
||||||
|
|
|
@ -522,7 +522,7 @@ static int
|
||||||
send_packet(mac_callback_t mac_callback, void *mac_callback_ptr, struct rdc_buf_list *buf_list)
|
send_packet(mac_callback_t mac_callback, void *mac_callback_ptr, struct rdc_buf_list *buf_list)
|
||||||
{
|
{
|
||||||
rtimer_clock_t t0;
|
rtimer_clock_t t0;
|
||||||
rtimer_clock_t encounter_time = 0, previous_txtime = 0;
|
rtimer_clock_t encounter_time = 0;
|
||||||
int strobes;
|
int strobes;
|
||||||
uint8_t got_strobe_ack = 0;
|
uint8_t got_strobe_ack = 0;
|
||||||
int hdrlen, len;
|
int hdrlen, len;
|
||||||
|
@ -723,7 +723,6 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr, struct rdc_buf_
|
||||||
watchdog_periodic();
|
watchdog_periodic();
|
||||||
t0 = RTIMER_NOW();
|
t0 = RTIMER_NOW();
|
||||||
seqno = packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO);
|
seqno = packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO);
|
||||||
previous_txtime = RTIMER_NOW();
|
|
||||||
for(strobes = 0, collisions = 0;
|
for(strobes = 0, collisions = 0;
|
||||||
got_strobe_ack == 0 && collisions == 0 &&
|
got_strobe_ack == 0 && collisions == 0 &&
|
||||||
RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + STROBE_TIME); strobes++) {
|
RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + STROBE_TIME); strobes++) {
|
||||||
|
@ -751,7 +750,7 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr, struct rdc_buf_
|
||||||
if(ret == RADIO_TX_OK) {
|
if(ret == RADIO_TX_OK) {
|
||||||
if(!is_broadcast) {
|
if(!is_broadcast) {
|
||||||
got_strobe_ack = 1;
|
got_strobe_ack = 1;
|
||||||
encounter_time = previous_txtime;
|
encounter_time = txtime;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (ret == RADIO_TX_NOACK) {
|
} else if (ret == RADIO_TX_NOACK) {
|
||||||
|
@ -776,7 +775,7 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr, struct rdc_buf_
|
||||||
len = NETSTACK_RADIO.read(ackbuf, ACK_LEN);
|
len = NETSTACK_RADIO.read(ackbuf, ACK_LEN);
|
||||||
if(len == ACK_LEN && seqno == ackbuf[ACK_LEN-1]) {
|
if(len == ACK_LEN && seqno == ackbuf[ACK_LEN-1]) {
|
||||||
got_strobe_ack = 1;
|
got_strobe_ack = 1;
|
||||||
encounter_time = previous_txtime;
|
encounter_time = txtime;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
PRINTF("contikimac: collisions while sending\n");
|
PRINTF("contikimac: collisions while sending\n");
|
||||||
|
@ -784,8 +783,6 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr, struct rdc_buf_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* RDC_CONF_HARDWARE_ACK */
|
#endif /* RDC_CONF_HARDWARE_ACK */
|
||||||
|
|
||||||
previous_txtime = txtime;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,8 +89,6 @@ void rime_input(void);
|
||||||
|
|
||||||
int rime_output(struct channel *c);
|
int rime_output(struct channel *c);
|
||||||
|
|
||||||
extern const struct mac_driver *rime_mac;
|
|
||||||
|
|
||||||
struct rime_sniffer {
|
struct rime_sniffer {
|
||||||
struct rime_sniffer *next;
|
struct rime_sniffer *next;
|
||||||
void (* input_callback)(void);
|
void (* input_callback)(void);
|
||||||
|
|
|
@ -61,8 +61,6 @@
|
||||||
|
|
||||||
#include "lib/list.h"
|
#include "lib/list.h"
|
||||||
|
|
||||||
const struct mac_driver *rime_mac;
|
|
||||||
|
|
||||||
#ifdef RIME_CONF_BROADCAST_ANNOUNCEMENT_CHANNEL
|
#ifdef RIME_CONF_BROADCAST_ANNOUNCEMENT_CHANNEL
|
||||||
#define BROADCAST_ANNOUNCEMENT_CHANNEL RIME_CONF_BROADCAST_ANNOUNCEMENT_CHANNEL
|
#define BROADCAST_ANNOUNCEMENT_CHANNEL RIME_CONF_BROADCAST_ANNOUNCEMENT_CHANNEL
|
||||||
#else /* RIME_CONF_BROADCAST_ANNOUNCEMENT_CHANNEL */
|
#else /* RIME_CONF_BROADCAST_ANNOUNCEMENT_CHANNEL */
|
||||||
|
@ -130,7 +128,6 @@ init(void)
|
||||||
packetbuf_clear();
|
packetbuf_clear();
|
||||||
announcement_init();
|
announcement_init();
|
||||||
|
|
||||||
rime_mac = &NETSTACK_MAC;
|
|
||||||
chameleon_init();
|
chameleon_init();
|
||||||
|
|
||||||
/* XXX This is initializes the transmission of announcements but it
|
/* XXX This is initializes the transmission of announcements but it
|
||||||
|
|
|
@ -211,6 +211,11 @@ static uint8_t rime_payload_len;
|
||||||
* is used this includes the UDP header in addition to the IP header).
|
* is used this includes the UDP header in addition to the IP header).
|
||||||
*/
|
*/
|
||||||
static uint8_t uncomp_hdr_len;
|
static uint8_t uncomp_hdr_len;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the result of the last transmitted fragment
|
||||||
|
*/
|
||||||
|
static int last_tx_status;
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
#if SICSLOWPAN_CONF_FRAG
|
#if SICSLOWPAN_CONF_FRAG
|
||||||
|
@ -234,7 +239,7 @@ static uip_buf_t sicslowpan_aligned_buf;
|
||||||
* length of the ip packet already sent / received.
|
* length of the ip packet already sent / received.
|
||||||
* It includes IP and transport headers.
|
* It includes IP and transport headers.
|
||||||
*/
|
*/
|
||||||
static uint16_t processed_ip_len;
|
static uint16_t processed_ip_in_len;
|
||||||
|
|
||||||
/** Datagram tag to be put in the fragments I send. */
|
/** Datagram tag to be put in the fragments I send. */
|
||||||
static uint16_t my_tag;
|
static uint16_t my_tag;
|
||||||
|
@ -1308,6 +1313,7 @@ packet_sent(void *ptr, int status, int transmissions)
|
||||||
if(callback != NULL) {
|
if(callback != NULL) {
|
||||||
callback->output_callback(status);
|
callback->output_callback(status);
|
||||||
}
|
}
|
||||||
|
last_tx_status = status;
|
||||||
}
|
}
|
||||||
/*--------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------*/
|
||||||
/**
|
/**
|
||||||
|
@ -1353,6 +1359,9 @@ output(uip_lladdr_t *localdest)
|
||||||
/* The MAC address of the destination of the packet */
|
/* The MAC address of the destination of the packet */
|
||||||
rimeaddr_t dest;
|
rimeaddr_t dest;
|
||||||
|
|
||||||
|
/* Number of bytes processed. */
|
||||||
|
uint16_t processed_ip_out_len;
|
||||||
|
|
||||||
/* init */
|
/* init */
|
||||||
uncomp_hdr_len = 0;
|
uncomp_hdr_len = 0;
|
||||||
rime_hdr_len = 0;
|
rime_hdr_len = 0;
|
||||||
|
@ -1443,6 +1452,7 @@ output(uip_lladdr_t *localdest)
|
||||||
((SICSLOWPAN_DISPATCH_FRAG1 << 8) | uip_len));
|
((SICSLOWPAN_DISPATCH_FRAG1 << 8) | uip_len));
|
||||||
/* RIME_FRAG_BUF->tag = uip_htons(my_tag); */
|
/* RIME_FRAG_BUF->tag = uip_htons(my_tag); */
|
||||||
SET16(RIME_FRAG_PTR, RIME_FRAG_TAG, my_tag);
|
SET16(RIME_FRAG_PTR, RIME_FRAG_TAG, my_tag);
|
||||||
|
my_tag++;
|
||||||
|
|
||||||
/* Copy payload and send */
|
/* Copy payload and send */
|
||||||
rime_hdr_len += SICSLOWPAN_FRAG1_HDR_LEN;
|
rime_hdr_len += SICSLOWPAN_FRAG1_HDR_LEN;
|
||||||
|
@ -1461,8 +1471,16 @@ output(uip_lladdr_t *localdest)
|
||||||
queuebuf_free(q);
|
queuebuf_free(q);
|
||||||
q = NULL;
|
q = NULL;
|
||||||
|
|
||||||
/* set processed_ip_len to what we already sent from the IP payload*/
|
/* Check tx result. */
|
||||||
processed_ip_len = rime_payload_len + uncomp_hdr_len;
|
if((last_tx_status == MAC_TX_COLLISION) ||
|
||||||
|
(last_tx_status == MAC_TX_ERR) ||
|
||||||
|
(last_tx_status == MAC_TX_ERR_FATAL)) {
|
||||||
|
PRINTFO("error in fragment tx, dropping subsequent fragments.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set processed_ip_out_len to what we already sent from the IP payload*/
|
||||||
|
processed_ip_out_len = rime_payload_len + uncomp_hdr_len;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create following fragments
|
* Create following fragments
|
||||||
|
@ -1475,19 +1493,19 @@ output(uip_lladdr_t *localdest)
|
||||||
SET16(RIME_FRAG_PTR, RIME_FRAG_DISPATCH_SIZE,
|
SET16(RIME_FRAG_PTR, RIME_FRAG_DISPATCH_SIZE,
|
||||||
((SICSLOWPAN_DISPATCH_FRAGN << 8) | uip_len));
|
((SICSLOWPAN_DISPATCH_FRAGN << 8) | uip_len));
|
||||||
rime_payload_len = (MAC_MAX_PAYLOAD - rime_hdr_len) & 0xf8;
|
rime_payload_len = (MAC_MAX_PAYLOAD - rime_hdr_len) & 0xf8;
|
||||||
while(processed_ip_len < uip_len) {
|
while(processed_ip_out_len < uip_len) {
|
||||||
PRINTFO("sicslowpan output: fragment ");
|
PRINTFO("sicslowpan output: fragment ");
|
||||||
RIME_FRAG_PTR[RIME_FRAG_OFFSET] = processed_ip_len >> 3;
|
RIME_FRAG_PTR[RIME_FRAG_OFFSET] = processed_ip_out_len >> 3;
|
||||||
|
|
||||||
/* Copy payload and send */
|
/* Copy payload and send */
|
||||||
if(uip_len - processed_ip_len < rime_payload_len) {
|
if(uip_len - processed_ip_out_len < rime_payload_len) {
|
||||||
/* last fragment */
|
/* last fragment */
|
||||||
rime_payload_len = uip_len - processed_ip_len;
|
rime_payload_len = uip_len - processed_ip_out_len;
|
||||||
}
|
}
|
||||||
PRINTFO("(offset %d, len %d, tag %d)\n",
|
PRINTFO("(offset %d, len %d, tag %d)\n",
|
||||||
processed_ip_len >> 3, rime_payload_len, my_tag);
|
processed_ip_out_len >> 3, rime_payload_len, my_tag);
|
||||||
memcpy(rime_ptr + rime_hdr_len,
|
memcpy(rime_ptr + rime_hdr_len,
|
||||||
(uint8_t *)UIP_IP_BUF + processed_ip_len, rime_payload_len);
|
(uint8_t *)UIP_IP_BUF + processed_ip_out_len, rime_payload_len);
|
||||||
packetbuf_set_datalen(rime_payload_len + rime_hdr_len);
|
packetbuf_set_datalen(rime_payload_len + rime_hdr_len);
|
||||||
q = queuebuf_new_from_packetbuf();
|
q = queuebuf_new_from_packetbuf();
|
||||||
if(q == NULL) {
|
if(q == NULL) {
|
||||||
|
@ -1498,12 +1516,16 @@ output(uip_lladdr_t *localdest)
|
||||||
queuebuf_to_packetbuf(q);
|
queuebuf_to_packetbuf(q);
|
||||||
queuebuf_free(q);
|
queuebuf_free(q);
|
||||||
q = NULL;
|
q = NULL;
|
||||||
processed_ip_len += rime_payload_len;
|
processed_ip_out_len += rime_payload_len;
|
||||||
|
|
||||||
|
/* Check tx result. */
|
||||||
|
if((last_tx_status == MAC_TX_COLLISION) ||
|
||||||
|
(last_tx_status == MAC_TX_ERR) ||
|
||||||
|
(last_tx_status == MAC_TX_ERR_FATAL)) {
|
||||||
|
PRINTFO("error in fragment tx, dropping subsequent fragments.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* end: reset global variables */
|
|
||||||
my_tag++;
|
|
||||||
processed_ip_len = 0;
|
|
||||||
#else /* SICSLOWPAN_CONF_FRAG */
|
#else /* SICSLOWPAN_CONF_FRAG */
|
||||||
PRINTFO("sicslowpan output: Packet too large to be sent without fragmentation support; dropping packet\n");
|
PRINTFO("sicslowpan output: Packet too large to be sent without fragmentation support; dropping packet\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1558,7 +1580,7 @@ input(void)
|
||||||
/* if reassembly timed out, cancel it */
|
/* if reassembly timed out, cancel it */
|
||||||
if(timer_expired(&reass_timer)) {
|
if(timer_expired(&reass_timer)) {
|
||||||
sicslowpan_len = 0;
|
sicslowpan_len = 0;
|
||||||
processed_ip_len = 0;
|
processed_ip_in_len = 0;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Since we don't support the mesh and broadcast header, the first header
|
* Since we don't support the mesh and broadcast header, the first header
|
||||||
|
@ -1593,10 +1615,10 @@ input(void)
|
||||||
|
|
||||||
/* If this is the last fragment, we may shave off any extrenous
|
/* If this is the last fragment, we may shave off any extrenous
|
||||||
bytes at the end. We must be liberal in what we accept. */
|
bytes at the end. We must be liberal in what we accept. */
|
||||||
PRINTFI("last_fragment?: processed_ip_len %d rime_payload_len %d frag_size %d\n",
|
PRINTFI("last_fragment?: processed_ip_in_len %d rime_payload_len %d frag_size %d\n",
|
||||||
processed_ip_len, packetbuf_datalen() - rime_hdr_len, frag_size);
|
processed_ip_in_len, packetbuf_datalen() - rime_hdr_len, frag_size);
|
||||||
|
|
||||||
if(processed_ip_len + packetbuf_datalen() - rime_hdr_len >= frag_size) {
|
if(processed_ip_in_len + packetbuf_datalen() - rime_hdr_len >= frag_size) {
|
||||||
last_fragment = 1;
|
last_fragment = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1604,7 +1626,7 @@ input(void)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(processed_ip_len > 0) {
|
if(processed_ip_in_len > 0) {
|
||||||
/* reassembly is ongoing */
|
/* reassembly is ongoing */
|
||||||
/* printf("frag %d %d\n", reass_tag, frag_tag);*/
|
/* printf("frag %d %d\n", reass_tag, frag_tag);*/
|
||||||
if((frag_size > 0 &&
|
if((frag_size > 0 &&
|
||||||
|
@ -1624,7 +1646,7 @@ input(void)
|
||||||
* reassembly is off
|
* reassembly is off
|
||||||
* start it if we received a fragment
|
* start it if we received a fragment
|
||||||
*/
|
*/
|
||||||
if(frag_size > 0) {
|
if((frag_size > 0) && (frag_size <= UIP_BUFSIZE)) {
|
||||||
sicslowpan_len = frag_size;
|
sicslowpan_len = frag_size;
|
||||||
reass_tag = frag_tag;
|
reass_tag = frag_tag;
|
||||||
timer_set(&reass_timer, SICSLOWPAN_REASS_MAXAGE*CLOCK_SECOND);
|
timer_set(&reass_timer, SICSLOWPAN_REASS_MAXAGE*CLOCK_SECOND);
|
||||||
|
@ -1690,22 +1712,22 @@ input(void)
|
||||||
rime_payload_len = packetbuf_datalen() - rime_hdr_len;
|
rime_payload_len = packetbuf_datalen() - rime_hdr_len;
|
||||||
memcpy((uint8_t *)SICSLOWPAN_IP_BUF + uncomp_hdr_len + (uint16_t)(frag_offset << 3), rime_ptr + rime_hdr_len, rime_payload_len);
|
memcpy((uint8_t *)SICSLOWPAN_IP_BUF + uncomp_hdr_len + (uint16_t)(frag_offset << 3), rime_ptr + rime_hdr_len, rime_payload_len);
|
||||||
|
|
||||||
/* update processed_ip_len if fragment, sicslowpan_len otherwise */
|
/* update processed_ip_in_len if fragment, sicslowpan_len otherwise */
|
||||||
|
|
||||||
#if SICSLOWPAN_CONF_FRAG
|
#if SICSLOWPAN_CONF_FRAG
|
||||||
if(frag_size > 0) {
|
if(frag_size > 0) {
|
||||||
/* Add the size of the header only for the first fragment. */
|
/* Add the size of the header only for the first fragment. */
|
||||||
if(first_fragment != 0) {
|
if(first_fragment != 0) {
|
||||||
processed_ip_len += uncomp_hdr_len;
|
processed_ip_in_len += uncomp_hdr_len;
|
||||||
}
|
}
|
||||||
/* For the last fragment, we are OK if there is extrenous bytes at
|
/* For the last fragment, we are OK if there is extrenous bytes at
|
||||||
the end of the packet. */
|
the end of the packet. */
|
||||||
if(last_fragment != 0) {
|
if(last_fragment != 0) {
|
||||||
processed_ip_len = frag_size;
|
processed_ip_in_len = frag_size;
|
||||||
} else {
|
} else {
|
||||||
processed_ip_len += rime_payload_len;
|
processed_ip_in_len += rime_payload_len;
|
||||||
}
|
}
|
||||||
PRINTF("processed_ip_len %d, rime_payload_len %d\n", processed_ip_len, rime_payload_len);
|
PRINTF("processed_ip_in_len %d, rime_payload_len %d\n", processed_ip_in_len, rime_payload_len);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
#endif /* SICSLOWPAN_CONF_FRAG */
|
#endif /* SICSLOWPAN_CONF_FRAG */
|
||||||
|
@ -1717,15 +1739,15 @@ input(void)
|
||||||
* If we have a full IP packet in sicslowpan_buf, deliver it to
|
* If we have a full IP packet in sicslowpan_buf, deliver it to
|
||||||
* the IP stack
|
* the IP stack
|
||||||
*/
|
*/
|
||||||
PRINTF("sicslowpan_init processed_ip_len %d, sicslowpan_len %d\n",
|
PRINTF("sicslowpan_init processed_ip_in_len %d, sicslowpan_len %d\n",
|
||||||
processed_ip_len, sicslowpan_len);
|
processed_ip_in_len, sicslowpan_len);
|
||||||
if(processed_ip_len == 0 || (processed_ip_len == sicslowpan_len)) {
|
if(processed_ip_in_len == 0 || (processed_ip_in_len == sicslowpan_len)) {
|
||||||
PRINTFI("sicslowpan input: IP packet ready (length %d)\n",
|
PRINTFI("sicslowpan input: IP packet ready (length %d)\n",
|
||||||
sicslowpan_len);
|
sicslowpan_len);
|
||||||
memcpy((uint8_t *)UIP_IP_BUF, (uint8_t *)SICSLOWPAN_IP_BUF, sicslowpan_len);
|
memcpy((uint8_t *)UIP_IP_BUF, (uint8_t *)SICSLOWPAN_IP_BUF, sicslowpan_len);
|
||||||
uip_len = sicslowpan_len;
|
uip_len = sicslowpan_len;
|
||||||
sicslowpan_len = 0;
|
sicslowpan_len = 0;
|
||||||
processed_ip_len = 0;
|
processed_ip_in_len = 0;
|
||||||
#endif /* SICSLOWPAN_CONF_FRAG */
|
#endif /* SICSLOWPAN_CONF_FRAG */
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
|
|
@ -570,6 +570,7 @@ tcpip_ipv6_output(void)
|
||||||
PRINTF("FALLBACK: removing ext hdrs & setting proto %d %d\n",
|
PRINTF("FALLBACK: removing ext hdrs & setting proto %d %d\n",
|
||||||
uip_ext_len, *((uint8_t *)UIP_IP_BUF + 40));
|
uip_ext_len, *((uint8_t *)UIP_IP_BUF + 40));
|
||||||
if(uip_ext_len > 0) {
|
if(uip_ext_len > 0) {
|
||||||
|
extern void remove_ext_hdr(void);
|
||||||
uint8_t proto = *((uint8_t *)UIP_IP_BUF + 40);
|
uint8_t proto = *((uint8_t *)UIP_IP_BUF + 40);
|
||||||
remove_ext_hdr();
|
remove_ext_hdr();
|
||||||
/* This should be copied from the ext header... */
|
/* This should be copied from the ext header... */
|
||||||
|
@ -643,7 +644,6 @@ tcpip_ipv6_output(void)
|
||||||
PRINTF("tcpip_ipv6_output: nbr cache entry stale moving to delay\n");
|
PRINTF("tcpip_ipv6_output: nbr cache entry stale moving to delay\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000);
|
|
||||||
tcpip_output(&nbr->lladdr);
|
tcpip_output(&nbr->lladdr);
|
||||||
|
|
||||||
#if UIP_CONF_IPV6_QUEUE_PKT
|
#if UIP_CONF_IPV6_QUEUE_PKT
|
||||||
|
|
|
@ -212,12 +212,11 @@ uip_ds6_periodic(void)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NBR_DELAY:
|
case NBR_DELAY:
|
||||||
if(stimer_expired(&locnbr->reachable) && (uip_len == 0)) {
|
if(stimer_expired(&locnbr->reachable)) {
|
||||||
locnbr->state = NBR_PROBE;
|
locnbr->state = NBR_PROBE;
|
||||||
locnbr->nscount = 1;
|
locnbr->nscount = 0;
|
||||||
PRINTF("DELAY: moving to PROBE + NS %u\n", locnbr->nscount);
|
PRINTF("DELAY: moving to PROBE\n");
|
||||||
uip_nd6_ns_output(NULL, &locnbr->ipaddr, &locnbr->ipaddr);
|
stimer_set(&locnbr->sendns, 0);
|
||||||
stimer_set(&locnbr->sendns, uip_ds6_if.retrans_timer / 1000);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NBR_PROBE:
|
case NBR_PROBE:
|
||||||
|
|
|
@ -166,8 +166,8 @@ loader-init.o: ${CONTIKI_TARGET}/loader/loader-init.S
|
||||||
$(AS) -o $(notdir $(<:.S=.o)) $<
|
$(AS) -o $(notdir $(<:.S=.o)) $<
|
||||||
# cp loader-init.o build-app/
|
# cp loader-init.o build-app/
|
||||||
|
|
||||||
.PHONY: symbols.c symbols.h
|
|
||||||
ifdef CORE
|
ifdef CORE
|
||||||
|
.PHONY: symbols.c symbols.h
|
||||||
symbols.c:
|
symbols.c:
|
||||||
$(NM) $(CORE) | awk -f $(CONTIKI)/tools/mknmlist > symbols.c
|
$(NM) $(CORE) | awk -f $(CONTIKI)/tools/mknmlist > symbols.c
|
||||||
else
|
else
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
|
|
||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
|
|
||||||
|
define \n
|
||||||
|
|
||||||
|
|
||||||
|
endef
|
||||||
|
|
||||||
ifdef IAR
|
ifdef IAR
|
||||||
${info Using IAR...}
|
${info Using IAR...}
|
||||||
#IAR_PATH = C:/Program\ Files/IAR\ Systems/Embedded\ Workbench\ 5.4\ Evaluation
|
#IAR_PATH = C:/Program\ Files/IAR\ Systems/Embedded\ Workbench\ 5.4\ Evaluation
|
||||||
|
@ -18,7 +23,7 @@ CONTIKI_CPU_DIRS = . dev hal simplemac hal/micro/cortexm3 hal/micro/cortexm3/stm
|
||||||
|
|
||||||
STM32W_C = leds-arch.c leds.c clock.c watchdog.c uart1.c uart1-putchar.c slip_uart1.c slip.c\
|
STM32W_C = leds-arch.c leds.c clock.c watchdog.c uart1.c uart1-putchar.c slip_uart1.c slip.c\
|
||||||
stm32w-radio.c stm32w_systick.c uip_arch.c rtimer-arch.c adc.c micro.c sleep.c \
|
stm32w-radio.c stm32w_systick.c uip_arch.c rtimer-arch.c adc.c micro.c sleep.c \
|
||||||
micro-common.c micro-common-internal.c clocks.c mfg-token.c nvm.c flash.c rand.c system-timer.c
|
micro-common.c micro-common-internal.c clocks.c mfg-token.c nvm.c flash.c rand.c system-timer.c mpu.c
|
||||||
|
|
||||||
STM32W_S = spmr.s79 context-switch.s79
|
STM32W_S = spmr.s79 context-switch.s79
|
||||||
|
|
||||||
|
@ -163,7 +168,7 @@ endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
FLASHER = $(CONTIKI)/tools/stm32w/stm32w_flasher/stm32w_flasher
|
FLASHER = sudo $(CONTIKI)/tools/stm32w/stm32w_flasher/stm32w_flasher
|
||||||
|
|
||||||
# Check if we are running under Windows
|
# Check if we are running under Windows
|
||||||
ifeq ($(HOST_OS),Windows)
|
ifeq ($(HOST_OS),Windows)
|
||||||
|
@ -224,11 +229,11 @@ CUSTOM_RULE_C_TO_CE = 1
|
||||||
|
|
||||||
CUSTOM_RULE_LINK = 1
|
CUSTOM_RULE_LINK = 1
|
||||||
|
|
||||||
.PHONY: symbols.c symbols.h
|
|
||||||
ifdef CORE
|
ifdef CORE
|
||||||
ifeq ($(wildcard $(CORE)),)
|
ifeq ($(wildcard $(CORE)),)
|
||||||
${error $(CORE) doesn't exist}
|
${error $(CORE) doesn't exist}
|
||||||
endif
|
endif
|
||||||
|
.PHONY: symbols.c symbols.h
|
||||||
symbols.c:
|
symbols.c:
|
||||||
$(NM) $(CORE) | awk -f $(CONTIKI)/tools/mknmlist > symbols.c
|
$(NM) $(CORE) | awk -f $(CONTIKI)/tools/mknmlist > symbols.c
|
||||||
else
|
else
|
||||||
|
@ -250,6 +255,19 @@ endif
|
||||||
|
|
||||||
endif #IAR
|
endif #IAR
|
||||||
|
|
||||||
|
MOTELIST = $(CONTIKI)/tools/stm32w/motelist-linux
|
||||||
|
|
||||||
|
MOTES = $(shell $(MOTELIST) 2>&- | grep USB | \
|
||||||
|
cut -f 4 -d \ | \
|
||||||
|
perl -ne 'print $$1 . " " if(m-(/dev/\w+)-);')
|
||||||
|
|
||||||
|
motelist: stm-motelist
|
||||||
|
|
||||||
|
stm-motelist:
|
||||||
|
$(MOTELIST)
|
||||||
|
stm-motes:
|
||||||
|
@echo $(MOTES)
|
||||||
|
|
||||||
$(OBJECTDIR)/%.o: %.s79
|
$(OBJECTDIR)/%.o: %.s79
|
||||||
$(AS) $(ASFLAGS) -o $@ $<
|
$(AS) $(ASFLAGS) -o $@ $<
|
||||||
|
|
||||||
|
@ -258,7 +276,24 @@ $(OBJECTDIR)/%.o: %.s
|
||||||
|
|
||||||
%.bin: %.$(TARGET)
|
%.bin: %.$(TARGET)
|
||||||
$(OBJCOPY) $(OBJOPTS) $< $@
|
$(OBJCOPY) $(OBJOPTS) $< $@
|
||||||
|
|
||||||
%.flash: %.bin
|
# reset all stm32w devices sequentially, as stm32w_flasher cannot access different ports in parallel
|
||||||
$(FLASHER) $(FLASHEROPTS) $<
|
stm-reset:
|
||||||
|
$(foreach PORT, $(MOTES), $(FLASHER) -r -p $(PORT);$(\n))
|
||||||
|
@echo Done
|
||||||
|
|
||||||
|
ifdef MOTE
|
||||||
|
%.upload: %.bin
|
||||||
|
$(FLASHER) $(FLASHEROPTS) $< -p $(word $(MOTE), $(MOTES))
|
||||||
|
else # MOTE
|
||||||
|
%.upload: %.bin
|
||||||
|
$(foreach PORT, $(MOTES), $(FLASHER) $(FLASHEROPTS) $< -p $(PORT);$(\n))
|
||||||
|
endif # MOTE
|
||||||
|
|
||||||
|
ifdef MOTE
|
||||||
|
login:
|
||||||
|
$(SERIALDUMP) -b115200 -d10000 $(USBDEVPREFIX)$(word $(MOTE), $(MOTES))
|
||||||
|
else
|
||||||
|
login:
|
||||||
|
$(SERIALDUMP) -b115200 -d10000 $(USBDEVPREFIX)$(firstword $(MOTES))
|
||||||
|
endif
|
||||||
|
|
|
@ -21,8 +21,8 @@ endif
|
||||||
%.so: $(OBJECTDIR)/%.o
|
%.so: $(OBJECTDIR)/%.o
|
||||||
$(LD) -shared -o $@ $^
|
$(LD) -shared -o $@ $^
|
||||||
|
|
||||||
# .PHONY: symbols.c symbols.h
|
|
||||||
ifdef CORE
|
ifdef CORE
|
||||||
|
.PHONY: symbols.c symbols.h
|
||||||
symbols.c symbols.h:
|
symbols.c symbols.h:
|
||||||
$(NM) $(CORE) | awk -f $(CONTIKI)/tools/mknmlist > symbols.c
|
$(NM) $(CORE) | awk -f $(CONTIKI)/tools/mknmlist > symbols.c
|
||||||
else
|
else
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
|
|
||||||
#include "contiki.h"
|
#include "contiki.h"
|
||||||
#include "net/rime.h"
|
#include "net/rime.h"
|
||||||
|
#include "net/netstack.h"
|
||||||
|
|
||||||
#include "dev/leds.h"
|
#include "dev/leds.h"
|
||||||
#include "dev/cc2420.h"
|
#include "dev/cc2420.h"
|
||||||
|
@ -81,7 +82,7 @@ PROCESS_THREAD(scanner_process, ev, data)
|
||||||
{
|
{
|
||||||
PROCESS_BEGIN();
|
PROCESS_BEGIN();
|
||||||
/* switch mac layer off, and turn radio on */
|
/* switch mac layer off, and turn radio on */
|
||||||
rime_mac->off(0);
|
NETSTACK_MAC.off(0);
|
||||||
cc2420_on();
|
cc2420_on();
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "contiki.h"
|
#include "contiki.h"
|
||||||
|
#include "net/netstack.h"
|
||||||
#include "net/rime.h"
|
#include "net/rime.h"
|
||||||
#include "net/rime/collect.h"
|
#include "net/rime/collect.h"
|
||||||
#include "net/rime/collect-neighbor.h"
|
#include "net/rime/collect-neighbor.h"
|
||||||
|
@ -133,7 +134,7 @@ do_rssi(void)
|
||||||
static int sample;
|
static int sample;
|
||||||
int channel;
|
int channel;
|
||||||
|
|
||||||
rime_mac->off(0);
|
NETSTACK_MAC.off(0);
|
||||||
|
|
||||||
cc2420_on();
|
cc2420_on();
|
||||||
for(channel = 11; channel <= 26; ++channel) {
|
for(channel = 11; channel <= 26; ++channel) {
|
||||||
|
@ -141,7 +142,7 @@ do_rssi(void)
|
||||||
rssi_samples[sample].channel[channel - 11] = cc2420_rssi() + 53;
|
rssi_samples[sample].channel[channel - 11] = cc2420_rssi() + 53;
|
||||||
}
|
}
|
||||||
|
|
||||||
rime_mac->on();
|
NETSTACK_MAC.on();
|
||||||
|
|
||||||
sample = (sample + 1) % NUM_SAMPLES;
|
sample = (sample + 1) % NUM_SAMPLES;
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
|
|
||||||
#include "contiki.h"
|
#include "contiki.h"
|
||||||
#include "net/rime.h"
|
#include "net/rime.h"
|
||||||
|
#include "net/netstack.h"
|
||||||
|
|
||||||
#include "dev/leds.h"
|
#include "dev/leds.h"
|
||||||
#include "dev/cc2420.h"
|
#include "dev/cc2420.h"
|
||||||
|
@ -83,7 +84,7 @@ PROCESS_THREAD(scanner_process, ev, data)
|
||||||
{
|
{
|
||||||
PROCESS_BEGIN();
|
PROCESS_BEGIN();
|
||||||
/* switch mac layer off, and turn radio on */
|
/* switch mac layer off, and turn radio on */
|
||||||
rime_mac->off(0);
|
NETSTACK_MAC.off(0);
|
||||||
cc2420_on();
|
cc2420_on();
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
|
|
|
@ -22,8 +22,3 @@ SERIALDUMP = $(CONTIKI)/tools/stm32w/serialdump-linux
|
||||||
ifeq ($(HOST_OS),Windows)
|
ifeq ($(HOST_OS),Windows)
|
||||||
SERIALDUMP = $(CONTIKI)/tools/stm32w/serialdump-windows
|
SERIALDUMP = $(CONTIKI)/tools/stm32w/serialdump-windows
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
login:
|
|
||||||
$(SERIALDUMP) -b115200 -d10000 $(PORT)
|
|
||||||
|
|
|
@ -172,6 +172,18 @@ main(int argc, char **argv)
|
||||||
contiki_argc = argc;
|
contiki_argc = argc;
|
||||||
contiki_argv = argv;
|
contiki_argv = argv;
|
||||||
|
|
||||||
|
/* native under windows is hardcoded to use the first one or two args */
|
||||||
|
/* for wpcap configuration so this needs to be "removed" from */
|
||||||
|
/* contiki_args (used by the native-border-router) */
|
||||||
|
#ifdef __CYGWIN__
|
||||||
|
contiki_argc--;
|
||||||
|
contiki_argv++;
|
||||||
|
#ifdef UIP_FALLBACK_INTERFACE
|
||||||
|
contiki_argc--;
|
||||||
|
contiki_argv++;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
process_init();
|
process_init();
|
||||||
process_start(&etimer_process, NULL);
|
process_start(&etimer_process, NULL);
|
||||||
ctimer_init();
|
ctimer_init();
|
||||||
|
|
|
@ -36,7 +36,6 @@ import java.io.IOException;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
|
|
||||||
|
@ -582,9 +581,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
|
||||||
/* Match file */
|
/* Match file */
|
||||||
Hashtable<Integer, Integer> lineTable = debuggingInfo.get(file);
|
Hashtable<Integer, Integer> lineTable = debuggingInfo.get(file);
|
||||||
if (lineTable == null) {
|
if (lineTable == null) {
|
||||||
Enumeration<File> fileEnum = debuggingInfo.keys();
|
for (File f: debuggingInfo.keySet()) {
|
||||||
while (fileEnum.hasMoreElements()) {
|
|
||||||
File f = fileEnum.nextElement();
|
|
||||||
if (f != null && f.getName().equals(file.getName())) {
|
if (f != null && f.getName().equals(file.getName())) {
|
||||||
lineTable = debuggingInfo.get(f);
|
lineTable = debuggingInfo.get(f);
|
||||||
break;
|
break;
|
||||||
|
@ -598,9 +595,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
|
||||||
/* Match line number */
|
/* Match line number */
|
||||||
Integer address = lineTable.get(lineNr);
|
Integer address = lineTable.get(lineNr);
|
||||||
if (address != null) {
|
if (address != null) {
|
||||||
Enumeration<Integer> lineEnum = lineTable.keys();
|
for (Integer l: lineTable.keySet()) {
|
||||||
while (lineEnum.hasMoreElements()) {
|
|
||||||
Integer l = lineEnum.nextElement();
|
|
||||||
if (l != null && l.intValue() == lineNr) {
|
if (l != null && l.intValue() == lineNr) {
|
||||||
/* Found line address */
|
/* Found line address */
|
||||||
return lineTable.get(l);
|
return lineTable.get(l);
|
||||||
|
|
|
@ -317,7 +317,7 @@ public abstract class MspMoteType implements MoteType {
|
||||||
logger.warn("Old simulation config detected: SkySerial was replaced by MspSerial");
|
logger.warn("Old simulation config detected: SkySerial was replaced by MspSerial");
|
||||||
intfClass = MspSerial.class.getName();
|
intfClass = MspSerial.class.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
Class<? extends MoteInterface> moteInterfaceClass =
|
Class<? extends MoteInterface> moteInterfaceClass =
|
||||||
simulation.getGUI().tryLoadClass(this, MoteInterface.class, intfClass);
|
simulation.getGUI().tryLoadClass(this, MoteInterface.class, intfClass);
|
||||||
|
|
||||||
|
@ -368,7 +368,7 @@ public abstract class MspMoteType implements MoteType {
|
||||||
private static ELF loadELF(String filepath) throws IOException {
|
private static ELF loadELF(String filepath) throws IOException {
|
||||||
return ELF.readELF(filepath);
|
return ELF.readELF(filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ELF elf; /* cached */
|
private ELF elf; /* cached */
|
||||||
public ELF getELF() throws IOException {
|
public ELF getELF() throws IOException {
|
||||||
if (elf == null) {
|
if (elf == null) {
|
||||||
|
@ -379,9 +379,9 @@ public abstract class MspMoteType implements MoteType {
|
||||||
}
|
}
|
||||||
return elf;
|
return elf;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Hashtable<File, Hashtable<Integer, Integer>> debuggingInfo = null; /* cached */
|
private Hashtable<File, Hashtable<Integer, Integer>> debuggingInfo = null; /* cached */
|
||||||
public Hashtable<File, Hashtable<Integer, Integer>> getFirmwareDebugInfo()
|
public Hashtable<File, Hashtable<Integer, Integer>> getFirmwareDebugInfo()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (debuggingInfo == null) {
|
if (debuggingInfo == null) {
|
||||||
debuggingInfo = getFirmwareDebugInfo(getELF());
|
debuggingInfo = getFirmwareDebugInfo(getELF());
|
||||||
|
@ -407,33 +407,35 @@ public abstract class MspMoteType implements MoteType {
|
||||||
|
|
||||||
for (int address: addresses) {
|
for (int address: addresses) {
|
||||||
DebugInfo info = elf.getDebugInfo(address);
|
DebugInfo info = elf.getDebugInfo(address);
|
||||||
|
if (info == null) {
|
||||||
if (info != null && info.getPath() != null && info.getFile() != null && info.getLine() >= 0) {
|
continue;
|
||||||
|
|
||||||
/* Nasty Cygwin-Windows fix */
|
|
||||||
String path = info.getPath();
|
|
||||||
if (path.contains("/cygdrive/")) {
|
|
||||||
int index = path.indexOf("/cygdrive/");
|
|
||||||
char driveCharacter = path.charAt(index+10);
|
|
||||||
|
|
||||||
path = path.replace("/cygdrive/" + driveCharacter + "/", driveCharacter + ":/");
|
|
||||||
}
|
|
||||||
|
|
||||||
File file = new File(path, info.getFile());
|
|
||||||
try {
|
|
||||||
file = file.getCanonicalFile();
|
|
||||||
} catch (IOException e) {
|
|
||||||
} catch (java.security.AccessControlException e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
Hashtable<Integer, Integer> lineToAddrHash = fileToLineHash.get(file);
|
|
||||||
if (lineToAddrHash == null) {
|
|
||||||
lineToAddrHash = new Hashtable<Integer, Integer>();
|
|
||||||
fileToLineHash.put(file, lineToAddrHash);
|
|
||||||
}
|
|
||||||
|
|
||||||
lineToAddrHash.put(info.getLine(), address);
|
|
||||||
}
|
}
|
||||||
|
if (info.getPath() == null && info.getFile() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (info.getLine() < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
File file;
|
||||||
|
if (info.getPath() != null) {
|
||||||
|
file = new File(info.getPath(), info.getFile());
|
||||||
|
} else {
|
||||||
|
file = new File(info.getFile());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
file = file.getCanonicalFile();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} catch (java.security.AccessControlException e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Hashtable<Integer, Integer> lineToAddrHash = fileToLineHash.get(file);
|
||||||
|
if (lineToAddrHash == null) {
|
||||||
|
lineToAddrHash = new Hashtable<Integer, Integer>();
|
||||||
|
fileToLineHash.put(file, lineToAddrHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
lineToAddrHash.put(info.getLine(), address);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileToLineHash;
|
return fileToLineHash;
|
||||||
|
|
|
@ -163,6 +163,8 @@ public class CodeUI extends JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Configure breakpoint menu options */
|
/* Configure breakpoint menu options */
|
||||||
|
/* XXX TODO We should ask for the file specified in the firmware, not
|
||||||
|
* the actual file on disk. */
|
||||||
Integer address =
|
Integer address =
|
||||||
CodeUI.this.mote.getExecutableAddressOf(displayedFile, line);
|
CodeUI.this.mote.getExecutableAddressOf(displayedFile, line);
|
||||||
if (address == null) {
|
if (address == null) {
|
||||||
|
@ -254,7 +256,8 @@ public class CodeUI extends JPanel {
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
displayedFile = null;
|
displayedFile = null;
|
||||||
codeEditor.setText(null);
|
codeEditor.setText("[no source displayed]");
|
||||||
|
codeEditor.setEnabled(false);
|
||||||
codeEditorLines.clear();
|
codeEditorLines.clear();
|
||||||
displayLine(-1, markCurrent);
|
displayLine(-1, markCurrent);
|
||||||
}
|
}
|
||||||
|
@ -275,6 +278,7 @@ public class CodeUI extends JPanel {
|
||||||
displayNoCode(markCurrent);
|
displayNoCode(markCurrent);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
codeEditor.setEnabled(true);
|
||||||
|
|
||||||
String[] lines = data.split("\n");
|
String[] lines = data.split("\n");
|
||||||
logger.info("Opening " + codeFile + " (" + lines.length + " lines)");
|
logger.info("Opening " + codeFile + " (" + lines.length + " lines)");
|
||||||
|
|
|
@ -32,12 +32,15 @@ package se.sics.cooja.mspmote.plugins;
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
|
import java.awt.Window;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
|
|
||||||
|
@ -47,23 +50,23 @@ import javax.swing.Box;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
import javax.swing.JFileChooser;
|
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JList;
|
import javax.swing.JList;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.JSplitPane;
|
||||||
import javax.swing.JTabbedPane;
|
import javax.swing.JTabbedPane;
|
||||||
import javax.swing.JTextField;
|
import javax.swing.JTable;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.filechooser.FileFilter;
|
|
||||||
import javax.swing.plaf.basic.BasicComboBoxRenderer;
|
import javax.swing.plaf.basic.BasicComboBoxRenderer;
|
||||||
|
import javax.swing.table.AbstractTableModel;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.jdom.Element;
|
import org.jdom.Element;
|
||||||
|
|
||||||
import se.sics.cooja.ClassDescription;
|
import se.sics.cooja.ClassDescription;
|
||||||
import se.sics.cooja.GUI;
|
import se.sics.cooja.GUI;
|
||||||
import se.sics.cooja.GUI.RunnableInEDT;
|
|
||||||
import se.sics.cooja.Mote;
|
import se.sics.cooja.Mote;
|
||||||
import se.sics.cooja.MotePlugin;
|
import se.sics.cooja.MotePlugin;
|
||||||
import se.sics.cooja.PluginType;
|
import se.sics.cooja.PluginType;
|
||||||
|
@ -72,6 +75,7 @@ import se.sics.cooja.VisPlugin;
|
||||||
import se.sics.cooja.Watchpoint;
|
import se.sics.cooja.Watchpoint;
|
||||||
import se.sics.cooja.WatchpointMote;
|
import se.sics.cooja.WatchpointMote;
|
||||||
import se.sics.cooja.WatchpointMote.WatchpointListener;
|
import se.sics.cooja.WatchpointMote.WatchpointListener;
|
||||||
|
import se.sics.cooja.dialogs.MessageList;
|
||||||
import se.sics.cooja.mspmote.MspMote;
|
import se.sics.cooja.mspmote.MspMote;
|
||||||
import se.sics.cooja.mspmote.MspMoteType;
|
import se.sics.cooja.mspmote.MspMoteType;
|
||||||
import se.sics.mspsim.core.EmulationException;
|
import se.sics.mspsim.core.EmulationException;
|
||||||
|
@ -103,11 +107,14 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
||||||
private WatchpointListener watchpointListener;
|
private WatchpointListener watchpointListener;
|
||||||
|
|
||||||
private JComboBox fileComboBox;
|
private JComboBox fileComboBox;
|
||||||
private String[] debugInfoMap = null;
|
|
||||||
private File[] sourceFiles;
|
private File[] sourceFiles;
|
||||||
|
|
||||||
private JTabbedPane mainPane;
|
private JTabbedPane mainPane;
|
||||||
|
|
||||||
|
private ArrayList<Rule> rules;
|
||||||
|
private ELFDebug debug;
|
||||||
|
private String[] debugSourceFiles;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mini-debugger for MSP Motes.
|
* Mini-debugger for MSP Motes.
|
||||||
* Visualizes instructions, source code and allows a user to manipulate breakpoints.
|
* Visualizes instructions, source code and allows a user to manipulate breakpoints.
|
||||||
|
@ -121,6 +128,41 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
||||||
simulation = simulationToVisualize;
|
simulation = simulationToVisualize;
|
||||||
this.mspMote = (MspMote) mote;
|
this.mspMote = (MspMote) mote;
|
||||||
this.watchpointMote = (WatchpointMote) mote;
|
this.watchpointMote = (WatchpointMote) mote;
|
||||||
|
try {
|
||||||
|
debug = ((MspMoteType)mspMote.getType()).getELF().getDebug();
|
||||||
|
if (debug == null) {
|
||||||
|
throw new RuntimeException("No debugging info found in firmware, aborting");
|
||||||
|
}
|
||||||
|
debugSourceFiles = debug.getSourceFiles();
|
||||||
|
if (debugSourceFiles == null) {
|
||||||
|
throw new RuntimeException("No debugging info found in firmware, aborting");
|
||||||
|
}
|
||||||
|
} catch (IOException e1) {
|
||||||
|
throw new RuntimeException("No debugging info found in firmware, aborting");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX Temporary workaround: source file removing duplicates awaiting Mspsim update */
|
||||||
|
{
|
||||||
|
ArrayList<String> newDebugSourceFiles = new ArrayList<String>();
|
||||||
|
for (String sf: debugSourceFiles) {
|
||||||
|
boolean found = false;
|
||||||
|
for (String nsf: newDebugSourceFiles) {
|
||||||
|
if (sf.equals(nsf)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
newDebugSourceFiles.add(sf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debugSourceFiles = newDebugSourceFiles.toArray(new String[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rules = new ArrayList<Rule>();
|
||||||
|
|
||||||
|
loadDefaultRules();
|
||||||
|
|
||||||
getContentPane().setLayout(new BorderLayout());
|
getContentPane().setLayout(new BorderLayout());
|
||||||
|
|
||||||
|
@ -150,7 +192,6 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
updateFileComboBox();
|
|
||||||
|
|
||||||
/* Browse code control (north) */
|
/* Browse code control (north) */
|
||||||
Box sourceCodeControl = Box.createHorizontalBox();
|
Box sourceCodeControl = Box.createHorizontalBox();
|
||||||
|
@ -223,8 +264,13 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
||||||
showCurrentPC();
|
showCurrentPC();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void startPlugin() {
|
||||||
|
super.startPlugin();
|
||||||
|
updateFileComboBox();
|
||||||
|
}
|
||||||
|
|
||||||
private void updateFileComboBox() {
|
private void updateFileComboBox() {
|
||||||
sourceFiles = getSourceFiles(mspMote, debugInfoMap);
|
sourceFiles = getSourceFiles(mspMote, rules);
|
||||||
fileComboBox.removeAllItems();
|
fileComboBox.removeAllItems();
|
||||||
fileComboBox.addItem("[view sourcefile]");
|
fileComboBox.addItem("[view sourcefile]");
|
||||||
for (File f: sourceFiles) {
|
for (File f: sourceFiles) {
|
||||||
|
@ -288,39 +334,22 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
||||||
currentCodeFile = null;
|
currentCodeFile = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ELFDebug debug = ((MspMoteType)mspMote.getType()).getELF().getDebug();
|
|
||||||
if (debug == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int pc = mspMote.getCPU().getPC();
|
int pc = mspMote.getCPU().getPC();
|
||||||
DebugInfo debugInfo = debug.getDebugInfo(pc);
|
DebugInfo debugInfo = debug.getDebugInfo(pc);
|
||||||
|
if (pc <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (debugInfo == null) {
|
if (debugInfo == null) {
|
||||||
if (pc != 0) {
|
logger.warn("No source info at " + String.format("0x%04x", pc));
|
||||||
logger.warn("No sourcecode info at " + String.format("0x%04x", mspMote.getCPU().getPC()));
|
return;
|
||||||
}
|
}
|
||||||
|
File f = applySubstitutionRules(new File(debugInfo.getPath(), debugInfo.getFile()), rules);
|
||||||
|
if (f == null || !f.exists()) {
|
||||||
|
logger.warn("Unknown source at " + String.format("0x%04x", pc) + ": " + debugInfo.getPath() + " " + debugInfo.getFile());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String path = new File(debugInfo.getPath(), debugInfo.getFile()).getPath();
|
currentCodeFile = f;
|
||||||
if (path == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
path = path.replace('\\', '/');
|
|
||||||
|
|
||||||
/* Debug info to source file map */
|
|
||||||
if (debugInfoMap != null && debugInfoMap.length == 2) {
|
|
||||||
if (path.startsWith(debugInfoMap[0])) {
|
|
||||||
path = debugInfoMap[1] + path.substring(debugInfoMap[0].length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Nasty Cygwin-Windows fix */
|
|
||||||
if (path.length() > 10 && path.startsWith("/cygdrive/")) {
|
|
||||||
char driveCharacter = path.charAt(10);
|
|
||||||
path = driveCharacter + ":/" + path.substring(11);
|
|
||||||
}
|
|
||||||
|
|
||||||
currentCodeFile = new File(path).getCanonicalFile();
|
|
||||||
currentLineNumber = debugInfo.getLine();
|
currentLineNumber = debugInfo.getLine();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.fatal("Exception: " + e.getMessage(), e);
|
logger.fatal("Exception: " + e.getMessage(), e);
|
||||||
|
@ -329,147 +358,332 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryMapDebugInfo() {
|
private int getLocatedSourcesCount() {
|
||||||
final String[] debugFiles;
|
File files[] = getSourceFiles(mspMote, rules);
|
||||||
try {
|
if (files == null) {
|
||||||
|
return 0;
|
||||||
ELFDebug debug = ((MspMoteType)mspMote.getType()).getELF().getDebug();
|
|
||||||
debugFiles = debug != null ? debug.getSourceFiles() : null;
|
|
||||||
if (debugFiles == null) {
|
|
||||||
logger.fatal("Error: No debug information is available");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (IOException e1) {
|
|
||||||
logger.fatal("Error: " + e1.getMessage(), e1);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
String[] map = new RunnableInEDT<String[]>() {
|
return files.length;
|
||||||
public String[] work() {
|
}
|
||||||
/* Select which source file to use */
|
|
||||||
int counter = 0, n;
|
|
||||||
File correspondingFile = null;
|
|
||||||
while (true) {
|
|
||||||
n = JOptionPane.showOptionDialog(GUI.getTopParentContainer(),
|
|
||||||
"Choose which source file to manually locate.\n\n" +
|
|
||||||
"Some source files may not exist, as debug info is also inherited from the toolchain.\n" +
|
|
||||||
"\"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,
|
|
||||||
new String[] { "Next File", "Locate File", "Cancel"}, "Next File");
|
|
||||||
if (n == JOptionPane.CANCEL_OPTION || n == JOptionPane.CLOSED_OPTION) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (n == JOptionPane.NO_OPTION) {
|
|
||||||
/* Locate file */
|
|
||||||
final String filename = new File(debugFiles[counter]).getName();
|
|
||||||
JFileChooser fc = new JFileChooser();
|
|
||||||
fc.setFileFilter(new FileFilter() {
|
|
||||||
public boolean accept(File file) {
|
|
||||||
if (file.isDirectory()) { return true; }
|
|
||||||
if (file.getName().equals(filename)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
public String getDescription() {
|
|
||||||
return "Source file " + filename;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
fc.setCurrentDirectory(new File(GUI.getExternalToolsSetting("PATH_CONTIKI", ".")));
|
|
||||||
int returnVal = fc.showOpenDialog(GUI.getTopParentContainer());
|
|
||||||
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
|
||||||
correspondingFile = fc.getSelectedFile();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n == JOptionPane.YES_OPTION) {
|
private void updateRulesUsage() {
|
||||||
/* Next file */
|
for (Rule rule: rules) {
|
||||||
counter = (counter+1) % debugFiles.length;
|
rule.prefixMatches = 0;
|
||||||
}
|
rule.locatesFile = 0;
|
||||||
}
|
}
|
||||||
|
getSourceFiles(mspMote, rules);
|
||||||
/* Match files */
|
rulesMatched = new int[rules.size()];
|
||||||
try {
|
rulesOK = new int[rules.size()];
|
||||||
String canonDebug = debugFiles[counter];
|
for (int i=0; i < rules.size(); i++) {
|
||||||
String canonSelected = correspondingFile.getCanonicalFile().getPath().replace('\\', '/');
|
rulesMatched[i] = rules.get(i).prefixMatches;
|
||||||
|
rulesOK[i] = rules.get(i).locatesFile;
|
||||||
int offset = 0;
|
|
||||||
while (canonDebug.regionMatches(
|
|
||||||
true,
|
|
||||||
canonDebug.length()-offset,
|
|
||||||
canonSelected, canonSelected.length()-offset,
|
|
||||||
offset)) {
|
|
||||||
offset++;
|
|
||||||
if (offset >= canonDebug.length() ||
|
|
||||||
offset >= canonSelected.length())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
offset--;
|
|
||||||
String replace = canonDebug.substring(0, canonDebug.length() - offset);
|
|
||||||
String replacement = canonSelected.substring(0, canonSelected.length() - offset);
|
|
||||||
|
|
||||||
{
|
|
||||||
JTextField replaceInput = new JTextField(replace);
|
|
||||||
replaceInput.setEditable(true);
|
|
||||||
JTextField replacementInput = new JTextField(replacement);
|
|
||||||
replacementInput.setEditable(true);
|
|
||||||
|
|
||||||
Box box = Box.createVerticalBox();
|
|
||||||
box.add(new JLabel("Debug info file:"));
|
|
||||||
box.add(new JLabel(canonDebug));
|
|
||||||
box.add(new JLabel("Selected file:"));
|
|
||||||
box.add(new JLabel(canonSelected));
|
|
||||||
box.add(Box.createVerticalStrut(20));
|
|
||||||
box.add(new JLabel("Replacing:"));
|
|
||||||
box.add(replaceInput);
|
|
||||||
box.add(new JLabel("with:"));
|
|
||||||
box.add(replacementInput);
|
|
||||||
|
|
||||||
JOptionPane optionPane = new JOptionPane();
|
|
||||||
optionPane.setMessage(box);
|
|
||||||
optionPane.setMessageType(JOptionPane.INFORMATION_MESSAGE);
|
|
||||||
optionPane.setOptions(new String[] { "OK" });
|
|
||||||
optionPane.setInitialValue("OK");
|
|
||||||
JDialog dialog = optionPane.createDialog(
|
|
||||||
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 };
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.fatal("Error: " + e.getMessage(), e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.invokeAndWait();
|
|
||||||
|
|
||||||
if (map != null) {
|
|
||||||
debugInfoMap = map;
|
|
||||||
updateFileComboBox();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static File[] getSourceFiles(MspMote mote, String[] map) {
|
private class Rule {
|
||||||
final String[] sourceFiles;
|
String from = "";
|
||||||
try {
|
String to = "";
|
||||||
ELFDebug debug = ((MspMoteType)mote.getType()).getELF().getDebug();
|
int prefixMatches = 0;
|
||||||
sourceFiles = debug != null ? debug.getSourceFiles() : null;
|
int locatesFile = 0;
|
||||||
if (sourceFiles == null) {
|
public Rule(String from, String to) {
|
||||||
logger.fatal("Error: No debug information is available");
|
this.from = from;
|
||||||
return new File[0];
|
this.to = to;
|
||||||
|
}
|
||||||
|
File apply(File f) {
|
||||||
|
if (f == null) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
} catch (IOException e1) {
|
if (from == null) {
|
||||||
logger.fatal("Error: " + e1.getMessage(), e1);
|
return null;
|
||||||
|
}
|
||||||
|
if (!f.getPath().startsWith(from)) {
|
||||||
|
if (rulesWithDebuggingOutput) {
|
||||||
|
rulesDebuggingOutput.addMessage(this + " does not match: " + f.getPath(), MessageList.ERROR);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
prefixMatches++;
|
||||||
|
if (rulesWithDebuggingOutput) {
|
||||||
|
rulesDebuggingOutput.addMessage(this + " testing on: " + f.getPath());
|
||||||
|
}
|
||||||
|
if (to == null) {
|
||||||
|
if (rulesWithDebuggingOutput) {
|
||||||
|
rulesDebuggingOutput.addMessage(this + " enter substition: " + f.getPath(), MessageList.ERROR);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
File file = new File(to + f.getPath().substring(from.length()));
|
||||||
|
if (!file.exists()) {
|
||||||
|
if (rulesWithDebuggingOutput) {
|
||||||
|
rulesDebuggingOutput.addMessage(this + " not found: " + file.getPath(), MessageList.ERROR);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (rulesWithDebuggingOutput) {
|
||||||
|
rulesDebuggingOutput.addMessage(this + " OK: " + f.getPath());
|
||||||
|
}
|
||||||
|
locatesFile++;
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
public String toString() {
|
||||||
|
return "[" + from + "|" + to + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File applySubstitutionRules(String file, Collection<Rule> rules) {
|
||||||
|
return applySubstitutionRules(new File(file), rules);
|
||||||
|
}
|
||||||
|
private static File applySubstitutionRules(File file, Collection<Rule> rules) {
|
||||||
|
if (file == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (file.exists()) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Rule rule: rules) {
|
||||||
|
File f = rule.apply(file);
|
||||||
|
if (f != null && f.exists()) {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadDefaultRules() {
|
||||||
|
String rulesString = GUI.getExternalToolsSetting("MSPCODEWATCHER_RULES", "/cygdrive/c/*c:/");
|
||||||
|
String[] rulesArr = rulesString.split("\\*");
|
||||||
|
rules.clear();
|
||||||
|
for (int i=0; i < rulesArr.length/2; i++) {
|
||||||
|
Rule r = new Rule(rulesArr[i*2], rulesArr[i*2+1]);
|
||||||
|
if (r.from.equals("[empty]")) {
|
||||||
|
r.from = "";
|
||||||
|
}
|
||||||
|
if (r.to.equals("[empty]")) {
|
||||||
|
r.to = "";
|
||||||
|
}
|
||||||
|
rules.add(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MessageList rulesDebuggingOutput = new MessageList();
|
||||||
|
private boolean rulesWithDebuggingOutput = false;
|
||||||
|
private int[] rulesMatched = null;
|
||||||
|
private int[] rulesOK = null;
|
||||||
|
private JTable table = null;
|
||||||
|
private void tryMapDebugInfo() {
|
||||||
|
/* called from AWT */
|
||||||
|
int r = JOptionPane.showConfirmDialog(GUI.getTopParentContainer(),
|
||||||
|
"The firmware file " + mspMote.getType().getContikiFirmwareFile().getName() + " references " + debugSourceFiles.length + " source files.\n" +
|
||||||
|
"This function tries to locate these files on disk with a set of simple substitution rules.\n" +
|
||||||
|
"\n" +
|
||||||
|
"Right now " + getLocatedSourcesCount() + "/" + debugSourceFiles.length + " source files can be found.",
|
||||||
|
"Locate source files", JOptionPane.OK_CANCEL_OPTION);
|
||||||
|
if (r != JOptionPane.OK_OPTION) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* table with rules */
|
||||||
|
rulesDebuggingOutput.clearMessages();
|
||||||
|
final JDialog dialog = new JDialog((Window)GUI.getTopParentContainer(), "Locate source files");
|
||||||
|
dialog.setModal(true);
|
||||||
|
updateRulesUsage();
|
||||||
|
AbstractTableModel model = new AbstractTableModel() {
|
||||||
|
public int getRowCount() {
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
public int getColumnCount() {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
public String getColumnName(int col) {
|
||||||
|
if (col == 0) {
|
||||||
|
return "Prefix";
|
||||||
|
}
|
||||||
|
if (col == 1) {
|
||||||
|
return "Substitution";
|
||||||
|
}
|
||||||
|
if (col == 2) {
|
||||||
|
return "Matched";
|
||||||
|
}
|
||||||
|
if (col == 3) {
|
||||||
|
return "OK";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||||
|
if (rowIndex < 0 || rowIndex >= rules.size()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Rule rule = rules.get(rowIndex);
|
||||||
|
if (columnIndex == 0) {
|
||||||
|
return rule.from;
|
||||||
|
}
|
||||||
|
if (columnIndex == 1) {
|
||||||
|
return rule.to;
|
||||||
|
}
|
||||||
|
if (columnIndex == 2) {
|
||||||
|
if (rulesMatched == null || rowIndex >= rulesMatched.length) {
|
||||||
|
return "[click Apply]";
|
||||||
|
}
|
||||||
|
return rulesMatched[rowIndex];
|
||||||
|
}
|
||||||
|
if (columnIndex == 3) {
|
||||||
|
if (rulesOK == null || rowIndex >= rulesOK.length) {
|
||||||
|
return "[click Apply]";
|
||||||
|
}
|
||||||
|
return rulesOK[rowIndex];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public boolean isCellEditable(int row, int column) {
|
||||||
|
if (column == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (column == 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
|
||||||
|
Rule rule;
|
||||||
|
if (rowIndex < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (rowIndex < rules.size()) {
|
||||||
|
rule = rules.get(rowIndex);
|
||||||
|
} else {
|
||||||
|
do {
|
||||||
|
rule = new Rule("", "");
|
||||||
|
rules.add(rule);
|
||||||
|
} while (rowIndex >= rules.size());
|
||||||
|
}
|
||||||
|
if (columnIndex == 0) {
|
||||||
|
rule.from = (String) aValue;
|
||||||
|
}
|
||||||
|
if (columnIndex == 1) {
|
||||||
|
rule.to = (String) aValue;
|
||||||
|
}
|
||||||
|
rulesMatched = null;
|
||||||
|
rulesOK = null;
|
||||||
|
table.invalidate();
|
||||||
|
table.repaint();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
table = new JTable(model);
|
||||||
|
|
||||||
|
/* control panel: save/load, clear/apply/close */
|
||||||
|
final JButton applyButton = new JButton("Apply");
|
||||||
|
applyButton.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
/* Remove trailing empty rules */
|
||||||
|
ArrayList<Rule> trimmedRules = new ArrayList<Rule>();
|
||||||
|
for (Rule rule: rules) {
|
||||||
|
if (rule.from == null || rule.from.trim().isEmpty()) {
|
||||||
|
rule.from = "";
|
||||||
|
}
|
||||||
|
if (rule.to == null || rule.to.trim().isEmpty()) {
|
||||||
|
rule.to = "";
|
||||||
|
}
|
||||||
|
if (rule.from.isEmpty() && rule.to.isEmpty()) {
|
||||||
|
/* ignore */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
trimmedRules.add(rule);
|
||||||
|
}
|
||||||
|
rules = trimmedRules;
|
||||||
|
|
||||||
|
rulesDebuggingOutput.clearMessages();
|
||||||
|
rulesDebuggingOutput.addMessage("Applying " + rules.size() + " substitution rules");
|
||||||
|
rulesWithDebuggingOutput = true;
|
||||||
|
updateRulesUsage();
|
||||||
|
rulesWithDebuggingOutput = false;
|
||||||
|
rulesDebuggingOutput.addMessage("Done! " + "Located sources: " + getLocatedSourcesCount() + "/" + debugSourceFiles.length);
|
||||||
|
rulesDebuggingOutput.addMessage(" ");
|
||||||
|
for (String s: debugSourceFiles) {
|
||||||
|
File f = applySubstitutionRules(s, rules);
|
||||||
|
if (f == null || !f.exists()) {
|
||||||
|
rulesDebuggingOutput.addMessage("Not yet located: " + s, MessageList.ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table.invalidate();
|
||||||
|
table.repaint();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
JButton clearButton = new JButton("Clear");
|
||||||
|
clearButton.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
rules.clear();
|
||||||
|
applyButton.doClick();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
JButton loadButton = new JButton("Load default");
|
||||||
|
loadButton.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
loadDefaultRules();
|
||||||
|
applyButton.doClick();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
JButton saveButton = new JButton("Save as default");
|
||||||
|
saveButton.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (Rule r: rules) {
|
||||||
|
sb.append("*");
|
||||||
|
if (r.from.isEmpty()) {
|
||||||
|
sb.append("[empty]");
|
||||||
|
} else {
|
||||||
|
sb.append(r.from);
|
||||||
|
}
|
||||||
|
sb.append("*");
|
||||||
|
if (r.to.isEmpty()) {
|
||||||
|
sb.append("[empty]");
|
||||||
|
} else {
|
||||||
|
sb.append(r.to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sb.length() >= 1) {
|
||||||
|
GUI.setExternalToolsSetting("MSPCODEWATCHER_RULES", sb.substring(1));
|
||||||
|
} else {
|
||||||
|
GUI.setExternalToolsSetting("MSPCODEWATCHER_RULES", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
JButton closeButton = new JButton("Close");
|
||||||
|
closeButton.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
updateFileComboBox();
|
||||||
|
dialog.dispose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Box control = Box.createHorizontalBox();
|
||||||
|
control.add(loadButton);
|
||||||
|
control.add(saveButton);
|
||||||
|
control.add(Box.createHorizontalGlue());
|
||||||
|
control.add(clearButton);
|
||||||
|
control.add(applyButton);
|
||||||
|
control.add(closeButton);
|
||||||
|
|
||||||
|
final JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
|
||||||
|
new JScrollPane(table),
|
||||||
|
new JScrollPane(rulesDebuggingOutput));
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
split.setDividerLocation(0.5);
|
||||||
|
applyButton.doClick();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dialog.getContentPane().add(BorderLayout.CENTER, split);
|
||||||
|
dialog.getContentPane().add(BorderLayout.SOUTH, control);
|
||||||
|
dialog.getRootPane().setDefaultButton(closeButton);
|
||||||
|
dialog.setSize(550, 500);
|
||||||
|
dialog.setLocationRelativeTo(GUI.getTopParentContainer());
|
||||||
|
dialog.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private File[] getSourceFiles(MspMote mote, ArrayList<Rule> rules) {
|
||||||
File contikiSource = mote.getType().getContikiSourceFile();
|
File contikiSource = mote.getType().getContikiSourceFile();
|
||||||
if (contikiSource != null) {
|
if (contikiSource != null) {
|
||||||
try {
|
try {
|
||||||
|
@ -480,75 +694,22 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
||||||
|
|
||||||
/* Verify that files exist */
|
/* Verify that files exist */
|
||||||
ArrayList<File> existing = new ArrayList<File>();
|
ArrayList<File> existing = new ArrayList<File>();
|
||||||
for (String sourceFile: sourceFiles) {
|
for (String sourceFile: debugSourceFiles) {
|
||||||
|
|
||||||
/* Debug info to source file map */
|
/* Debug info to source file map */
|
||||||
sourceFile = sourceFile.replace('\\', '/');
|
File f = applySubstitutionRules(sourceFile, rules);
|
||||||
if (map != null && map.length == 2) {
|
if (f != null && f.exists()) {
|
||||||
if (sourceFile.startsWith(map[0])) {
|
existing.add(f);
|
||||||
sourceFile = map[1] + sourceFile.substring(map[0].length());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Nasty Cygwin-Windows fix */
|
|
||||||
if (sourceFile.length() > 10 && sourceFile.contains("/cygdrive/")) {
|
|
||||||
char driveCharacter = sourceFile.charAt(10);
|
|
||||||
sourceFile = driveCharacter + ":/" + sourceFile.substring(11);
|
|
||||||
}
|
|
||||||
|
|
||||||
File file = new File(sourceFile);
|
|
||||||
try {
|
|
||||||
file = file.getCanonicalFile();
|
|
||||||
} catch (IOException e1) {
|
|
||||||
}
|
|
||||||
if (!GUI.isVisualizedInApplet()) {
|
|
||||||
if (file.exists() && file.isFile()) {
|
|
||||||
existing.add(file);
|
|
||||||
} else {
|
|
||||||
/*logger.warn("Can't locate source file, skipping: " + file.getPath());*/
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Accept all files without existence check */
|
|
||||||
existing.add(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If no files were found, suggest map function */
|
|
||||||
if (sourceFiles.length > 0 && existing.isEmpty() && GUI.isVisualized()) {
|
|
||||||
new RunnableInEDT<Boolean>() {
|
|
||||||
public Boolean work() {
|
|
||||||
JOptionPane.showMessageDialog(
|
|
||||||
GUI.getTopParentContainer(),
|
|
||||||
"The firmware debug info specifies " + sourceFiles.length + " source files.\n" +
|
|
||||||
"However, Msp Code Watcher could not find any of these files.\n" +
|
|
||||||
"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",
|
|
||||||
JOptionPane.WARNING_MESSAGE);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}.invokeAndWait();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sort alphabetically */
|
/* Sort alphabetically */
|
||||||
ArrayList<File> sorted = new ArrayList<File>();
|
File[] sorted = existing.toArray(new File[0]);
|
||||||
for (File file: existing) {
|
Arrays.sort(sorted, new Comparator<File>() {
|
||||||
int index = 0;
|
public int compare(File o1, File o2) {
|
||||||
for (index=0; index < sorted.size(); index++) {
|
return o1.getName().compareToIgnoreCase(o2.getName());
|
||||||
if (file.getName().compareToIgnoreCase(sorted.get(index).getName()) < 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
sorted.add(index, file);
|
});
|
||||||
}
|
return sorted;
|
||||||
|
|
||||||
/* Add Contiki source first */
|
|
||||||
if (contikiSource != null && contikiSource.exists()) {
|
|
||||||
sorted.add(0, contikiSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sorted.toArray(new File[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Element> getConfigXML() {
|
public Collection<Element> getConfigXML() {
|
||||||
|
@ -559,13 +720,27 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
||||||
element.addContent("" + mainPane.getSelectedIndex());
|
element.addContent("" + mainPane.getSelectedIndex());
|
||||||
config.add(element);
|
config.add(element);
|
||||||
|
|
||||||
|
for (Rule rule: rules) {
|
||||||
|
element = new Element("rule");
|
||||||
|
element.setAttribute("from", rule.from==null?"":rule.from);
|
||||||
|
element.setAttribute("to", rule.to==null?"":rule.to);
|
||||||
|
config.add(element);
|
||||||
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean setConfigXML(Collection<Element> configXML, boolean visAvailable) {
|
public boolean setConfigXML(Collection<Element> configXML, boolean visAvailable) {
|
||||||
|
boolean clearedRules = false;
|
||||||
for (Element element : configXML) {
|
for (Element element : configXML) {
|
||||||
if (element.getName().equals("tab")) {
|
if (element.getName().equals("tab")) {
|
||||||
mainPane.setSelectedIndex(Integer.parseInt(element.getText()));
|
mainPane.setSelectedIndex(Integer.parseInt(element.getText()));
|
||||||
|
} else if (element.getName().equals("rule")) {
|
||||||
|
if (!clearedRules) {
|
||||||
|
rules.clear();
|
||||||
|
clearedRules = true;
|
||||||
|
}
|
||||||
|
rules.add(new Rule(element.getAttributeValue("from"), element.getAttributeValue("to")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -582,7 +757,7 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private AbstractAction mapAction = new AbstractAction("Locate sources") {
|
private AbstractAction mapAction = new AbstractAction("Locate sources...") {
|
||||||
private static final long serialVersionUID = -3929432830596292495L;
|
private static final long serialVersionUID = -3929432830596292495L;
|
||||||
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
|
|
@ -2943,10 +2943,24 @@ public class GUI extends Observable {
|
||||||
* null
|
* null
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
String logConfigFile = null;
|
||||||
|
for (String element : args) {
|
||||||
|
if (element.startsWith("-log4j=")) {
|
||||||
|
String arg = element.substring("-log4j=".length());
|
||||||
|
logConfigFile = arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Configure logger
|
// Configure logger
|
||||||
if ((new File(LOG_CONFIG_FILE)).exists()) {
|
if (logConfigFile != null) {
|
||||||
|
if (new File(logConfigFile).exists()) {
|
||||||
|
DOMConfigurator.configure(logConfigFile);
|
||||||
|
} else {
|
||||||
|
System.err.println("Failed to open " + logConfigFile);
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
} else if (new File(LOG_CONFIG_FILE).exists()) {
|
||||||
DOMConfigurator.configure(LOG_CONFIG_FILE);
|
DOMConfigurator.configure(LOG_CONFIG_FILE);
|
||||||
} else {
|
} else {
|
||||||
// Used when starting from jar
|
// Used when starting from jar
|
||||||
|
|
|
@ -696,7 +696,6 @@ public class ScriptRunner extends VisPlugin {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (fileChooser.showOpenDialog(scriptRunner) != JFileChooser.APPROVE_OPTION) {
|
if (fileChooser.showOpenDialog(scriptRunner) != JFileChooser.APPROVE_OPTION) {
|
||||||
logger.debug("cancel");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
scriptRunner.setLinkFile(fileChooser.getSelectedFile());
|
scriptRunner.setLinkFile(fileChooser.getSelectedFile());
|
||||||
|
|
280
tools/stm32w/motelist-linux
Normal file
280
tools/stm32w/motelist-linux
Normal file
|
@ -0,0 +1,280 @@
|
||||||
|
#!/usr/bin/perl -w
|
||||||
|
use strict;
|
||||||
|
# $Id: motelist-linux,v 1.1 2007/05/29 19:34:30 adam Exp $
|
||||||
|
# @author Cory Sharp <cory@moteiv.com>
|
||||||
|
# @author Joe Polastre
|
||||||
|
|
||||||
|
my $help = <<'EOF';
|
||||||
|
usage: motelist [options]
|
||||||
|
|
||||||
|
$Revision: 1.1 $
|
||||||
|
|
||||||
|
options:
|
||||||
|
-h display this help
|
||||||
|
-c compact format, not pretty but easier for parsing
|
||||||
|
-f specify the usb-serial file (for smote.cs)
|
||||||
|
-k kernel version: 2.4, 2.6, auto (default)
|
||||||
|
-m method to scan usb: procfs, sysfs, auto (default)
|
||||||
|
-dev_prefix force the device prefix for the serial device
|
||||||
|
-usb display extra usb information
|
||||||
|
EOF
|
||||||
|
|
||||||
|
my %Opt = (
|
||||||
|
compact => 0,
|
||||||
|
usb => 0,
|
||||||
|
method => "auto",
|
||||||
|
kernel => "auto",
|
||||||
|
dev_prefix => [ "/dev/usb/tts/", "/dev/ttyUSB", "/dev/tts/USB" ],
|
||||||
|
usbserial => "sudo cat /proc/tty/driver/usbserial |",
|
||||||
|
);
|
||||||
|
|
||||||
|
while (@ARGV) {
|
||||||
|
last unless $ARGV[0] =~ /^-/;
|
||||||
|
my $opt = shift @ARGV;
|
||||||
|
if( $opt eq "-h" ) { print "$help\n"; exit 0; }
|
||||||
|
elsif( $opt eq "-c" ) { $Opt{compact} = 1; }
|
||||||
|
elsif( $opt eq "-f" ) { $Opt{usbserial} = shift @ARGV; }
|
||||||
|
elsif( $opt eq "-k" ) { $Opt{kernel} = shift @ARGV; }
|
||||||
|
elsif( $opt eq "-m" ) { $Opt{method} = shift @ARGV; }
|
||||||
|
elsif( $opt eq "-dev_prefix" ) { $Opt{dev_prefix} = shift @ARGV; }
|
||||||
|
elsif( $opt eq "-usb" ) { $Opt{usb} = 1; }
|
||||||
|
else { print STDERR "$help\nerror, unknown command line option $opt\n"; exit 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if( $Opt{kernel} eq "auto" ) {
|
||||||
|
$Opt{kernel} = "unknown";
|
||||||
|
$Opt{kernel} = $1 if snarf("/proc/version") =~ /\bLinux version (\d+\.\d+)/;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( $Opt{method} eq "auto" ) {
|
||||||
|
$Opt{method} = ($Opt{kernel} eq "2.4") ? "procfs" : "sysfs";
|
||||||
|
}
|
||||||
|
|
||||||
|
my @devs = $Opt{method} eq "procfs" ? scan_procfs() : scan_sysfs();
|
||||||
|
print_motelist( sort { cmp_usbdev($a,$b) } @devs );
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# SysFS
|
||||||
|
#
|
||||||
|
sub scan_sysfs {
|
||||||
|
|
||||||
|
# Scan /sys/bus/usb/drivers/usb for FTDI devices
|
||||||
|
my @ftdidevs =
|
||||||
|
grep { ($_->{UsbVendor}||"") eq "0403" && ($_->{UsbProduct}||"") eq "6001" && ($_->{UsbBcdDevice}||"") eq "0600"}
|
||||||
|
map { {
|
||||||
|
SysPath => $_,
|
||||||
|
UsbVendor => snarf("$_/idVendor",1),
|
||||||
|
UsbProduct => snarf("$_/idProduct",1),
|
||||||
|
UsbBcdDevice => snarf("$_/bcdDevice",1),
|
||||||
|
} }
|
||||||
|
glob("/sys/bus/usb/drivers/usb/*");
|
||||||
|
|
||||||
|
# Gather information about each FTDI device
|
||||||
|
for my $f (@ftdidevs) {
|
||||||
|
my $syspath = $f->{SysPath};
|
||||||
|
|
||||||
|
$f->{InfoManufacturer} = snarf("$syspath/manufacturer",1);
|
||||||
|
$f->{InfoProduct} = snarf("$syspath/product",1);
|
||||||
|
$f->{InfoSerial} = snarf("$syspath/serial",1);
|
||||||
|
$f->{UsbDevNum} = snarf("$syspath/devnum",1);
|
||||||
|
print $syspath;
|
||||||
|
print "\n";
|
||||||
|
|
||||||
|
my $devstr = readlink($syspath);
|
||||||
|
if( $devstr =~ m{([^/]+)/usb(\d+)/.*-([^/]+)$} ) {
|
||||||
|
$f->{UsbPath} = "usb-$1-$3";
|
||||||
|
$f->{UsbBusNum} = $2;
|
||||||
|
}
|
||||||
|
($f->{SysDev} = $syspath) =~ s{^.*/}{};
|
||||||
|
|
||||||
|
my $port = "$syspath/$f->{SysDev}:1.0";
|
||||||
|
($f->{DriverName} = readlink("$port/driver")) =~ s{^.*/}{} if -l "$port/driver";
|
||||||
|
($f->{SerialDevName} = (glob("$port/tty*"),undef)[0]) =~ s{^.*/}{};
|
||||||
|
$f->{SerialDevNum} = $1 if $f->{SerialDevName} =~ /(\d+)/;
|
||||||
|
$f->{SerialDevName} = getSerialDevName( $f->{SerialDevNum} ) || " (none)";
|
||||||
|
}
|
||||||
|
|
||||||
|
return @ftdidevs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Scan Procfs
|
||||||
|
#
|
||||||
|
sub scan_procfs {
|
||||||
|
|
||||||
|
my $text_devs = snarf("< /proc/bus/usb/devices");
|
||||||
|
my $text_serial = snarf($Opt{usbserial});
|
||||||
|
|
||||||
|
my @usbdevs = map { {parse_usb_devices_text($_)} }
|
||||||
|
grep { !/^\s*$/ } split /\n+(?=T:)/, $text_devs;
|
||||||
|
my %usbtree = build_usb_tree( @usbdevs );
|
||||||
|
my %usbserialtree = build_usbserial_tree( $text_serial );
|
||||||
|
for my $tts ( values %usbserialtree ) {
|
||||||
|
$usbtree{usbkey($tts->{path})}{usbserial} = $tts if defined $tts->{path};
|
||||||
|
}
|
||||||
|
|
||||||
|
my @ftdidevs = map { {
|
||||||
|
UsbVendor => $_->{Vendor},
|
||||||
|
UsbProduct => $_->{ProdID},
|
||||||
|
UsbBcdDevice => $_->{BcdDevice},
|
||||||
|
InfoManufacturer => $_->{Manufacturer},
|
||||||
|
InfoProduct => $_->{Product},
|
||||||
|
InfoSerial => $_->{SerialNumber},
|
||||||
|
UsbBusNum => $_->{nbus},
|
||||||
|
UsbDevNum => $_->{ndev},
|
||||||
|
UsbPath => (($Opt{kernel} eq "2.4") ? $_->{usbserial}{path} : $_->{usbpath}),
|
||||||
|
DriverName => $_->{driver},
|
||||||
|
SerialDevNum => $_->{usbserial}{tts},
|
||||||
|
SerialDevName => getSerialDevName($_->{usbserial}{tts}) || " (none)",
|
||||||
|
} }
|
||||||
|
grep { ($_->{Vendor}||"") eq "0403" && ($_->{ProdID}||"") eq "6001" && ($_->{BcdDevice}||"") eq "0600"}
|
||||||
|
values %usbtree;
|
||||||
|
|
||||||
|
return @ftdidevs;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub build_usb_tree {
|
||||||
|
my @devs = @_;
|
||||||
|
my %tree = ();
|
||||||
|
for my $dev (sort { $a->{Lev} <=> $b->{Lev} } @devs) {
|
||||||
|
my ($bus,$lev,$prnt) = ( $dev->{Bus}+0, $dev->{Lev}+0, $dev->{Prnt}+0 );
|
||||||
|
my $devnum = $dev->{"Dev#"}+0;
|
||||||
|
$dev->{nbus} = $bus;
|
||||||
|
$dev->{ndev} = $devnum;
|
||||||
|
$tree{"bus$bus"} = {} unless exists $tree{"bus$bus"};
|
||||||
|
$tree{"bus$bus"}{"dev$devnum"} = $dev;
|
||||||
|
if( $lev == 0 ) {
|
||||||
|
$dev->{usbpath} = "usb-$dev->{SerialNumber}";
|
||||||
|
} else {
|
||||||
|
my $sep = ($lev==1) ? "-" : ".";
|
||||||
|
$dev->{parent} = $tree{"bus$bus"}{"dev$prnt"};
|
||||||
|
$dev->{usbpath} = $dev->{parent}{usbpath} . $sep . ($dev->{Port}+1);
|
||||||
|
}
|
||||||
|
$tree{usbkey($dev->{usbpath})} = $dev;
|
||||||
|
}
|
||||||
|
return %tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub parse_usb_devices_text {
|
||||||
|
my $text = shift;
|
||||||
|
$text =~ s/^\S+\s*//gm;
|
||||||
|
$text =~ s/\s*(\S+=)/\001$1/g;
|
||||||
|
return map { m/(.*?)=(.*)/ } split /\001/, $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub build_usbserial_tree {
|
||||||
|
my $text = shift;
|
||||||
|
my %tree = ();
|
||||||
|
while( $text =~ /^([^:]+):(.*)/mg ) {
|
||||||
|
my ($tts,$params) = ($1,$2);
|
||||||
|
$tree{$tts} = { tts => $tts };
|
||||||
|
while ($params =~ m/\s+([^:]+):(?:"([^"]*)"|(\S+))/g) {
|
||||||
|
$tree{$tts}{$1} = $2||$3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return %tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub usbkey {
|
||||||
|
if( $Opt{kernel} eq "2.4" ) {
|
||||||
|
(my $key = $_[0]) =~ s/^.*-//;
|
||||||
|
return $key;
|
||||||
|
}
|
||||||
|
return $_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# getSerialDevName
|
||||||
|
#
|
||||||
|
# For each device, force to use dev_prefix if it's not an array. Otherwise,
|
||||||
|
# assume it's a list of candidate prefixes. Check them and commit to the
|
||||||
|
# first one that actually exists.
|
||||||
|
#
|
||||||
|
sub getSerialDevName {
|
||||||
|
my $devnum = shift;
|
||||||
|
my $devname = undef;
|
||||||
|
if( defined $devnum ) {
|
||||||
|
if( ref($Opt{dev_prefix}) eq "ARRAY" ) {
|
||||||
|
$devname = $devnum;
|
||||||
|
for my $prefix (@{$Opt{dev_prefix}}) {
|
||||||
|
my $file = $prefix . $devnum;
|
||||||
|
if( -e $file ) { $devname = $file; last; }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$devname = $Opt{dev_prefix} . $devnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $devname;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Print motelist
|
||||||
|
#
|
||||||
|
sub print_motelist {
|
||||||
|
my @devs = @_;
|
||||||
|
|
||||||
|
# If none were found, quit
|
||||||
|
if( @devs == 0 ) {
|
||||||
|
print "No devices found.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Print a header
|
||||||
|
if( !$Opt{compact} ) {
|
||||||
|
if( $Opt{usb} ) {
|
||||||
|
print << "EOF" unless $Opt{compact};
|
||||||
|
Bus Dev USB Path Reference Device Description
|
||||||
|
--- --- ------------------------ ---------- ---------------- -------------------------------------
|
||||||
|
EOF
|
||||||
|
} else {
|
||||||
|
print << "EOF" unless $Opt{compact};
|
||||||
|
Reference Device Description
|
||||||
|
---------- ---------------- ---------------------------------------------
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Print the usb information
|
||||||
|
for my $dev (sort { cmp_usbdev($a,$b) } @devs) {
|
||||||
|
my $desc = join( " ", $dev->{InfoManufacturer}||"", $dev->{InfoProduct}||"" ) || " (none)";
|
||||||
|
my @output = ( $dev->{InfoSerial}||" (none)", $dev->{SerialDevName}, $desc );
|
||||||
|
@output = ( $dev->{UsbBusNum}, $dev->{UsbDevNum}, $dev->{UsbPath}, @output ) if $Opt{usb};
|
||||||
|
if( $Opt{compact} ) {
|
||||||
|
print join(",",@output) . "\n";
|
||||||
|
} else {
|
||||||
|
printf( ($Opt{usb}?"%3d %3d %-24s ":"")."%-10s %-16s %s\n", @output );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Cmp Usbdev's
|
||||||
|
#
|
||||||
|
sub cmp_usbdev {
|
||||||
|
my ($a,$b) = @_;
|
||||||
|
if( defined $a->{SerialDevNum} ) {
|
||||||
|
if( defined $b->{SerialDevNum} ) {
|
||||||
|
return $a->{SerialDevNum} <=> $b->{SerialDevNum};
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 1 if defined $b->{SerialDevNum};
|
||||||
|
return ($a->{InfoSerial}||"") cmp ($b->{InfoSerial}||"");
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Read a file in
|
||||||
|
#
|
||||||
|
sub snarf {
|
||||||
|
open my $fh, $_[0] or return undef;
|
||||||
|
my $text = do{local $/;<$fh>};
|
||||||
|
close $fh;
|
||||||
|
$text =~ s/\s+$// if $_[1];
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue