Code Search for Developers
 
 
  

sympathy_status.c from EmStar at Krugle


Show sympathy_status.c syntax highlighted

/* ex: set tabstop=2 expandtab shiftwidth=2 softtabstop=2: */
/*
 *
 * Copyright (c) 2003 The Regents of the University of California.  All 
 * rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Neither the name of the University 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 REGENTS 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 REGENTS 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.
 *
 */

 /*
  *
  * Author: Nithya Ramanthan
  *
  */

#include <sympathy.h>
#include <time.h>

typedef struct {
  /* Always keep request as the first field since its assumed */
  char request[10];
  int printed_usage;
  /* Has the same index into it as sink.status_srcs[] */
  int printed_root_cause[SMAX_SRCS];
  int printed_rc_period[SMAX_SRCS];
} sympathy_client_data_t;

typedef void (* node_metrics_print_t) (buf_t* buf, sympathy_node_info_t* stat,
    int html);
static
void print_summary(sympathy_node_info_t* stat, Sfail_summary_t* fail);
typedef node_metrics_print_t (* get_print_funct_t) (char type);
typedef void (* generic_t)(buf_t* buf);

static 
void print_failure_info(buf_t* buf, sympathy_node_info_t* stat, int html);

/*** Static Functions ***/

static
char* tos_packet_to_string(int i) {
  switch(i) {
    case(SBEACON): return "BEACON";
    case(SNEIGHBOR_ADVERT): return "NEIGHBOR";
    case(SPATH_ADVERT): return "ROUTE";
    case(SNON_ROUTING_PKT): return "GENERAL";
    case(SYMPATHY_PKT): return "SYMPATHY";
    default: return "Unknown";
  }
  return "Unknown";
}

static
char* get_comp_string(char* comp_name, int app_type)
{
  DECLARE_STATIC_BUF_RING(buf, 1, FUSD_MAX_NAME_LENGTH);
  if (comp_name) sprintf(buf, "Comp %s(%d)", 
        comp_name, app_type);
  else sprintf(buf, "\nComp %d", app_type);
  return buf;
}

static
char* print_pd_of_event(int val, struct timeval* event_time)
{
  unsigned long diff = misc_tv_offset_msec(event_time, &start_time);
  DECLARE_STATIC_BUF_RING(buf, 1, 20);

  if (event_time->tv_sec == 0) return "INF";
  diff /= METRICS_PERIOD_MSEC; /* Convert to #periods */
  if (val > 0) sprintf(buf, "pd %d", (int) diff);
  return buf;
}

int get_minutes_since_event(struct timeval* event_time)
{
  struct timeval now;
  gettimeofday(&now, NULL);
  misc_tv_sub(&now, event_time);
  return((int) now.tv_sec/60);
}

static
char* print_minutes_since_event(int val, struct timeval* event_time)
{
  DECLARE_STATIC_BUF_RING(buf, 1, 20);
  int min_data = get_minutes_since_event(event_time);
  if (val > 0) snprintf(buf, 20, "%d mins", min_data);
  else sprintf(buf, "INF");
  return buf;
}

sympathy_node_info_t* iter_next_hop(sympathy_node_info_t* stat, int* iter, int sink_id)
{
  sympathy_node_info_t* stat2;
  if ((!stat) || (stat->next_hop.next_hop == sink_id) 
      || (stat->next_hop.next_hop == 0)
      || (stat->addr == sink_id)) return NULL;

  (*iter) += 1;
  if (*iter >= 15) {
    elog(LOG_ERR, "ERROR: VERY BAD: Suspecting a routing loop!!\n");
    *iter = -1;
    return NULL;
  }
  else if (!(stat2 = find_status_ptr(stat->next_hop.next_hop)))
  {
    elog(LOG_ERR, "Unable to find node %d 's next-hop: %d\n",
      stat->addr, stat->next_hop.next_hop);
    return NULL;
  }
  else return stat2;
}

/* Prints the neighbor list for one node */
static void
print_node_neighbors(buf_t* buf, sympathy_node_info_t* stat, int html)
{
  neighbor_t* neighbors = stat->neighbors;
  sneighbor_info_t* neighbor_info = stat->neighbor_info;
  int i, num_neighbors = stat->num_neighbors;

  if(!neighbors_valid(stat)) return;

  if (num_neighbors > 0)
  {
    bufprintf(buf, "\nNode-ID\t Egress\t Ingress Avg Rssi  Age[min] Avg-ingress Max-change(Mins-since)\n");
    bufprintf(buf, "---------------------------------------------------------------\n");

    for (i = 0; i < num_neighbors; i++)
    {
      if (neighbors[i].node_id > 0)
      {
        bufprintf(buf, "%d\t %d\t %d\t %d\t %d\t %d\t\t %d(%d)\n", 
            neighbors[i].node_id, (int) neighbors[i].conn_to, 
            (int) neighbors[i].conn_from,
            neighbor_info[i].avg_rssi, 
          get_minutes_since_event(&neighbor_info[i].time_added), 
          neighbor_info[i].avg_ingress, 
          neighbor_info[i].max_ingress_change, 
          get_minutes_since_event(&neighbor_info[i].time_max_change));
      }
    }

    bufprintf(buf, "\n");
  }

  if ((stat->addr != my_node_id) &&
      ((stat->metrics_valid) || route_valid(stat)) &&
      (stat->next_hop.sink > 0))
  {
    bufprintf(buf, "\nSink    Next-Hop    Quality  Age[min]  Num-changes\n");
    bufprintf(buf, "-----------------------------------------------\n");
    bufprintf(buf,"%-4d    %-8d    %-7d   %-4s    %-5d\n", stat->next_hop.sink, 
	      stat->next_hop.next_hop, stat->next_hop.quality,
	      print_minutes_since_event(stat->next_hop_info.num_changes,
					&stat->next_hop_info.time_changed),
	      stat->next_hop_info.num_changes);
    bufprintf(buf, "\n");
  }
}

static void
print_node_neighbors_html(buf_t* buf, sympathy_node_info_t* stat, int html)
{
  neighbor_t* temp;
  neighbor_t*  neighbors = stat->neighbors;
  int i, j, k, num_neighbors = stat->num_neighbors;
  sneighbor_info_t* neighbor_info = stat->neighbor_info;
  neighbor_t* ordered_nbrs[MAX_NEIGHBORS];

  if(!neighbors_valid(stat)) return;

  if (num_neighbors > 0)
  {
    bufprintf(buf, "<table frame=void cellspacing=5 cellpadding=6>\n");
    bufprintf(buf, "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>",
	      "Node-ID", "Egress", "Ingress", "Age[min]",
	      "Avg-ingress", "Max-change(Mins-since)");
    bufprintf(buf, "<tr><td colspan=6>%s</td></tr>", "----------------------------------------------------------------------------------------------------------");

    /* order the nodes by ID */
    for(i = 0; i < num_neighbors; i++)
    {
      ordered_nbrs[i] = &neighbors[i];

      for (j = i - 1, k = i;
	   (j >= 0)  && (ordered_nbrs[k]->node_id < ordered_nbrs[j]->node_id);
	   j--, k--)
      {
  	  //swap
	  temp = ordered_nbrs[k];
	  ordered_nbrs[k] = ordered_nbrs[j];
	  ordered_nbrs[j] = temp;
      }
    }

    /* print the neighbors */
    for (i = 0; i < num_neighbors; i++)
    {
      if (ordered_nbrs[i]->node_id > 0)
      {
        bufprintf(buf, "<tr><td>%d</td><td>%d</td><td>%d</td><td>%d</td><td>%d</td><td>%d(%d)</td></tr>",
	          ordered_nbrs[i]->node_id,
	          (int) ordered_nbrs[i]->conn_to,
	          (int) ordered_nbrs[i]->conn_from,
		  get_minutes_since_event(&neighbor_info[i].time_added), 
		  neighbor_info[i].avg_ingress, 
		  neighbor_info[i].max_ingress_change, 
		  get_minutes_since_event(&neighbor_info[i].time_max_change));
      }
    }

    bufprintf(buf, "</table><br><br>");
  }

  if ((stat->addr != my_node_id) &&
      ((stat->metrics_valid) || route_valid(stat)) &&
      (stat->next_hop.sink > 0))
  {
    bufprintf(buf, "<table frame=void cellspacing=5 cellpadding=6>\n");
    bufprintf(buf, "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n",
	      "Sink", "Next-Hop", "Quality", "Age[min]", "Num-changes");

   
    bufprintf(buf, "<tr><td colspan=5>%s</td></tr>",
	      "-------------------------------------------------------------------");
    bufprintf(buf, "<tr><td>%d</td><td>%d</td><td>%d</td><td>%s</td><td>%d</td></tr>\n",
	      stat->next_hop.sink, stat->next_hop.next_hop,
	      stat->next_hop.quality,
	      print_minutes_since_event(stat->next_hop_info.num_changes,
					&stat->next_hop_info.time_changed),
	      stat->next_hop_info.num_changes);
    bufprintf(buf, "</table><br>\n");
  }

  bufprintf(buf, "<br><br>");
}

/* Prints the packet table for one node */
static void
print_node_packet_table(buf_t* buf, sympathy_node_info_t* stat, int html)
{
  int i;
  stats_ctr_t* tmp_ctr;
  char* suffix;
  sympathy_node_app_info_t* snode;

   /* Print packets received in error */
   if (stat->addr == my_node_id) {
     bufprintf(buf, "\n#Pkts rx in error from unidentifiable nodes");
   }
   else bufprintf(buf, "\n#Pkts rx in error");
   bufprintf(buf, "/mins since last: %d(%d)/%s\n", 
	     stat->errs_rx.ctr, stat->errs_rx.agg_prev_epoch,
       print_minutes_since_event(stat->errs_rx.ctr, 
         &stat->errs_rx.last_updated));

  /* Print the packet table */
  /* If this is the sink, then the packet table is packets that were
   * transmitted by the sink */
  if (stat->addr == my_node_id)
    bufprintf(buf, "\n%-17s %-5s %-18s\n",
	      "Tos-type", "#Tx", "Mins-since-last");
   else
     bufprintf(buf, "\n%-17s %-5s %-18s\n",
	       "Tos-type", "#Rx", "Mins-since-last");

  bufprintf(buf, "---------------------------------------\n");

  for (i = 0; i < SNON_ROUTING_PKT; i++)
  {
    if (stat->tos_packets[i].ctr > 0)
    {
      bufprintf(buf, "%d:%-15s %d(%d%-4s %s(%s%-2s\n", 
        i, tos_packet_to_string(i),
		    stat->tos_packets[i].ctr, stat->tos_packets[i].agg_prev_epoch, 
		    ")", 
        print_minutes_since_event(stat->tos_packets[i].ctr, 
				  &stat->tos_packets[i].last_updated),
        print_pd_of_event(stat->tos_packets[i].ctr, 
			    &stat->tos_packets[i].last_updated), ")");
     }
   }

  /* APP-Layer-Unicast */
  bufprintf(buf, "%d:%-14s  %d(%d%-5s %s(%s%-2s\n", 
	    SNON_ROUTING_PKT, "app",
	    stat->tos_packets[SNON_ROUTING_PKT].ctr +
	    stat->tos_packets[SYMPATHY_PKT].ctr, 
	    stat->tos_packets[SNON_ROUTING_PKT].agg_prev_epoch + 
	    stat->tos_packets[SYMPATHY_PKT].agg_prev_epoch, 
	    ")", 
      print_minutes_since_event(stat->tos_packets[SNON_ROUTING_PKT].ctr, 
			    &stat->tos_packets[SNON_ROUTING_PKT].last_updated),
      print_pd_of_event(stat->tos_packets[SNON_ROUTING_PKT].ctr, 
		    &stat->tos_packets[SNON_ROUTING_PKT].last_updated), ")");
 
 
  /* Non-sympathy app-layer */
  for (i = 0; i < sink.num_apps_registered; i++)
  {
    if (stat->node_app_info[i].sink_pkt_rx.ctr > 0)
    {
      bufprintf(buf, " =>%-9s %d(%d%-5s %s(%s)\n", 
		get_comp_string(stat->node_app_info[i].comp_name, sink.app_type[i]),
		stat->node_app_info[i].sink_pkt_rx.ctr, 
		stat->node_app_info[i].sink_pkt_rx.agg_prev_epoch,
		")", 
      print_minutes_since_event(stat->node_app_info[i].app_stats_rx_from_node.ctr,
				&stat->node_app_info[i].app_stats_rx_from_node.last_updated),
        print_pd_of_event(stat->node_app_info[i].app_stats_rx_from_node.ctr, 
			    &stat->node_app_info[i].app_stats_rx_from_node.last_updated));
    }
  }
 
  if (stat->addr == my_node_id) return;
 
  /* Sympathy Layer */
  for (i = 0; i < 2; i++)
  {
    if (i == 0) 
    {
      tmp_ctr = &stat->sympathy_stats_rx;
      suffix = "stats";
    }
    else if (i == 1) {
      tmp_ctr = &stat->metrics_rx;
      suffix = "metrics";
    }
    if (tmp_ctr->ctr > 0) {
      bufprintf(buf, " =>Symp-%-9s %d(%d%-5s %s(%s)\n",
		suffix, tmp_ctr->ctr, tmp_ctr->agg_prev_epoch,
		")", 
      print_minutes_since_event(tmp_ctr->ctr, &tmp_ctr->last_updated),
        print_pd_of_event(tmp_ctr->ctr, &tmp_ctr->last_updated));
    }
  }
 
  for (i = 0; i < sink.num_apps_registered; i++)
  {
    snode = &stat->node_app_info[i];
    bufprintf(buf, " =>%s-stats %d(%d%-5s %s(%s)\n", 
	      get_comp_string(snode->comp_name, sink.app_type[i]),
	      stat->node_app_info[i].app_stats_rx_from_node.ctr, 
	      stat->node_app_info[i].app_stats_rx_from_node.agg_prev_epoch,
	      ")", 
        print_minutes_since_event(snode->app_stats_rx_from_node.ctr,
			      &snode->app_stats_rx_from_node.last_updated),
        print_pd_of_event(snode->app_stats_rx_from_node.ctr, 
		      &snode->app_stats_rx_from_node.last_updated));
  }
}

static void
print_node_packet_table_html(buf_t* buf, sympathy_node_info_t* stat, int html)
{
  int i;
  stats_ctr_t* tmp_ctr;
  char* suffix;
  sympathy_node_app_info_t* snode;

   /* Print packets received in error */
   bufprintf(buf, "<table frame=void cellspacing=5 cellpadding=6>");
   if (stat->addr == my_node_id) {
     bufprintf(buf, "<tr><td>#Pkts rx in error from unidentifiable nodes");
   }
   else bufprintf(buf, "<tr><td>#Pkts rx in error");
   bufprintf(buf, "/mins since last: %d(%d)/%s</td></tr></table><br>\n", 
         stat->errs_rx.ctr, stat->errs_rx.agg_prev_epoch,
       print_minutes_since_event(stat->errs_rx.ctr, 
			     &stat->errs_rx.last_updated));


  /* Print the packet table */
  /* If this is the sink, then the packet table is packets that were
   * transmitted by the sink */
  bufprintf(buf, "<table frame=void cellspacing=5 cellpadding=6>");
  if (stat->addr == my_node_id)
    bufprintf(buf, "<tr><td>%s</td><td>%s</td><td>%s</td></tr>\n",
	      "Tos-type", "#Tx", "Mins-since-last");
  else
    bufprintf(buf, "<tr><td>%s</td><td>%s</td><td>%s</td></tr>\n",
	      "Tos-type", "#Rx", "Mins-since-last");

  bufprintf(buf, "<tr><td colspan=3>%s</td></tr>", "--------------------------------------------------------");

  for (i = 0; i < SNON_ROUTING_PKT; i++)
  {
    if (stat->tos_packets[i].ctr > 0)
    {
      bufprintf(buf, "<tr><td>%d:%s</td>\n", 
        i, tos_packet_to_string(i));
      bufprintf(buf, "<td>%d(%d)</td>", 
		stat->tos_packets[i].ctr, stat->tos_packets[i].agg_prev_epoch);
      bufprintf(buf,"<td>%s(%s)</td></tr>", 
        print_minutes_since_event(stat->tos_packets[i].ctr, 
				&stat->tos_packets[i].last_updated),
        print_pd_of_event(stat->tos_packets[i].ctr, 
			    &stat->tos_packets[i].last_updated));
     }
   }

  /* APP-Layer-Unicast */

  bufprintf(buf, "<tr><td>%d:app</td>\n", SNON_ROUTING_PKT);
  bufprintf(buf, "<td>%d(%d)</td>\n",
	    stat->tos_packets[SNON_ROUTING_PKT].ctr +
	    stat->tos_packets[SYMPATHY_PKT].ctr, 
	    stat->tos_packets[SNON_ROUTING_PKT].agg_prev_epoch + 
	    stat->tos_packets[SYMPATHY_PKT].agg_prev_epoch);

  bufprintf(buf, "<td>%s(%s)</td></tr>\n", 
    print_minutes_since_event(stat->tos_packets[SNON_ROUTING_PKT].ctr, 
			    &stat->tos_packets[SNON_ROUTING_PKT].last_updated), 
    print_pd_of_event(stat->tos_packets[SNON_ROUTING_PKT].ctr, 
		    &stat->tos_packets[SNON_ROUTING_PKT].last_updated));

  /* Non-sympathy app-layer */
  for (i = 0; i < sink.num_apps_registered; i++) {
    if (stat->node_app_info[i].sink_pkt_rx.ctr > 0)
    {

      bufprintf(buf, "<tr><td> =>%s</td><td> %d(%d)</td>\n",
		get_comp_string(stat->node_app_info[i].comp_name,
				sink.app_type[i]),
		stat->node_app_info[i].sink_pkt_rx.ctr, 
		stat->node_app_info[i].sink_pkt_rx.agg_prev_epoch);

      bufprintf(buf, "<td>%s(%s)</td></tr>\n", 
        print_minutes_since_event(stat->node_app_info[i].app_stats_rx_from_node.ctr,
				&stat->node_app_info[i].app_stats_rx_from_node.last_updated),
        print_pd_of_event(stat->node_app_info[i].app_stats_rx_from_node.ctr, 
			    &stat->node_app_info[i].app_stats_rx_from_node.last_updated));
    }
  }

  /* Sympathy Layer */
  for (i = 0; i < 2; i++)
  {
    if (i == 0) 
    {
      tmp_ctr = &stat->sympathy_stats_rx;
      suffix = "stats";
    }
    else if (i == 1) {
      tmp_ctr = &stat->metrics_rx;
      suffix = "metrics";
    }

    if (tmp_ctr->ctr > 0) {

      bufprintf(buf, "<tr><td> =>Symp-%s</td>\n", suffix);
      bufprintf(buf, "<td>%d(%d)</td>\n",
		tmp_ctr->ctr, tmp_ctr->agg_prev_epoch);
      bufprintf(buf, "<td>%s(%s)</td></tr>\n", 
        print_minutes_since_event(tmp_ctr->ctr, &tmp_ctr->last_updated),
        print_pd_of_event(tmp_ctr->ctr, &tmp_ctr->last_updated));
    }
  }

  for (i = 0; i < sink.num_apps_registered; i++)
  {
    snode = &stat->node_app_info[i];

    bufprintf(buf, "<tr><td> =>Symp-%s</td>\n",
	      get_comp_string(snode->comp_name, sink.app_type[i]));
    bufprintf(buf, "<td>%d(%d)</td>\n",
	      stat->node_app_info[i].app_stats_rx_from_node.ctr, 
	      stat->node_app_info[i].app_stats_rx_from_node.agg_prev_epoch);
    bufprintf(buf, "<td>%s(%s)</td></tr>\n", 
      print_minutes_since_event(snode->app_stats_rx_from_node.ctr,
			       &snode->app_stats_rx_from_node.last_updated),
      print_pd_of_event(snode->app_stats_rx_from_node.ctr, 
		       &snode->app_stats_rx_from_node.last_updated));
  }

  bufprintf(buf, "</table><br><br>\n");
}

/* Prints the route info for one node */
static void
print_node_route_info(buf_t* buf, sympathy_node_info_t* stat, int html)
{
  sympathy_node_info_t* stat2 = stat;
  int sctr, i = 0;
  int iter = 0;

  if (stat->next_hop.next_hop == 0) return;

  /* Check if this node IS the sink */
  if (stat->addr == stat->next_hop.sink) return;

  /* First print out route to sink */
  if (html) bufprintf(buf, "<table frame=void cellspacing=5 cellpadding=6><tr><td>");
  bufprintf(buf, "Route");
  if (!route_valid(stat)) bufprintf(buf, "(INVALID)");
  bufprintf(buf, ":%d -> %d", stat->addr, stat->next_hop.next_hop);

  while ((stat2 = iter_next_hop(stat2, &iter, stat->next_hop.sink))) {
    bufprintf(buf, " -> %d ", stat2->next_hop.next_hop);
  }
  if (iter < 0) bufprintf(buf, "ERROR: VERY BAD Suspecting a routing loop!!\n");

  if (html) {
    bufprintf(buf, "</td></tr></table><table frame=void cellspacing=5 cellpadding=6><tr><td>");
  }
  else bufprintf(buf, ";\t  ");

  /* Now print children */
  sctr = 0;
  for (i = 0; i < SMAX_SRCS; i++)
  {
    if ((sink.status_srcs[i].next_hop.next_hop == stat->addr)
        && (sink.status_srcs[i].metrics_valid))
    {
      bufprintf(buf, "node %d, ", sink.status_srcs[i].addr);
      sctr++;
    }
  }
  if (sctr > 1) bufprintf(buf, "are children\n");
  else if (sctr == 1) {
    bufprintf(buf, "is a child\n");
  }
  if (html) bufprintf(buf, "</td></tr></table><br>\n");
}

/* Prints the components stats for one node */
static void
print_node_components_stats(buf_t* buf, sympathy_node_info_t* stat, int html)
{
  int i;
  sympathy_node_app_info_t* snode;
  
  /* Print no data if this is the sink */
  if (stat->addr == my_node_id) return;

  /* Print information received from pinging of nodes */
  if (stat->neighbor_buf->len > 0) {
    bufprintf(buf, "\n*** Data Returned From Pings:\n%s", stat->neighbor_buf->buf);
    clear_buf(&stat->neighbor_buf);
  }

  if (stat->sympathy_stats_rx.ctr > 0) 
  {
    bufprintf(buf, "\nReported Stats from Components\n");
    bufprintf(buf, "-------------------------------\n");
    bufprintf(buf, "#metrics tx/expected/#stats tx: %d(%d)/%d(%d)/%d(%d)\n",     
	      stat->num_metrics_tx.ctr, stat->num_metrics_tx.agg_prev_epoch, 
	      sink.expected_num_sympathy_metrics.ctr,
	      sink.expected_num_sympathy_metrics.agg_prev_epoch,
	      stat->num_stats_tx.ctr, stat->num_stats_tx.agg_prev_epoch);
    bufprintf(buf, "#pkts rx CRC error: %d(%d)\n",
	      stat->num_pkts_crc_error.ctr,
	      stat->num_pkts_crc_error.agg_prev_epoch);
    bufprintf(buf, "#pkts rx/routed-succ/failed/dropped: %d(%d)/%d(%d)/%d(%d)/%d(%d)\n",
	      stat->num_pkts_rx.ctr,
	      stat->num_pkts_rx.agg_prev_epoch,
	      stat->num_pkts_tx_succeeded.ctr,
	      stat->num_pkts_tx_succeeded.agg_prev_epoch,
	      stat->num_pkts_tx_failed.ctr,
	      stat->num_pkts_tx_failed.agg_prev_epoch,
	      stat->num_pkts_dropped.ctr,
	      stat->num_pkts_dropped.agg_prev_epoch);
  }

  for (i = 0; i < sink.num_apps_registered; i++)
  {
    snode = &stat->node_app_info[i];
    if ((snode->app_stats_rx_from_node.ctr > 0) ||
	event_valid(&snode->sink_pkt_tx.last_updated)) {

      /* Check if we have printed out the title yet */
      if (stat->sympathy_stats_rx.ctr == 0)
      {
        bufprintf(buf, "\nReported Stats from Components\n");
	bufprintf(buf, "------------------------------------\n");
      }
      bufprintf(buf, "\n%s: \n", 
		get_comp_string(snode->comp_name, sink.app_type[i]));
      bufprintf(buf, "#reqs node rx/#reqs sink tx: %d(%d)/%d(%d)\n", 
		snode->node_num_pkts_rx.ctr,
		snode->node_num_pkts_rx.agg_prev_epoch, 
		snode->sink_pkt_tx.ctr, snode->sink_pkt_tx.agg_prev_epoch);
      bufprintf(buf, "#pkts node tx/sink rx/sink expected rx: %d(%d)/%d(%d)/%d(%d)\n",
		snode->node_num_pkts_tx.ctr,
		snode->node_num_pkts_tx.agg_prev_epoch, 
		snode->sink_pkt_rx.ctr,
		snode->sink_pkt_rx.agg_prev_epoch, 
		snode->sink_pkt_expected_rx.ctr, 
		snode->sink_pkt_expected_rx.agg_prev_epoch);
    bufprintf(buf, "#send failures/max Q occupancy/#pkts dropped: %d(%d)/%d(%d)/%d(%d)\n",
      snode->node_send_failures.ctr,
      snode->node_send_failures.agg_prev_epoch,
      snode->node_max_queue_occupancy.ctr,
      snode->node_max_queue_occupancy.agg_prev_epoch,
      snode->node_num_pkts_dropped.ctr,
      snode->node_num_pkts_dropped.agg_prev_epoch);
    }

    if (snode->generic_stats_buf->len > 0)
    {
      bufprintf(buf, "\n%s Generic:  %s\n", 
		get_comp_string(snode->comp_name, sink.app_type[i]),
		snode->generic_stats_buf->buf);
      clear_buf(&snode->generic_stats_buf);
    }
  }
}

static void
print_node_components_stats_html(buf_t* buf, sympathy_node_info_t* stat, int html)
{
  int i;
  sympathy_node_app_info_t* snode;

  /* Print no data if this is the sink */
  if (stat->addr == my_node_id) return;

  /* Print information received from pinging of nodes */
  if (stat->neighbor_buf->len > 0)
  {
    bufprintf(buf, "<table frame=void cellspacing=5 cellpadding=6>\n");
    bufprintf(buf, "<tr><td>Data Returned From Pings:</td></tr><tr><td>%s</td></tr></table><br><br>\n", stat->neighbor_buf->buf);
    clear_buf(&stat->neighbor_buf);
  }

  if (stat->sympathy_stats_rx.ctr > 0) 
  {
    bufprintf(buf, "<table frame=void cellspacing=5 cellpadding=6>");
    bufprintf(buf, "<tr><td>Reported Stats from Components</td></tr>\n");
    bufprintf(buf, "<tr><td>%s</td></tr></table>", "**********************************");
    bufprintf(buf, "<table frame=void cellspacing=5 cellpadding=6>");
    bufprintf(buf, "<tr><td>**Sympathy:</td></tr>\n");
    bufprintf(buf, "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n", "#metrics tx", "#stats tx", "#metrics expected", "#pkts rx CRC error","#pkts routed succ", "failed", "#pkts dropped");
    bufprintf(buf, "<tr><td colspan=7>%s</td></tr>", "-----------------------------------------------------------------------------------------------------------------------------------------------------");
    bufprintf(buf, "<tr><td>%d(%d)</td><td>%d(%d)</td><td>%d(%d)</td><td>%d(%d)</td><td>%d(%d)</td><td>%d(%d)</td><td>%d(%d)</td></tr>\n",
	      stat->num_metrics_tx.ctr, stat->num_metrics_tx.agg_prev_epoch, 
	      stat->num_stats_tx.ctr, stat->num_stats_tx.agg_prev_epoch, 
	      sink.expected_num_sympathy_metrics.ctr,
	      sink.expected_num_sympathy_metrics.agg_prev_epoch,
	      stat->num_pkts_crc_error.ctr,
	      stat->num_pkts_crc_error.agg_prev_epoch,
	      stat->num_pkts_tx_succeeded.ctr,
	      stat->num_pkts_tx_succeeded.agg_prev_epoch,
	      stat->num_pkts_tx_failed.ctr,
	      stat->num_pkts_tx_failed.agg_prev_epoch,
	      stat->num_pkts_dropped.ctr,
	      stat->num_pkts_dropped.agg_prev_epoch);
    bufprintf(buf, "</table><br><br>");
  }

  for (i = 0; i < sink.num_apps_registered; i++)
  {
    snode = &stat->node_app_info[i];
    if ((snode->app_stats_rx_from_node.ctr > 0) ||
      event_valid(&snode->sink_pkt_tx.last_updated)) {

      /* Check if we have printed out the title yet */
      if (stat->sympathy_stats_rx.ctr == 0)
      {
        bufprintf(buf, "<table frame=void cellspacing=5 cellpadding=6>");
        bufprintf(buf, "<tr><td colspan=5>Reported Stats from Components</td></tr>\n");
        bufprintf(buf, "<tr><td>%s</td></tr></table>", "**********************************");
      }

      bufprintf(buf, " <table frame=void cellspacing=5 cellpadding=6>");
      bufprintf(buf, "<tr><td>%s:</td></tr>\n", 
		get_comp_string(snode->comp_name, sink.app_type[i]));
      bufprintf(buf, "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n",
		"#reqs node rx", "#reqs sink tx", "#pkts node tx",
		"sink rx", "sink expected rx");
      bufprintf(buf, "<tr><td colspan=5>%s</td></tr>", "----------------------------------------------------------------------------------------------------");
      bufprintf(buf, "<tr><td>%d(%d)</td><td>%d(%d)</td><td>%d(%d)</td><td>%d(%d)</td><td>%d(%d)</td></tr>\n",
		snode->node_num_pkts_rx.ctr,
		snode->node_num_pkts_rx.agg_prev_epoch, 
		snode->sink_pkt_tx.ctr,
		snode->sink_pkt_tx.agg_prev_epoch,
		snode->node_num_pkts_tx.ctr,
		snode->node_num_pkts_tx.agg_prev_epoch, 
		snode->sink_pkt_rx.ctr,
		snode->sink_pkt_rx.agg_prev_epoch, 
		snode->sink_pkt_expected_rx.ctr, 
		snode->sink_pkt_expected_rx.agg_prev_epoch);
      bufprintf(buf, "<tr><td>%s</td><td>%s</td><td>%s</td></tr>\n",
          "#send failures","max Q occupancy","#pkts dropped");
      bufprintf(buf, "<tr><td colspan=5>%s</td></tr>", "----------------------------------------------------------------------------------------------------");
      bufprintf(buf, "<tr><td>%d(%d)</td><td>%d(%d)</td><td>%d(%d)</td></tr>\n",
        snode->node_send_failures.ctr,
        snode->node_send_failures.agg_prev_epoch,
        snode->node_max_queue_occupancy.ctr,
        snode->node_max_queue_occupancy.agg_prev_epoch,
        snode->node_num_pkts_dropped.ctr,
        snode->node_num_pkts_dropped.agg_prev_epoch);
    }

    if (snode->generic_stats_buf->len > 0)
    {
      bufprintf(buf, "<table frame=void cellspacing=5 cellpadding=6>");
      bufprintf(buf, "<tr><td>%s Generic: %s</td></tr></table>\n", 
		get_comp_string(snode->comp_name, sink.app_type[i]),
		snode->generic_stats_buf->buf);
      clear_buf(&snode->generic_stats_buf);
    }

    bufprintf(buf, "<br><br>\n");
  }
}

static void print_failed_info(buf_t* buf, 
    int root_cause, buf_t* fault_buf, char* comp_name, int addr)
{
  if (root_cause == SFL_OK) return;

  bufprintf(buf, " * %s Failure; Root-Cause %s \n", comp_name,
    decode_root_cause(root_cause, addr));
  if (fault_buf) bufprintf(buf, "  %s", fault_buf->buf);
}

static void
print_header(buf_t* buf, sympathy_node_info_t* stat, int html)
{
  time_t timep;
  char* atime;

  if (html) bufprintf(buf, "<table cellspacing=5 cellpadding=6><tr>\n");
  else bufprintf(buf, "\n************* ");

  if (stat->addr == my_node_id)
  {
    time(&timep);
    atime = asctime(localtime(&timep));
    if (html) bufprintf(buf, "<td>%s</td></tr>\n", atime);
    else bufprintf(buf, "%s", atime);
  }
  else {
    if (html) bufprintf(buf, "</tr>\n");
    else bufprintf(buf, "\n");
  }

  if (html) bufprintf(buf, "<tr><td>");
  bufprintf(buf, "Node %d", stat->addr); 

  /* If this node is the sink, specify that! */
  if (stat->addr == my_node_id)
  {
    int min = get_minutes_since_event(&start_time);
    if (html) {
      bufprintf(buf, " (Sink)</td></tr><tr><td>Time awake: %d(mins)</td></tr>\n", min);
    }
    else bufprintf(buf, " (Sink), Time awake: %d(mins),", min);
  }
  else {
    if (html) {
      bufprintf(buf, "</td></tr><tr><td>Time awake: %d(mins)</td></tr>\n", stat->time_awake_mins.ctr);
    }
    else bufprintf(buf, ", Time awake: %d(mins),", stat->time_awake_mins.ctr);
  }

  if (html) {
    bufprintf(buf, "<tr><td>Metric Pd: %d</td></tr></table><br>\n", sink.metric_pd);
  }
  else bufprintf(buf, " Metric Pd: %d\n",sink.metric_pd);

  print_failure_info(buf, stat, html);
  if ((stat->topology_info) && (stat->topology_info->len > 0)) {
    if (html) bufprintf(buf, "<table cellspacing=5 cellpadding=6>\n<tr><td>");
    bufprintf(buf, "%s\n", stat->topology_info->buf);
    if (html) bufprintf(buf, "</td></tr>\n</table><br><br>\n");
  }
  if (stat->congestion_detected) bufprintf(buf, "Congestion Detected!\n");
}



static void
print_node_metrics(buf_t* buf, sympathy_node_info_t* stat, int html)
{
  print_header(buf, stat, html);
  print_node_route_info(buf, stat, html);
  if (html) print_node_packet_table_html(buf, stat, html);
  else print_node_packet_table(buf, stat, html);
  if (html) print_node_components_stats_html(buf, stat, 1);
  else print_node_components_stats(buf, stat, html);
  if (html) {
    print_node_neighbors_html(buf, stat, 1);
    bufprintf(buf, "<br>\n");
  }
  else print_node_neighbors(buf, stat, html);
}

static node_metrics_print_t get_node_metrics_funct(char type)
{ 
  node_metrics_print_t print = NULL;

  switch(type)  // get function to call for each node
  {
    case 'n': print = print_node_neighbors;
              break;;
    case 'p': print = print_node_packet_table;
              break;
    case 'r': print = print_node_route_info;
              break;
    case 'c': print = print_node_components_stats;
              break;
    default:  elog(LOG_ERR, "Invalid metrics type %c!\n", type);
              break;
  }
  
  return print;
}

static node_metrics_print_t get_node_metrics_funct_html(char type)
{ 
  node_metrics_print_t print = NULL;

  switch(type)  // get function to call for each node
  {
    case 'n': print = print_node_neighbors_html;
              break;;
    case 'p': print = print_node_packet_table_html;
              break;
    case 'r': print = print_node_route_info;
              break;
    case 'c': print = print_node_components_stats_html;
              break;
    default:  elog(LOG_ERR, "Invalid metrics type %c!\n", type);
              break;
  }
  
  return print;
}

static
void metrics_cmd_summary(buf_t* buf)
{
  bufprintf(buf, "\nCommand Summary\n\n");

  bufprintf(buf, "\tKey letters:\n");
  bufprintf(buf, "\t\tn - neighbor list\n");
  bufprintf(buf, "\t\tp - packet table\n");
  bufprintf(buf, "\t\tr - route info\n");
  bufprintf(buf, "\t\tc - components' stats\n\n");

  bufprintf(buf, "\tAll metrics:\n");
  bufprintf(buf, "\t\t1) For all nodes- no command needed\n");
  bufprintf(buf, "\t\t2) For one node- nodeID#\n");
  bufprintf(buf, "\t\t\texample: 5 (retrieves all metrics for node 5)\n");

  bufprintf(buf, "\tOne type of metrics:\n");
  bufprintf(buf, "\t\t1) For all nodes- a + key letter\n");
  bufprintf(buf, "\t\t\texample: an (retrieves all neighbor lists)\n");
  bufprintf(buf, "\t\t2) For one node- key letter + nodeID#\n");
  bufprintf(buf, "\t\t\texample: r17 (retrieves route info for node 17)\n\n");
}

static
void metrics_cmd_summary_html(buf_t* buf)
{
  bufprintf(buf, "<br><a name=\"Command Summary\"><h3>Command Summary</h3></a>\n");

  bufprintf(buf, "<ul><li><h4>Key letters:</h4><ul>\n");
  bufprintf(buf, "<li>n - neighbor list\n");
  bufprintf(buf, "<li>p - packet table\n");
  bufprintf(buf, "<li>r - route info\n");
  bufprintf(buf, "<li>c - components' stats</ul>\n");

  bufprintf(buf, "<li><h4>All metrics:</h4><ol>\n");
  bufprintf(buf, "<li>For all nodes- no command needed\n");
  bufprintf(buf, "<li>For one node- nodeID#<br>\n");
  bufprintf(buf, "<pre>     example: 5 (retrieves all metrics for node 5)</pre></ol>\n");

  bufprintf(buf, "<li><h4>One type of metrics:</h4><ol>\n");
  bufprintf(buf, "<li> For all nodes- a + key letter<br>\n");
  bufprintf(buf, "<pre>     example: an (retrieves all neighbor lists)</pre>\n");
  bufprintf(buf, "<li>For one node- key letter + nodeID#<br>\n");
  bufprintf(buf, "<pre>     example: r17 (retrieves route info for node 17)</pre>");
  bufprintf(buf, "</ol></ul><br><br>\n");
}

void order_by_id(sympathy_node_info_t* ordered[SMAX_SRCS])
{
  int i, j, k;
  sympathy_node_info_t* temp;

  for(i = 0; i < sink.num_srcs; i++)
  {
    ordered[i] = &sink.status_srcs[i];
    for (j = i - 1, k = i;
	 (j >= 0)  && (ordered[k]->addr < ordered[j]->addr); j--, k--)
    {
       //swap
       temp = ordered[k];
       ordered[k] = ordered[j];
       ordered[j] = temp;
    }
  }
}

static int
sympathy_print_metrics_template(int html,
				status_context_t *info, buf_t *buf)
{
  int i, j, sctr;
  char* request = NULL;
  buf_t *temp = buf_new();
  request = (char*)sd_client_data(sd_curr_client(info));
  sympathy_node_info_t* status_srcs_cpy[SMAX_SRCS];
  sympathy_node_info_t* stat;
  node_metrics_print_t mprint;
  get_print_funct_t gnmf;

  if (html) {
    gnmf = get_node_metrics_funct_html;
  }
  else {
    gnmf = get_node_metrics_funct;
  }

  if (request && ((*request) > 0))
  {
    char first = request[0];

    if (first != 'a')
    {
      if (isdigit(first))  // print all metrics for one node
      {
        int nodeid = atoi(request);
        if ((nodeid < 0) || ((sctr = find_status(nodeid)) < 0))
        {
          elog(LOG_ERR, "Can't find node %d!\n", nodeid);
          goto done;
        }
        stat = &sink.status_srcs[sctr];
        print_node_metrics(buf, stat, html);
        goto done;
      }
      else  // print one type of metrics for one node
      {
        mprint = gnmf(first);
        if(mprint) {
          char id[200] = "";
          j = 1;
          if(j < strlen(request))  strcat(id, &request[j]);
          else  elog(LOG_ERR, "Must supply node id %s!\n", id);

          int idnum = atoi(id);

          if ((idnum < 0) || ((sctr = find_status(idnum)) < 0))
          {
            elog(LOG_ERR, "Can't find node %d!\n", idnum);
            goto done;
          }

          stat = &sink.status_srcs[sctr];
          mprint(buf, stat, html);
        }
        else {
	        elog(LOG_ERR, "Invalid metrics request: %s!\n", request);
          goto done;
        }
      }
    }
 
    // (first == 'a'), print one type of metrics for all nodes
    if (strlen(request) < 2)
    {
      elog(LOG_ERR, "Invalid metrics request: %s\n", request);
      goto done;
    }
    mprint = gnmf(request[1]);

    if(mprint)
    {
      order_by_id(status_srcs_cpy);
      for (i = 0; i < sink.num_srcs; i++)
      {
        mprint(temp, status_srcs_cpy[i], html);
        if(buf_len(temp) > 0) { // print "Node x:" only if it has metrics 
          if(html) {
            bufprintf(buf, "<h3>Node %d:</h3><br>", status_srcs_cpy[i]->addr);
          }
          else bufprintf(buf, "Node %d:\n", status_srcs_cpy[i]->addr);
          mprint(buf, status_srcs_cpy[i], html);
        }
      }

      buf_free(temp);
      temp = buf_new();

      bufprintf(buf, "\n\n");
    }
    else elog(LOG_ERR, "Invalid metrics request: %s!\n", request);
    goto done;
  }

  order_by_id(status_srcs_cpy);
  for (i = 0; i < sink.num_srcs; i++)  // print all metrics for all nodes
  {
    print_node_metrics(buf, status_srcs_cpy[i], html);
  }

  /* Command summary */
  {
    status_client_t* curr = sd_curr_client(info);
    sympathy_client_data_t* m = (sympathy_client_data_t *)sd_client_data(curr);
    if (m) {
      if (!m->printed_usage) {
        if (html) metrics_cmd_summary_html(buf);
        else metrics_cmd_summary(buf);
        m->printed_usage = 1;
      }
    }
  }

  done:
  buf_free(temp);
  return STATUS_MSG_COMPLETE;
}

static
int sympathy_print_metrics(status_context_t *info, buf_t *buf)
{
  return sympathy_print_metrics_template(0, info, buf);
}

static
int sympathy_print_metrics_binary(status_context_t *info, buf_t *buf)
{
  int i, j, ctr;
  sympathy_node_info_t* stat;

  for (i = 0; i < sink.num_srcs; i++) {
    ctr = 0;
    stat = &sink.status_srcs[i];
    {
      sympathy_metrics_t m = {
        address: stat->addr,
        congestion_detected: stat->congestion_detected, 
        num_neighbors: stat->num_neighbors, 
        num_heard_this_node: stat->num_heard_this_node, 
        time_awake_minutes: stat->time_awake_mins.ctr,
      };

      memcpy(&m.route, &stat->next_hop, sizeof(stat->next_hop));
      for (j = 0; j < NUM_TOS_PKT_TYPES; j++) {
        m.tos_packets[j] = stat->tos_packets[j].ctr;
      }

      for (j = 0; j < stat->num_neighbors; j++) {
        if ((stat->neighbors[j].node_id> 0) &&
          (stat->neighbors[j].node_id!= TOS_BCAST_ADDR)) {
          m.neighbors[ctr].addr = stat->neighbors[j].node_id;
          ctr++;
        }
      }
      print_summary(stat, &m.failure);
      bufcpy(buf, &m, sizeof(sympathy_metrics_t));
    }
  }
  return STATUS_MSG_COMPLETE;
}

static
int sympathy_print_metrics_xml(status_context_t *info, buf_t *buf)
{
  buf_t* binary_buf = buf_new();
  sympathy_print_metrics_binary(info, binary_buf);
  sympathy_metrics_t* m = (sympathy_metrics_t *)binary_buf->buf;
  int i = 0;
  int j = 0;
  int num_nodes = binary_buf->len / (sizeof(sympathy_metrics_t));

  while (i < num_nodes) {
    bufprintf(buf, "\n\n<sympathy_data mote_id=\"%d\" time_awake_mins=\"%d\"\n",
        m[i].address, m[i].time_awake_minutes);
    bufprintf(buf, "<sink>%d</sink>\n", m[i].is_sink ? 1 : 0);

    if (m[i].failure.node_failure_category > SFL_OK) {
      bufprintf(buf, "<failure_type>%d</failure_type>\n",
        m[i].failure.node_failure_category );
      bufprintf(buf, "<root_cause>\"%s\"</root_cause>\n",
        decode_root_cause(m[i].failure.failure_root_cause,m[i].address));
      bufprintf(buf, "<failure_localization>\"%s\"</failure_localization>\n",decode_localization(m[i].failure.failure_localization));
    }

    bufprintf(buf, "<congestion_detected>%d</congestion_detected>\n", 
        m[i].congestion_detected ? 1: 0);

    bufprintf(buf, "<packet_table>\n");
    for (j = 0; j < NUM_TOS_PKT_TYPES; j++) {
      if (m[i].tos_packets[j] > 0) {
	      bufprintf(buf, "  <packet type=\"%s\" number_rx=\"%d\" />\n",
          tos_packet_to_string(j), m[i].tos_packets[j]);
      }
    }
    bufprintf(buf, "</packet_table>\n");

    //<!-- print the following ONLY when they change -->
    bufprintf(buf, "<neighbor_list>\n");
    {
      for (j = 0; j < m[i].num_neighbors; j++) {
        bufprintf(buf, "  <node mote_id=\"%d\"/>\n",
          m[i].neighbors[j].addr);
      }
    }
    bufprintf(buf, "</neighbor_list>\n");

    //<!-- print the following ONLY when we received an update -->
    if (!m[i].is_sink) {
      bufprintf(buf, "<routing_table>\n");
      bufprintf(buf, "<sink mote_id=\"%d\" next_hop_address=\"%d\" path_quality=\"%d\"/>\n",
          m[i].route.sink, m[i].route.next_hop, m[i].route.quality);
      bufprintf(buf, "</routing_table>\n");
    }

    //<!-- print the following ONLY when it changed.  -->
    bufprintf(buf, "<num_neighbors_heard_this_node>%d</num_neighbors_heard_this_node>\n", 
        m[i].num_heard_this_node);
    i++;
  }

  buf_free(binary_buf);
  return STATUS_MSG_COMPLETE;
}

static
int sympathy_print_metrics_html(status_context_t *info, buf_t *buf)
{
  return sympathy_print_metrics_template(1, info, buf);
}

static
int sympathy_metrics_write(status_context_t *ctx, char cmd[], size_t size)
{
  status_client_t* curr = sd_curr_client(ctx);
  sympathy_client_data_t* m = (sympathy_client_data_t *)sd_client_data(curr);
  if (size < 10) sprintf(m->request, "%s", cmd);
  else elog(LOG_ERR, "Size of command: %d is > 10!\n", size);
  return STATUS_WRITE_NOTIFY_CLIENT;
}

static
int sympathy_device_close(status_context_t *ctx)
{
  status_client_t* curr = sd_curr_client(ctx);
  if (curr) g_free(sd_client_data(curr));
  return 0;
}

static
int sympathy_device_open(status_context_t *ctx)
{
  status_client_t* curr = sd_curr_client(ctx);
  sympathy_client_data_t* m = g_new0(sympathy_client_data_t, 1);
  if (curr) sd_set_client_data(curr, m);
  return 0;
}


static 
void print_failure_info(buf_t* buf, sympathy_node_info_t* stat, int html)
{
  int i;

  if (stat->failure_type == SFL_OK) return;

  if (html) {
    bufprintf(buf, "<br><table frame=void cellspacing=5 cellpadding=6><tr><td>");
  }

  bufprintf(buf, "  ** ");
  if (stat->failure_localization == S_SELF) bufprintf(buf, "Root ");

  bufprintf(buf, "Failure (%d); Root-Cause: %s (%d periods)\n",
      stat->failure_type,
      decode_root_cause(stat->failure_root_cause, stat->addr),
      sink.metric_pd - stat->period_root_caused + 1);
  if (stat->failure_localization != S_SELF) {
    bufprintf (buf, "; Localized to ");

    /* See if root cause if congestion at the node or just
     * another failure */
    {
      sympathy_node_info_t* tmp_stat = find_status_ptr(stat->source_node_failure);
      if (tmp_stat) {
        if (tmp_stat->congestion_detected) {
          bufprintf (buf, "Congestion  at");
        }
        else {
          bufprintf(buf, "%s at", decode_root_cause(tmp_stat->failure_root_cause, tmp_stat->addr));
        }
      }
      bufprintf(buf, " node %d\n", stat->source_node_failure);
    }
  }
  bufprintf(buf, "%s \n", stat->fault_buf->buf);
  if (html) bufprintf(buf, "</td></tr><tr><td>");

  if (html) bufprintf(buf, "</td></tr><tr><td></table>\n<br>");

  /* If the root-cause is less severe than no-neighbors, then print
   * component failures */
  if (stat->failure_root_cause < SRC_NO_NEIGHBORS) {
    for (i = 0; i < sink.num_apps_registered; i++)
    {
      if (html) {
        bufprintf(buf, "<table frame=void cellspacing=5 cellpadding=6>");
      }
      if (sink.app_type[i] < SCOMP_LAST)
      {
        if (html) bufprintf(buf, "<tr><td>");
        print_failed_info(buf, stat->node_app_info[i].failure_root_cause, 
         stat->node_app_info[i].fault_buf, 
         stat->node_app_info[i].comp_name, stat->addr);
        if (html) bufprintf(buf, "</tr></td>");
      }
      if (html) bufprintf(buf, "</table>\n");
    }
    if (html) bufprintf(buf, "</table>\n<br>");
  }
}

/*** External functions ***/

int event_valid(struct timeval* t)
{
  int min_data = get_minutes_since_event(t);
  return (min_data <= EPOCH_MSEC/60000);
}

int neighbors_valid(sympathy_node_info_t* stat)
{
  if (stat->addr == my_node_id) return 1;
  return(stat->metrics_valid || 
      event_valid(&stat->tos_packets[SNEIGHBOR_ADVERT].last_updated));
}

int route_valid(sympathy_node_info_t* stat)
{
  if (stat->addr == my_node_id) return 1;
  return(stat->metrics_valid || 
      event_valid(&stat->tos_packets[SPATH_ADVERT].last_updated));
}

static
int check_set_client_data(status_context_t *info, sympathy_node_info_t* stat)
{
  status_client_t* curr = sd_curr_client(info);
  sympathy_client_data_t* m = sd_client_data(curr);

  /* First find the index for this node */
  int i = find_status(stat->addr);

  if (!m) {
    elog(LOG_ERR, "No client data for node: %d\n", stat->addr);
    return 1;
  }

  if (i < 0) {
    elog(LOG_ERR, "Can't find index for node %d\n", stat->addr);
    return 1;
  }

  /* We print the data if it hasnt been printed yet this period, or 
   * if the failure is a node-crash or node-reboot */
  if ((m->printed_rc_period[i] != sink.metric_pd) 
      || (((stat->failure_root_cause == SRC_NODE_REBOOTED)
          || (stat->failure_root_cause == SRC_NODE_FAILED))
         && (m->printed_root_cause[i] != stat->failure_root_cause))) {
    m->printed_rc_period[i] = sink.metric_pd;
    m->printed_root_cause[i] = stat->failure_root_cause;
    return 1;
  }
  return 0;
}

static
void print_summary_info(status_context_t* ctx, buf_t* buf, int print_all, 
    int html)
{
  int i;
  sympathy_node_info_t* stat;

  if (sink.metric_pd < TRACK_FAILURE_WINDOW_SIZE - 1) goto done;

  /* Treat the sink separately because if the sink has a failure
   * then there is no need to print the failures of other nodes */
  if ((stat = find_status_ptr(my_node_id))) {
    if (check_set_client_data(ctx, stat)) {
      if ((print_all) || (stat->failure_type > SFL_OK)) {
        print_header(buf, stat, html);
      }
    }
  }

  for (i = 0; i < sink.num_srcs; i++)
  {
    stat = &sink.status_srcs[i];

    /* This check will also check if stat->addr != to the sink, so we don't
     * have to do that check again */
    if (check_set_client_data(ctx, stat)) {
      if ((print_all) || (stat->failure_type > SFL_OK)) {
        print_header(buf, stat, html);
        print_node_route_info(buf, stat, html);
        if (html) {
          bufprintf(buf, "<br><table frame=void cellspacing=5 cellpadding=6>\n<tr><td>");
        }
        if (stat->packet.ctr > 0) {
          bufprintf(buf, "Heard from node %s (%s) ago\n",
            print_minutes_since_event(stat->packet.ctr, 
            &stat->packet.last_updated),
            print_pd_of_event(stat->packet.ctr, 
              &stat->packet.last_updated));
        }
        else bufprintf(buf, "\nNever heard from this node!!\n");
        if (html) bufprintf(buf, "</tr></td>\n</table>\n<br>");
      }
    }
  }
done: return;
}

/* Summary file will print info for all nodes:
 *  - header info, any failures, route, time since heard from node */
static
int sympathy_print_summary(status_context_t *info, buf_t *buf)
{
  print_summary_info(info, buf, 1, 0);

#ifdef USE_BAYES
  bufprintf(buf,getClassificationsFromBayes());
#endif
  return STATUS_MSG_COMPLETE;
}

static
void print_summary(sympathy_node_info_t* stat, Sfail_summary_t* fail)
{
  int j;
  fail->node = stat->addr;
  fail->node_failure_category = stat->failure_type;
  fail->failure_root_cause = stat->failure_root_cause;
  fail->failure_localization = stat->failure_localization;
  for (j = 0; j < SCOMP_LAST; j++) {
    fail->comp_failure[j] = stat->node_app_info[j].failure_type; 
  }
}

static
int sympathy_print_summary_bin(status_context_t *info, buf_t *buf)
{
  Sfail_summary_t fail = {
    metric_pd: sink.metric_pd,
  };
  int i;
  sympathy_node_info_t* stat;

  for (i = 0; i < sink.num_srcs; i++)
  {
    stat = &sink.status_srcs[i];
    if (check_set_client_data(info, stat)) {
      print_summary(stat, &fail);
      bufcpy(buf, &fail, sizeof(Sfail_summary_t));
    }
  }
  return STATUS_MSG_COMPLETE;
}

/* Gives current status of all components registered with sympathy
 * and shows how to change parameters */
static
int sympathy_print_status(status_context_t *info, buf_t *buf)
{
  int i, j;
  sympathy_node_info_t* stat;
  sympathy_node_app_info_t* snode;

  bufprintf(buf, "Node\t Comp-Name\t Min Pkt Rx(%%)\n");
  for (i = 0; i < sink.num_srcs; i++) {
    stat = &sink.status_srcs[i];
    if (stat->addr > 0) {
      for (j = 0; j < sink.num_apps_registered; j++) {
        snode = &stat->node_app_info[j];
        bufprintf(buf, "%d  \t %s  \t %d\n", stat->addr, snode->comp_name,
            snode->pkt_reception_percent);
      }
    }
  }

  bufprintf(buf, "\n*****\nTo change a node's minimum required percent of packets expected by the sink, write:\n");
  bufprintf(buf, "\t\tnode=<id>:comp_name=<string>:rx_percent=<int>\n");
  bufprintf(buf, "**NOTE: This will override assignment from the corresponding component on the sink!\n");
  return STATUS_MSG_COMPLETE;
}

static
int sympathy_status_html(status_context_t *info, buf_t *buf)
{
  int i, j;
  sympathy_node_info_t* stat;
  sympathy_node_app_info_t* snode;
  sympathy_node_info_t* status_srcs_cpy[SMAX_SRCS];

  order_by_id(status_srcs_cpy);
  bufprintf(buf, "<table frame=void cellspacing=5 cellpadding=6>\n");
  bufprintf(buf, "<tr><td>%s</td><td>%s</td><td>%s</td></tr>\n",
	    "Node", "Comp-Name", "Min Pkt Rx(%)");
  bufprintf(buf, "<tr><td colspan=3>-----------------------------------------------------------</td></tr>");
  for (i = 0; i < sink.num_srcs; i++) {
    stat = status_srcs_cpy[i];
    if (stat->addr > 0) {
      for (j = 0; j < sink.num_apps_registered; j++) {
        snode = &stat->node_app_info[j];
        bufprintf(buf, "<tr><td>%d</td><td>%s</td><td>%d</td></tr>\n",
		  stat->addr, snode->comp_name,
		  snode->pkt_reception_percent);
      }
    }
  }

  bufprintf(buf, "</table>");
  return STATUS_MSG_COMPLETE;
}

int find_comp_name_index(char* comp_name, sympathy_node_info_t* stat) {
  int j;

  for (j = 0; j < sink.num_apps_registered; j++) {
    if (strcmp(stat->node_app_info[j].comp_name, comp_name) == 0) return j;
  }
  return -1;
}

static
int sympathy_status_write(status_context_t *ctx, char* cmd, size_t size)
{
  parser_state_t* ps = misc_parse_init(cmd, MISC_PARSE_COLON_SCHEME);
  sympathy_node_info_t* stat = NULL;
  char comp_name[100] = {};
  int rx_percent = -1;

  while (misc_parse_next_kvp(ps) >= 0) {
    if (!ps->value) {
      elog(LOG_ERR, "Key of %s requires a value!\n", ps->key);
      goto error;
    }

    if (strcmp(ps->key, "node") == 0) {
      if (!(stat = find_status_ptr(atoi(ps->value)))) {
        elog(LOG_ERR, "ERROR: Unable to find node %d!\n", atoi(ps->value));
        goto error;
      }
    }
    else if (strcmp(ps->key, "comp_name") == 0) {
      sprintf(comp_name, "%s", ps->value);
    }
    else if (strcmp(ps->key, "rx_percent") == 0) {
      rx_percent = atoi(ps->value);
    }
    else {
      elog(LOG_ERR, "Unrecognized key: %s\n", ps->key);
      goto error;
    }
  }

  if ((stat) && (rx_percent > -1) && (strlen(comp_name) > 0)) {
    int index = find_comp_name_index(comp_name, stat);
    if (index > -1) {
      elog(LOG_NOTICE, "Changing reception percent for comp_name %s from %d to %d\n", 
          comp_name, stat->node_app_info[index].pkt_reception_percent, 
          rx_percent);
      stat->node_app_info[index].pkt_reception_percent = rx_percent;
      stat->node_app_info[index].pkt_reception_locked = 1;
    }
    else goto error;
  }
  else goto error;
  misc_parse_cleanup(ps);
  return STATUS_WRITE_DONE;

error:
  misc_parse_cleanup(ps);
  elog(LOG_ERR, "ERROR: Bad argument(%s)! cat device for usage!\n",cmd);
  return EVENT_ERROR(EINVAL);
}

static
int sympathy_print_failures(status_context_t *info, buf_t *buf)
{
  print_summary_info(info, buf, 0, 0);
  return STATUS_MSG_COMPLETE;
}

static
int sympathy_failures_html(status_context_t *info, buf_t *buf)
{
  print_summary_info(info, buf, 0, 1);
  return STATUS_MSG_COMPLETE;
}

void initialize_devices()
{
  status_dev_opts_t sopts = {
    device: {
		},
	};
  
  /* Create a status device */
  sopts.device.devname = sympathy_device(SSINK_COMP_STATUS);
	sopts.printable = sympathy_print_status;
  sopts.html = sympathy_status_html;
	sopts.write = sympathy_status_write;
  if (g_status_dev(&sopts, &sink.sink_status) < 0) {
		elog(LOG_ERR, "Unable to open status device %s: %m\n", sopts.device.devname);
	}

  /* FOR all devices */
	sopts.close = sympathy_device_close;
	sopts.open = sympathy_device_open;

  /* For specific devices */
  sopts.device.devname = sympathy_device(SMETRICS_STATUS);
	sopts.printable = sympathy_print_metrics;
  sopts.html = sympathy_print_metrics_html;
  sopts.xml = sympathy_print_metrics_xml;
	sopts.write = sympathy_metrics_write;
	sopts.binary = sympathy_print_metrics_binary;
  if (g_status_dev(&sopts, &sink.metrics_status) < 0) {
		elog(LOG_ERR, "Unable to open status device %s: %m\n", sopts.device.devname);
	}

  sopts.device.devname = sympathy_device(SFAIL_STATUS);
	sopts.printable = sympathy_print_failures;
  sopts.html = sympathy_failures_html;
  sopts.xml = 0;
	sopts.write = 0;
  if (g_status_dev(&sopts, &sink.fail_status) < 0) {
		elog(LOG_ERR, "Unable to open status device %s: %m\n", sopts.device.devname);
	}

  sopts.device.devname = sympathy_device(SFAILURE_SUMMARY_STATUS);
	sopts.printable = sympathy_print_summary;
	sopts.binary = sympathy_print_summary_bin;
  if (g_status_dev(&sopts, &sink.summary_status) < 0) {
		elog(LOG_ERR, "Unable to open status device: %s: %m\n", sopts.device.devname);
	}

  /* Battery device */
  {
    status_dev_opts_t opts = {
      device: {
        devname: sympathy_device(SYMPATHY_BATTERY_DEVICE)
      },
      write: sbattery_write,
      printable: sbattery_print,
      html: sbattery_html
    };

    if (g_status_dev(&opts, NULL) < 0) {
      printf("unable to create status dev 1\n");
    }
  }
}




See more files for this project here

EmStar

EmStar is a software system for developing and deploying wireless sensor networks involving Linux-based platforms. As the wireless sensor network community has attempted to deploy more complex designs---large-scale, long-lived systems that need self-organization and adaptivity---a number of difficult software design issues have arisen. Advances in software design have not kept pace with the capabilities of hardware. This is because designing for an adaptive, efficient, and useful sensor network has turned out to be surprisingly complex and difficult. EmStar is a Linux-based software framework, whose goal is to dramatically reduce this complexity, enabling work to be shared and reused, and simplifying and speeding the design of new sensor network applications.

Project homepage: http://cvs.cens.ucla.edu/emstar/
Programming language(s): C,Shell Script
License: other

  bayes/
    lib/
      libnetica.a
    src/
      Netica.h
      NeticaEx.c
      NeticaEx.h
    bayes_classifier.c
    nodes.states
    training.prob
  include/
    sympathy.h
    sympathy_app.h
    sympathy_dev.h
    sympathy_routing.h
  libsympathy/
    sympathy_routing.c
  scripts/
    get_recent_status.pl
    get_throughput.pl
  testtabs/
    essjr.run
    essjr_sensor.run
    rr_mote.run
    rr_mote_ceiling.run
    sympathy.run
    sympathy_ceiling.sim
    sympathy_sim.sim
    sympathy_sim_small.sim
    sympathy_snoop.run
    sympathy_test.sim
  BUILD
  data.xml
  jr_loc_small
  sars.pl
  sympathy_analyze.c
  sympathy_battery.c
  sympathy_device.c
  sympathy_doc
  sympathy_emview.c
  sympathy_events.c
  sympathy_main.c
  sympathy_print_stats.c
  sympathy_status.c