Code Search for Developers
 
 
  

tosnic_lower.c from EmStar at Krugle


Show tosnic_lower.c syntax highlighted

/*
 *
 * Copyright (c) 2005 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.
 *
 */
 
#include "tosnic_i.h"
#include <termios.h>
#include <sys/uio.h>

/*
 *  tosnic_lower.c
 *
 *  Connects to local serial or remote tcp server, and handles integration with
 *  simulation and emulation
 *
 */

/*
 *  interface to framer 
 */

/* does NOT delete buffer */
void tosnic_lower_write(tosnic_state_t *s, buf_t *framed)
{
  elog(LOG_DEBUG(5), "Writing bytes to port:");
  elog_raw(LOG_DEBUG(5), framed->buf, framed->len);

  s->serial_tx_count += framed->len;
  
  if (s->net_port)
    ev_tcp_peer_write(s->net_port, framed);
  else {
    if (write_to_fd(s->serial_fd, framed->buf, framed->len) < 0) {
      elog(LOG_WARNING, "Error on underlying serial connection: %m");
      tosnic_reset(s);
    }
  }
}


/*
 *  serial handler
 */

static
int tosnic_lower_serial_data_ready(void *data, int fd, int cond, g_event_t *event)
{
  tosnic_state_t *s = (tosnic_state_t *)data;

  if (cond == FUSD_NOTIFY_INPUT) {
    buf_t *serial_data = buf_new();
    bufcpy(serial_data, NULL, TOSNIC_READ_LEN);
    int status = read(fd, serial_data->buf, TOSNIC_READ_LEN);
    if (status < 0) {
      if (errno == EINTR || errno == EAGAIN) 
	goto done;
      elog(LOG_CRIT, "Read error from serial %s: %m", s->local_device);
      exit(1);
    }
    if (status > 0) {
      serial_data->len = status;
      tosnic_framer_data_from_lower(s, serial_data);
    }

  done:
    return EVENT_RENEW;
  }

  elog(LOG_WARNING, "Exception on serial %s.. USB flaked?: %m", 
       s->local_device);
  close(fd);
  elog(LOG_WARNING, "Will attempt to reconnect after one second...");
  sleep(1);
  tosnic_reset(s);
  return EVENT_DONE;
}


/*
 *  tcp handlers
 */

static
int tosnic_lower_tcp_data_ready(ev_tcp_peer_t *peer, buf_t *data)
{
  tosnic_state_t *s = (tosnic_state_t *)ev_tcp_peer_get_peer_data(peer);
  tosnic_framer_data_from_lower(s, data);
  return EVENT_RENEW;
}

static
void tosnic_lower_tcp_close(ev_tcp_peer_t *peer, int errno_value)
{
  tosnic_state_t *s = (tosnic_state_t *)ev_tcp_peer_get_peer_data(peer);
  elog(LOG_CRIT, "exiting: connection to %s dropped: %s",
       s->serial_devname, strerror(errno_value));
  exit(1);
}


/*
 *  initialization
 */


int tosnic_lower_reset(tosnic_state_t *s)
{
  /* if host:port specified, connect to remote tcp port.. */
  if (s->hostname) {

    /* close if previously connected */
    if (s->net_port) ev_tcp_peer_close(s->net_port, 0);
    
    ev_tcp_peer_opts_t opts = {
      data_ready: tosnic_lower_tcp_data_ready,
      on_close: tosnic_lower_tcp_close,
      peer_info: s
    };

    s->net_port = ev_tcp_connect(NULL, s->hostname, s->port_num, &opts);
    if (s->net_port == NULL) {
      elog(LOG_CRIT, "Can't connect to %s: %m", s->serial_devname);
      exit(1);
    }
  }
  
  /* otherwise, open serial */
  else if (s->local_device) {

    /* close if previously open */
    if (s->serial) {
      close(s->serial_fd);
      g_event_destroy(s->serial);
    }

    /* Try to open the port */
    if ((s->serial_fd = open(s->local_device, O_RDWR | O_NOCTTY)) < 0) {
      elog(LOG_CRIT, "can't open %s: %m", s->local_device);
      exit(1);
    }
    
    /* configure the serial port: raw, set baud, no rtscts */
    misc_config_serial(s->serial_fd, s->baud, s->rtscts);

    /* flush output */
    if (tcflush(s->serial_fd, TCIFLUSH) < 0)
      elog(LOG_WARNING, "can't tcflush serial port %s: %m", s->local_device);
    
    /* Set this FD to be nonblocking */
    set_nonblock(s->serial_fd, 1);
    
    /* Add an event that fires when the serial port is readable */
    if (g_event_add(s->serial_fd, FUSD_NOTIFY_INPUT | FUSD_NOTIFY_EXCEPT, 
		    tosnic_lower_serial_data_ready, s, NULL, &s->serial) < 0) {
      elog(LOG_CRIT, "can't create event for %s: %m", s->local_device);
      exit(1);
    }
  }

  else return -1;

  return 0;
}


static
void tosnic_parse_moteid(tosnic_state_t *s)
{
  char *dup = strdup(s->serial_devname);

  /* is it a host:port? */
  char *colon;
  if ((colon = strchr(dup, ':'))) {
    *colon = 0;
    colon++;
    s->port_num = atoi(colon);
    s->hostname = dup;
  }
  
  else if (strncmp(dup, "/dev/", 5) == 0) {
    s->local_device = dup;
  }
  
  else {
    int id;
    if (sscanf(dup, "%d", &id) == 1) {
      char port[20];
      sprintf(port, "/dev/tty%d", id);
      s->local_device = strdup(port);
    }
    else {
      elog(LOG_WARNING, "*** Error parsing mote config string '%s'", dup);
      exit(1);
    }
  }
}


int tosnic_lower_init(tosnic_state_t *s, int *argc, char **argv)
{
  /* parse lower configuration args */
  s->serial_devname = misc_parse_out_option(argc, argv, "port", 0);
  s->baud_requested = (0 == misc_parse_option_as_uint(argc, argv, "baud", 'b', &s->baud));
  s->rtscts = misc_parse_out_switch(argc, argv, "rtscts", 0);
  s->power_requested = (0 == misc_parse_option_as_uint(argc, argv, "power", 'p', &s->power));
  s->mote_type_str = misc_parse_out_option(argc, argv, "mote", 'm');
  int debug_in_sim = misc_parse_out_switch(argc, argv, "debug_in_sim", 0);

  /* parse the mote type */
  if (s->mote_type_str) {
    if (strcmp(s->mote_type_str, "mica2") == 0) {
      s->mote_type = TOSNIC_MICA2;
    }
    else if (strcmp(s->mote_type_str, "mica2dot") == 0) {
      s->mote_type = TOSNIC_MICA2DOT;
    }
    else if (strcmp(s->mote_type_str, "mica") == 0) {
      s->mote_type = TOSNIC_MICA1;
    }
    else if (strcmp(s->mote_type_str, "telos") == 0) {
      s->mote_type = TOSNIC_TELOS;
    }
    else if (strcmp(s->mote_type_str, "cricket") == 0) {
      s->mote_type = TOSNIC_CRICKET;
    }
    else {
      elog(LOG_WARNING, "Unknown mote type '%s'.. aborting", s->mote_type_str);
      exit(1);
    }
  }

  /* mica2 is default */
  else {
    s->mote_type_str = "mica2";
    s->mote_type = TOSNIC_MICA2;
  }

  /* if a mote type is set, autoconf baud rate */
  if (!s->baud_requested) {
    switch (s->mote_type) {
    case TOSNIC_MICA2:
      s->baud = 57600;
      break;
    case TOSNIC_MICA1:
    case TOSNIC_MICA2DOT:
      s->baud = 19200;
      break;
    case TOSNIC_CRICKET:
      s->baud = 115200;
      break;
    case TOSNIC_TELOS:
      s->baud = 262144;
      break;
    }
  }

  /* if a mote type is set, autoconf power */
  if (!s->power_requested) {
    s->power = 15;
    if (s->mote_type == TOSNIC_MICA1)
      s->power = 67;
  }

  /* are we in sim mode? */
  if (in_sim) {

    /* if we're in proxy mode, we don't do anything locally */
    char *proxy_host = misc_sim_get_proxy_host(s->dev_name, argc, argv);    
    if (proxy_host) {
      /* ok, we connect to the remote host.. */
      elog(LOG_NOTICE, "Connecting to remote host %s, link device %s", proxy_host, s->dev_name);
      elog(LOG_NOTICE, "Mapping to group %d, node %d, device %s", my_sim_group, my_node_id, s->dev_name);
      
      lp_register_in_class(s->class_name, s->dev_name);
      if (!(fusdd_proxy_connect(proxy_host, link_name_s_nosim(s->dev_name, LINK_DATA_SUBDEV),
				link_name_s(s->dev_name, LINK_DATA_SUBDEV), NULL) == 0 &&
	    fusdd_proxy_connect(proxy_host, link_name_s_nosim(s->dev_name, LINK_STATUS_SUBDEV),
				link_name_s(s->dev_name, LINK_STATUS_SUBDEV), NULL) == 0 &&
	    fusdd_proxy_connect(proxy_host, link_name_s_nosim(s->dev_name, LINK_COMMAND_SUBDEV),
				link_name_s(s->dev_name, LINK_COMMAND_SUBDEV), NULL) == 0)) {
	/* $$$ expose the other mote devices.. */
	elog(LOG_CRIT, "Failed to connect to remote host: %m");
	exit(1);
      }
      return 1;
    }
    
    /* or do we have a mote ID env var? */
    char *str = getenv("MOTE_ID");
    if (str) {
      elog(LOG_NOTICE, "In ceiling mode... overriding port argument with %s", str);
      s->serial_devname = strdup(str);
    }

    /* if not, check to see if there's an active channel model. */
    else {
      lp_opts_t opts = {
	opts: {
	  name: s->dev_name,
	  if_class: s->class_name
	}
      };
      if (lp_check_sim(&opts))
	return 1;

      if (debug_in_sim) {
	elog(LOG_CRIT, "****************SIM DEBUGGING MODE!!!!");
	s->serial_devname = sim_path(s->serial_devname);
	elog(LOG_CRIT, "Will actually open lower device %s", s->serial_devname);
      }
      else {
	elog(LOG_CRIT, "***In SIM mode, but no simulated channel model or ceiling config present!");
	elog(LOG_CRIT, "***Please check your configuration!!   Exiting!");
	exit(1);  
      }    
    }
  }
  
  /* OK, now we will parse the port argument and open the lower connection */
  if (s->serial_devname) {
    tosnic_parse_moteid(s);
    if (tosnic_lower_reset(s) < 0) {
      /* nothing to open..? */
      elog(LOG_CRIT, "?? no hostname or local device to open?");
      exit(1);
    }  
  }

  else {
    elog(LOG_CRIT, "Must specify --port argument or provide via MOTE_ID environment variable!");
    usage(argv[0]);
    exit(1);
  }

  /* and continue to provide upper.. */
  return 0;
}






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

  status_scheme.txt
  tosnic_framer.c
  tosnic_i.h
  tosnic_lower.c
  tosnic_main.c
  tosnic_status.c
  tosnic_status_types.h
  tosnic_upper.c