Ejemplo n.º 1
0
/*---------------------------------------------------------------------------*/			
static unsigned short
make_routes(void *p)
{
  static const char httpd_cgi_rtes1[] HTTPD_STRING_ATTR = "(%u (via ";
  static const char httpd_cgi_rtes2[] HTTPD_STRING_ATTR = ") %lus<br>";
  static const char httpd_cgi_rtes3[] HTTPD_STRING_ATTR = ")<br>";
  uint8_t i,j=0;
  uint16_t numprinted;
  uip_ds6_route_t *r;

  numprinted = httpd_snprintf((char *)uip_appdata, uip_mss(),httpd_cgi_addrh);
  for(r = uip_ds6_route_list_head();
      r != NULL;
      r = list_item_next(r)) {
    j++;
    numprinted += httpd_cgi_sprint_ip6(r->ipaddr, uip_appdata + numprinted);
    numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_rtes1, r->length);
    numprinted += httpd_cgi_sprint_ip6(r->nexthop, uip_appdata + numprinted);
    if(r->state.lifetime < 3600) {
      numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_rtes2, r->state.lifetime);
    } else {
      numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_rtes3);
    }
  }
  if (j==0) numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_addrn);
  numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_addrf,UIP_DS6_ROUTE_NB-j);
  return numprinted;
}
Ejemplo n.º 2
0
static
PT_THREAD(generate_network(struct httpd_state *s))
{
  static int i;
  static uip_ds6_route_t *r;
  static uip_ds6_defrt_t *dr;

#if BUF_USES_STACK
  char buf[BUF_SIZE];
#endif
#if WEBSERVER_CONF_LOADTIME
  static clock_time_t numticks;

  numticks = clock_time();
#endif

  PSOCK_BEGIN(&s->sout);

  SEND_STRING(&s->sout, TOP);
  if(redirect) {
    //Quick hack to rewrite url after route or neighbour removal
    SEND_STRING(&s->sout,
                "<meta http-equiv=\"refresh\" content=\"0; url=/network.html\" />");
  }
  SEND_STRING(&s->sout, BODY);
  reset_buf();

  add_div_home("Network");
  add("<div id=\"left_home\">");
  add("<br /><h2>Addresses</h2><pre>");
  SEND_STRING(&s->sout, buf);
  reset_buf();

  for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
    if(uip_ds6_if.addr_list[i].isused) {
      ipaddr_add(&uip_ds6_if.addr_list[i].ipaddr);
      char flag;

      if(uip_ds6_if.addr_list[i].state == ADDR_TENTATIVE) {
        flag = 'T';
      } else if(uip_ds6_if.addr_list[i].state == ADDR_PREFERRED) {
        flag = 'P';
      } else {
        flag = '?';
      }
      add(" %c", flag);
      if(uip_ds6_if.addr_list[i].type == ADDR_MANUAL) {
        flag = 'M';
      } else if(uip_ds6_if.addr_list[i].type == ADDR_DHCP) {
        flag = 'D';
      } else if(uip_ds6_if.addr_list[i].type == ADDR_AUTOCONF) {
        flag = 'A';
      } else {
        flag = '?';
      }
      add(" %c", flag);
      if(!uip_ds6_if.addr_list[i].isinfinite) {
        add(" %u s", stimer_remaining(&uip_ds6_if.addr_list[i].vlifetime));
      }
      add("\n");
      SEND_STRING(&s->sout, buf);
      reset_buf();
    }
  }

  add("</pre><h2>Prefixes</h2><pre>");
  for(i = 0; i < UIP_DS6_PREFIX_NB; i++) {
    if(uip_ds6_prefix_list[i].isused) {
      ipaddr_add(&uip_ds6_prefix_list[i].ipaddr);
      add(" ");
#if UIP_CONF_ROUTER
      if(uip_ds6_prefix_list[i].advertise) {
        add("A");
      }
#else
      if(uip_ds6_prefix_list[i].isinfinite) {
        add("I");
      }
#endif
      add("\n");
    }
  }
  SEND_STRING(&s->sout, buf);
  reset_buf();

  add("</pre><h2>Neighbors</h2><pre>");
  for(i = 0; i < UIP_DS6_NBR_NB; i++) {
    if(uip_ds6_nbr_cache[i].isused) {
      if ((nvm_data.global_flags & CETIC_GLOBAL_DISABLE_CONFIG) == 0) {
        add("[<a href=\"nbr_rm?%d\">del</a>] ", i);
      }
      ipaddr_add(&uip_ds6_nbr_cache[i].ipaddr);
      add(" ");
      lladdr_add(&uip_ds6_nbr_cache[i].lladdr);
      add(" ");
      add_network_cases(uip_ds6_nbr_cache[i].state);
      add("\n");
      SEND_STRING(&s->sout, buf);
      reset_buf();
    }
  }
  add("</pre><h2>Routes</h2><pre>");
  SEND_STRING(&s->sout, buf);
  reset_buf();
  for(r = uip_ds6_route_list_head(), i = 0; r != NULL;
      r = list_item_next(r), ++i) {
    if ((nvm_data.global_flags & CETIC_GLOBAL_DISABLE_CONFIG) == 0) {
      add("[<a href=\"route_rm?%d\">del</a>] ", i);
    }
    ipaddr_add(&r->ipaddr);
    add("/%u (via ", r->length);
    ipaddr_add(&r->nexthop);
    if(1 || (r->state.lifetime < 600)) {
      add(") %lu s\n", r->state.lifetime);
    } else {
      add(")\n");
    }
    SEND_STRING(&s->sout, buf);
    reset_buf();
  }

  add("</pre><h2>Default Routers</h2><pre>");

  for(dr = uip_ds6_defrt_list_head(); dr != NULL; dr = list_item_next(r)) {
    ipaddr_add(&dr->ipaddr);
    if(!dr->isinfinite) {
      add(" %u s", stimer_remaining(&dr->lifetime));
    }
    add("\n");
    SEND_STRING(&s->sout, buf);
    reset_buf();
  }

#if UIP_CONF_DS6_ROUTE_INFORMATION
  add("</pre><h2>Route info</h2><pre>");
  for(i = 0; i < UIP_DS6_ROUTE_INFO_NB; i++) {
    if(uip_ds6_route_info_list[i].isused) {
      ipaddr_add(&uip_ds6_route_info_list[i].ipaddr);
      add("/%u (%x) %us\n", uip_ds6_route_info_list[i].length,
          uip_ds6_route_info_list[i].flags,
          uip_ds6_route_info_list[i].lifetime);
    }
  }
  SEND_STRING(&s->sout, buf);
  reset_buf();
#endif

#if CETIC_6LBR_TRANSPARENTBRIDGE
  add("</pre><h2>HW Prefixes cache</h2><pre>");
  for(i = 0; i < prefixCounter; i++) {
    add("%02x:%02x:%02x\n", prefixBuffer[i][0], prefixBuffer[i][1],
        prefixBuffer[i][2]);
  }
  SEND_STRING(&s->sout, buf);
  reset_buf();
  add("</pre><br />");
#endif

  add_div_footer();
#if WEBSERVER_CONF_FILESTATS
  static uint16_t numtimes;

  add("<br><i>This page sent %u times</i>", ++numtimes);
#endif

#if WEBSERVER_CONF_LOADTIME
  numticks = clock_time() - numticks + 1;
  add(" <i>(%u.%02u sec)</i>", numticks / CLOCK_SECOND,
      (100 * (numticks % CLOCK_SECOND) / CLOCK_SECOND));
#endif
  add("</div></div>");
  SEND_STRING(&s->sout, buf);
  SEND_STRING(&s->sout, BOTTOM);

  PSOCK_END(&s->sout);
}
Ejemplo n.º 3
0
/*---------------------------------------------------------------------------*/
static
PT_THREAD(generate_routes(struct httpd_state *s))
{
  static int i;
  static uip_ds6_route_t *r;
#if BUF_USES_STACK
  char buf[256];
#endif
#if WEBSERVER_CONF_LOADTIME
  static clock_time_t numticks;
  numticks = clock_time();
#endif

  PSOCK_BEGIN(&s->sout);

  SEND_STRING(&s->sout, TOP);
#if BUF_USES_STACK
  bufptr = buf;bufend=bufptr+sizeof(buf);
#else
  blen = 0;
#endif
  ADD("Neighbors<pre>");
  for(i = 0; i < UIP_DS6_NBR_NB; i++) {
    if(uip_ds6_nbr_cache[i].isused) {

#if WEBSERVER_CONF_NEIGHBOR_STATUS
#if BUF_USES_STACK
{char* j=bufptr+25;
      ipaddr_add(&uip_ds6_nbr_cache[i].ipaddr);
      while (bufptr < j) ADD(" ");
      switch (uip_ds6_nbr_cache[i].state) {
      case NBR_INCOMPLETE: ADD(" INCOMPLETE");break;
      case NBR_REACHABLE: ADD(" REACHABLE");break;
      case NBR_STALE: ADD(" STALE");break;      
      case NBR_DELAY: ADD(" DELAY");break;
      case NBR_PROBE: ADD(" NBR_PROBE");break;
      }
}
#else
{uint8_t j=blen+25;
      ipaddr_add(&uip_ds6_nbr_cache[i].ipaddr);
      while (blen < j) ADD(" ");
      switch (uip_ds6_nbr_cache[i].state) {
      case NBR_INCOMPLETE: ADD(" INCOMPLETE");break;
      case NBR_REACHABLE: ADD(" REACHABLE");break;
      case NBR_STALE: ADD(" STALE");break;      
      case NBR_DELAY: ADD(" DELAY");break;
      case NBR_PROBE: ADD(" NBR_PROBE");break;
      }
}
#endif
#else
      ipaddr_add(&uip_ds6_nbr_cache[i].ipaddr);
#endif

      ADD("\n");
#if BUF_USES_STACK
      if(bufptr > bufend - 45) {
        SEND_STRING(&s->sout, buf);
        bufptr = buf; bufend = bufptr + sizeof(buf);
      }
#else
      if(blen > sizeof(buf) - 45) {
        SEND_STRING(&s->sout, buf);
        blen = 0;
      }
#endif
    }
  }
  ADD("</pre>Routes<pre>");
  SEND_STRING(&s->sout, buf);
#if BUF_USES_STACK
  bufptr = buf; bufend = bufptr + sizeof(buf);
#else
  blen = 0;
#endif

  for(r = uip_ds6_route_list_head(); r != NULL; r = list_item_next(r)) {

#if BUF_USES_STACK
#if WEBSERVER_CONF_ROUTE_LINKS
    ADD("<a href=http://[");
    ipaddr_add(&r->ipaddr);
    ADD("]/status.shtml>");
    ipaddr_add(&r->ipaddr);
    ADD("</a>");
#else
    ipaddr_add(&r->ipaddr);
#endif
#else
#if WEBSERVER_CONF_ROUTE_LINKS
    ADD("<a href=http://[");
    ipaddr_add(&r->ipaddr);
    ADD("]/status.shtml>");
    SEND_STRING(&s->sout, buf); //TODO: why tunslip6 needs an output here, wpcapslip does not
    blen = 0;
    ipaddr_add(&r->ipaddr);
    ADD("</a>");
#else
    ipaddr_add(&r->ipaddr);
#endif
#endif
    ADD("/%u (via ", r->length);
    ipaddr_add(&r->nexthop);
    if(1 || (r->state.lifetime < 600)) {
      ADD(") %lus\n", r->state.lifetime);
    } else {
      ADD(")\n");
    }
    SEND_STRING(&s->sout, buf);
#if BUF_USES_STACK
    bufptr = buf; bufend = bufptr + sizeof(buf);
#else
    blen = 0;
#endif
  }
  ADD("</pre>");

#if WEBSERVER_CONF_FILESTATS
  static uint16_t numtimes;
  ADD("<br><i>This page sent %u times</i>",++numtimes);
#endif

#if WEBSERVER_CONF_LOADTIME
  numticks = clock_time() - numticks + 1;
  ADD(" <i>(%u.%02u sec)</i>",numticks/CLOCK_SECOND,(100*(numticks%CLOCK_SECOND))/CLOCK_SECOND));
#endif

  SEND_STRING(&s->sout, buf);
  SEND_STRING(&s->sout, BOTTOM);

  PSOCK_END(&s->sout);
}
Ejemplo n.º 4
0
/*---------------------------------------------------------------------------*/
httpd_simple_script_t
httpd_simple_get_script(const char *name)
{
  static uip_ds6_route_t *r;
  static char filename[HTTPD_PATHLEN];
  static int i;

  strcpy(filename, slip_config_www_root);
  strcat(filename, "/");
  strcat(filename, name);

  redirect = 0;

  if(strcmp(name, "index.html") == 0 || strcmp(name, "") == 0) {
    return generate_index;
#if CONTIKI_TARGET_NATIVE
  } else if (access(filename, R_OK) == 0) {
      return send_file;
#endif
#if CETIC_NODE_INFO
  } else if(strcmp(name, "sensors.html") == 0) {
    return generate_sensors;
#endif
  } else if(strcmp(name, "rpl.html") == 0) {
    return generate_rpl;
  } else if(strcmp(name, "network.html") == 0) {
    return generate_network;
  } else if(strcmp(name, "config.html") == 0) {
    return generate_config;
  } else if(strcmp(name, "statistics.html") == 0) {
    return generate_statistics;
  } else if ((nvm_data.global_flags & CETIC_GLOBAL_DISABLE_CONFIG) == 0) {
    if(strcmp(name, "rpl-gr") == 0) {
#if UIP_CONF_IPV6_RPL
      rpl_repair_root(RPL_DEFAULT_INSTANCE);
#endif
      return generate_rpl;
    } else if(memcmp(name, "route_rm?", 9) == 0) {
      redirect = 1;
      i = atoi(name + 9);
      for(r = uip_ds6_route_list_head(); r != NULL; r = list_item_next(r), --i) {
        if(i == 0) {
          uip_ds6_route_rm(r);
          break;
        }
      }
      return generate_network;
    } else if(memcmp(name, "nbr_rm?", 7) == 0) {
      redirect = 1;
      uip_ds6_nbr_rm(&uip_ds6_nbr_cache[atoi(name + 7)]);
      return generate_network;
    } else if(memcmp(name, "config?", 7) == 0) {
      if(update_config(name + 7)) {
        return generate_config;
      } else {
        return generate_reboot;
      }
    } else {
      return generate_404;
    }
  } else {
    return generate_404;
  }
}
Ejemplo n.º 5
0
void menu_process(char c)
{
  static enum menustate_enum            /* Defines an enumeration type    */
  {
      normal,
      channel,
      txpower
  } menustate = normal;

  static char channel_string[3];
  static uint8_t channel_string_i;// = 0;

  int tempchannel;

  if (menustate == channel) {

    switch(c) {
    case '\r':
    case '\n':
      if (channel_string_i) {
        channel_string[channel_string_i] = 0;
        tempchannel = atoi(channel_string);

        if ((tempchannel < 11) || (tempchannel > 26)) {
          PRINTF_P(PSTR("\n\rInvalid input\n\r"));
        } else {
          rf230_set_channel(tempchannel);

#if CONTIKI_CONF_SETTINGS_MANAGER
          if(settings_set_uint8(SETTINGS_KEY_CHANNEL, tempchannel) == SETTINGS_STATUS_OK) {
            PRINTF_P(PSTR("\n\rChannel changed to %d and stored in EEPROM.\n\r"), tempchannel);
          } else {
            PRINTF_P(PSTR("\n\rChannel changed to %d, but unable to store in EEPROM!\n\r"), tempchannel);
          }
#else
          PRINTF_P(PSTR("\n\rChannel changed to %d.\n\r"), tempchannel);
#endif
        }
      } else {
        PRINTF_P(PSTR("\n\rChannel unchanged.\n\r"));
      }

      menustate = normal;
      break;

    case '\b':
      if (channel_string_i) {
        channel_string_i--;
        PRINTF_P(PSTR("\b \b"));
      }
      break;

    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
      if (channel_string_i > 1) {
        // This time the user has gone too far.
        // Beep at them.
        putc('\a', stdout);
        break;
      }
      putc(c, stdout);
      channel_string[channel_string_i] = c;
      channel_string_i++;
      break;

    default:
      break;
    }

  } else if (menustate == txpower) {

    switch(c) {
    case '\r':
    case '\n':
      if (channel_string_i) {
        channel_string[channel_string_i] = 0;
        tempchannel = atoi(channel_string);

        if ((tempchannel < 0) || (tempchannel > 15))  {
          PRINTF_P(PSTR("\n\rInvalid input\n\r"));
        } else {
          PRINTF_P(PSTR(" ")); //for some reason needs a print here to clear the string input...
          rf230_set_txpower(tempchannel);

#if CONTIKI_CONF_SETTINGS_MANAGER
          if(settings_set_uint8(SETTINGS_KEY_TXPOWER, tempchannel) == SETTINGS_STATUS_OK) {
            PRINTF_P(PSTR("\n\rTransmit power changed to %d, and stored in EEPROM.\n\r"), tempchannel);
          } else {
            PRINTF_P(PSTR("\n\rTransmit power changed to %d, but unable to store in EEPROM!\n\r"), tempchannel);
          }
#else
          PRINTF_P(PSTR("\n\rTransmit power changed to %d.\n\r"), tempchannel);
#endif
        }
      } else {
        PRINTF_P(PSTR("\n\rTransmit power unchanged.\n\r"));
      }

      menustate = normal;
      break;

    case '\b':
      if (channel_string_i) {
        channel_string_i--;
        PRINTF_P(PSTR("\b \b"));
      }
      break;

    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
      if (channel_string_i > 1) {
        // This time the user has gone too far.
        // Beep at them.
        putc('\a', stdout);
        break;
      }
      putc(c, stdout);
      channel_string[channel_string_i] = c;
      channel_string_i++;
      break;

    default:
      break;
    }

  } else {
    uint8_t i;

    switch(c) {
    case '\r':
    case '\n':
      break;

    case 'h':
    case '?':
      menu_print();
      break;

    case 'd':
      if (mx_console_mode.debugOn) {
        PRINTF_P(PSTR("Node does not output debug strings\n\r"));
        mx_console_mode.debugOn = 0;
      } else {
        PRINTF_P(PSTR("Node now outputs debug strings\n\r"));
        mx_console_mode.debugOn = 1;
      }
      break;

    case 'c':
      PRINTF_P(PSTR("\nSelect 802.15.4 Channel in range 11-26 [%d]: "), rf230_get_channel());
      menustate = channel;
      channel_string_i = 0;
      break;
    case 'p':
      PRINTF_P(PSTR("\nSelect transmit power (0=+3dBm 15=-17.2dBm) [%d]: "), rf230_get_txpower());
      menustate = txpower;
      channel_string_i = 0;
      break;

#if UIP_CONF_IPV6_RPL
#include "rpl.h"
extern uip_ds6_nbr_t uip_ds6_nbr_cache[];
extern uip_ds6_netif_t uip_ds6_if;

    case 'N':
    {
      uint8_t i,j;
      PRINTF_P(PSTR("\n\rAddresses [%u max]\n\r"),UIP_DS6_ADDR_NB);
      for (i=0;i<UIP_DS6_ADDR_NB;i++) {
        if (uip_ds6_if.addr_list[i].isused) {
          ipaddr_add(&uip_ds6_if.addr_list[i].ipaddr);
          PRINTF_P(PSTR("\n\r"));
        }
      }
      PRINTF_P(PSTR("\n\rNeighbors [%u max]\n\r"),UIP_DS6_NBR_NB);
      for(i = 0,j=1; i < UIP_DS6_NBR_NB; i++) {
        if(uip_ds6_nbr_cache[i].isused) {
          ipaddr_add(&uip_ds6_nbr_cache[i].ipaddr);
          PRINTF_P(PSTR("\n\r"));
          j=0;
        }
      }
      if (j) PRINTF_P(PSTR("  <none>"));
      PRINTF_P(PSTR("\n\rRoutes [%u max]\n\r"),UIP_DS6_ROUTE_NB);
      {
        uip_ds6_route_t *r;
        j = 1;
        for(r = uip_ds6_route_list_head();
            r != NULL;
            r = list_item_next(r)) {
          ipaddr_add(&r->ipaddr);
          PRINTF_P(PSTR("/%u (via "), r->length);
          ipaddr_add(&r->nexthop);
          if(r->state.lifetime < 600) {
            PRINTF_P(PSTR(") %lus\n\r"), r->state.lifetime);
          } else {
            PRINTF_P(PSTR(")\n\r"));
          }
          j = 0;
        }
      }

      if (j) PRINTF_P(PSTR("  <none>"));
      PRINTF_P(PSTR("\n\r---------\n\r"));
      break;
    }

    case 'G':
      PRINTF_P(PSTR("Global repair returns %d\n\r"),rpl_repair_root(RPL_DEFAULT_INSTANCE));
      break;

    case 'L':
      rpl_local_repair(rpl_get_any_dag());
      PRINTF_P(PSTR("Local repair initiated\n\r"));
      break;

#endif

    case 'm':
      PRINTF_P(PSTR("Currently running on\n\r"));
      PRINTF_P(PSTR("  * %s\n\r"), CONTIKI_VERSION_STRING);
      PRINTF_P(PSTR("  * NETSTACK_MAC: %s, NETSTACK_RDC: %s\n\r"), NETSTACK_MAC.name, NETSTACK_RDC.name);
#if 1
      {
        int i;
        PRINTF_P(PSTR("  * Address: "));
        for (i = 0; i < 6; i += 2) {
          PRINTF_P(PSTR("%02x%02x:"), uip_lladdr.addr[i], uip_lladdr.addr[i + 1]);
        }
        PRINTF_P(PSTR("%02x%02x\n\r"), uip_lladdr.addr[6], uip_lladdr.addr[7]);
      }
#endif
#if UIP_CONF_IPV6_RPL
      PRINTF_P(PSTR("  * RPL Enabled\n\r"));
#endif
#if UIP_CONF_ROUTER
      PRINTF_P(PSTR("  * Routing Enabled\n\r"));
#endif
#if CONVERTTXPOWER
      PRINTF_P(PSTR("  * Operates on channel %d with TX power "),rf230_get_channel());
      printtxpower();
      PRINTF_P(PSTR("\n\r"));
#else  //just show the raw value
      PRINTF_P(PSTR("  * Operates on channel %d\n\r"), rf230_get_channel());
      PRINTF_P(PSTR("  * TX Power(0=+3dBm, 15=-17.2dBm): %d\n\r"), rf230_get_txpower());
#endif
      if (rf230_smallest_rssi) {
        PRINTF_P(PSTR("  * Current/Last/Smallest RSSI: %d/%d/%ddBm\n\r"), -91+(rf230_rssi()-1), -91+(rf230_last_rssi-1),-91+(rf230_smallest_rssi-1));
        rf230_smallest_rssi=0;
      } else {
        PRINTF_P(PSTR("  * Current/Last/Smallest RSSI: %d/%d/--dBm\n\r"), -91+(rf230_rssi()-1), -91+(rf230_last_rssi-1));
      }

#if CONFIG_STACK_MONITOR
      /* See contiki-raven-main.c for initialization of the magic numbers */
      {
        extern uint16_t __bss_end;
        uint16_t p=(uint16_t)&__bss_end;
        do {
          if (*(uint16_t *)p != 0x4242) {
            printf_P(PSTR("  * Never-used stack > %d bytes\n\r"),p-(uint16_t)&__bss_end);
            break;
          }
          p+=100;
        } while (p<RAMEND-100);
      }
#endif

      break;

    case 'e':
      PRINTF_P(PSTR("Energy Scan:\n"));
      {
        uint8_t i;
        uint16_t j;
        uint8_t previous_channel = rf230_get_channel();
        int8_t RSSI, maxRSSI[17];
        uint16_t accRSSI[17];

        bzero((void*)accRSSI,sizeof(accRSSI));
        bzero((void*)maxRSSI,sizeof(maxRSSI));

        for(j=0;j<(1<<12);j++) {
          for(i=11;i<=26;i++) {
            rf230_listen_channel(i);

            _delay_us(3*10);
            RSSI = rf230_rssi();  //multiplies rssi register by 3 for consistency with energy-detect register
            maxRSSI[i-11]=Max(maxRSSI[i-11],RSSI);
            accRSSI[i-11]+=RSSI;
          }

          if(j&(1<<7)) {
            leds_on(LEDS_RED);
            if(!(j&((1<<7)-1))) {
              PRINTF_P(PSTR("."));
            }
          } else {
            leds_off(LEDS_RED);
          }

          watchdog_periodic();
        }

        rf230_set_channel(previous_channel);

        PRINTF_P(PSTR("\n"));
        for(i=11;i<=26;i++) {
          uint8_t activity=Min(maxRSSI[i-11],accRSSI[i-11]/(1<<7));
          PRINTF_P(PSTR(" %d: %02ddB "),i, -91+(maxRSSI[i-11]-1));
          for(;activity--;maxRSSI[i-11]--) {
            PRINTF_P(PSTR("#"));
          }
          for(;maxRSSI[i-11]>0;maxRSSI[i-11]--) {
            PRINTF_P(PSTR(":"));
          }
          PRINTF_P(PSTR("\n"));
        }
      }

      PRINTF_P(PSTR("Done.\n"));
      break;

    case 'R':
      PRINTF_P(PSTR("Resetting...\n\r"));
      leds_on(LEDS_ALL);
      for(i = 0; i < 20; i++) _delay_ms(100);
      watchdog_reboot();
      break;

    default:
      PRINTF_P(PSTR("%c is not a valid option! h for menu\n\r"), c);
      break;
    }

  }
}