[Tinyos-2-commits] CVS: tinyos-2.x/support/sdk/c/sf Makefile.am, NONE, 1.1 README, NONE, 1.1 autoconf.h, NONE, 1.1 bootstrap, NONE, 1.1 build.xml, NONE, 1.1 configure.ac, NONE, 1.1 message.c, NONE, 1.1 message.h, NONE, 1.1 prettylisten.c, NONE, 1.1 seriallisten.c, NONE, 1.1 serialsend.c, NONE, 1.1 serialsource.c, NONE, 1.1 serialsource.h, NONE, 1.1 sf.c, NONE, 1.1 sflisten.c, NONE, 1.1 sfsend.c, NONE, 1.1 sfsource.c, NONE, 1.1 sfsource.h, NONE, 1.1

Omprakash Gnawali gnawali at users.sourceforge.net
Wed Dec 5 14:49:48 PST 2007


Update of /cvsroot/tinyos/tinyos-2.x/support/sdk/c/sf
In directory sc8-pr-cvs10.sourceforge.net:/tmp/cvs-serv7736

Added Files:
	Makefile.am README autoconf.h bootstrap build.xml configure.ac 
	message.c message.h prettylisten.c seriallisten.c serialsend.c 
	serialsource.c serialsource.h sf.c sflisten.c sfsend.c 
	sfsource.c sfsource.h 
Log Message:
moving from sdk/c

--- NEW FILE: Makefile.am ---
AUTOMAKE_OPTIONS = foreign

TOS=$(shell ncc -print-tosdir)
SERIAL_H = $(TOS)/lib/serial/Serial.h

BUILT_SOURCES = serialpacket.h serialprotocol.h

bin_PROGRAMS=sf 
noinst_PROGRAMS=prettylisten sflisten sfsend seriallisten serialsend
noinst_LIBRARIES=libmote.a

sf_SOURCES = sf.c
sf_LDADD = libmote.a

prettylisten_SOURCES = prettylisten.c
prettylisten_LDADD = libmote.a

sflisten_SOURCES = sflisten.c
sflisten_LDADD = libmote.a

sfsend_SOURCES = sfsend.c
sfsend_LDADD = libmote.a

seriallisten_SOURCES = seriallisten.c
seriallisten_LDADD = libmote.a

serialsend_SOURCES = serialsend.c
serialsend_LDADD = libmote.a

libmote_a_SOURCES = \
	message.c \
	serialpacket.c \
	serialsource.c \
	sfsource.c

serialpacket.c serialpacket.h: $(SERIAL_H)
	mig -o serialpacket.h -c-prefix=spacket c $(SERIAL_H) serial_packet

serialprotocol.h: $(SERIAL_H)
	ncg -o $@ -c-prefix=SERIAL c $(SERIAL_H) Serial.h

--- NEW FILE: README ---
Mini C-SDK for TinyOS
=====================

This directory contains a mini-SDK for C, for communicating with motes
running TinyOS 2.0. To build this SDK, run 
  ./bootstrap
  ./configure --prefix=<somewhere>
  make
in the current directory and, if you wish, "make install" to install the
C-based serial forwarder in <somewhere>/bin.

This directory contains one utility:
- sf: a C-based serial forwarder:
    sf <port> <device> <baudrate>
  Starts a serial forwarder listening for TCP connections on port <port>, and
  sending and receiving packets on serial port <device> at the specified
  <baudrate>.

  This serial forwarder implements the standard TinyOS 2.0 serial forwarder
  protocol (see comments in support/sdk/java/net/tinyos/packet/SFProtocol.java
  for a brief overview).

a library (libmote.a) supporting mote communication:
- serialsource.h: send and receive packets over a serial port (supports
  non-blocking I/O)
- sfsource.h: send and receive packets using the serial forwarder
  protocol
- message.h: support functions for mig, to encode and decode bitfields of
  arbitrary size and endianness
- serialpacket.h: mig-generated code to encode and decode the header of
  TinyOS serial active-message packets (the packets sent and received by the
  BaseStation application)
- serialprotocol.h: ncg-generated code containing the constants describing
  TinyOS serial packets (from tos/lib/serial/Serial.h)

and four example programs that use that library:
- seriallisten: print packets received from a serial port
- sflisten: print packets received from a serial forwarder
- prettylisten: print packets received from a serial forwarder, using
  mig-generated code to decode the standard serial-active-message header
- sfsend: send a packet (specified on the command line) to a serial forwarder

Note that sflisten prints, and sfsend sends, raw packets. In particular,
the first byte indicates the packet type (e.g., 00 for the AM-over-serial
packets). For more information on serial communication to and from motes,
see TEP113.

For more information on using ncg and mig with C, see the nescc-mig and
nescc-ncg man pages.



--- NEW FILE: autoconf.h ---
/* autoconf.h.  Generated from autoconf.h.in by configure.  */
/* autoconf.h.in.  Generated from configure.ac by autoheader.  */

/* Name of package */
#define PACKAGE "cmotesdk"

/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""

/* Define to the full name of this package. */
#define PACKAGE_NAME "cmotesdk"

/* Define to the full name and version of this package. */
#define PACKAGE_STRING "cmotesdk 1.0"

/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "cmotesdk"

/* Define to the version of this package. */
#define PACKAGE_VERSION "1.0"

/* Version number of package */
#define VERSION "1.0"

--- NEW FILE: bootstrap ---
mkdir config-aux
aclocal
autoheader
autoconf
automake -a -c

--- NEW FILE: build.xml ---
<project name="tinyos-2.x support sdk c" default="all">

	<target name="all" >
		<echo message = "Building support sdk c" />
		<exec executable="./bootstrap" failonerror="true">
		</exec>
		<exec executable="./configure" failonerror="true">
			<arg  line="--quiet" />
		</exec>
		<exec executable="make" failonerror="true">
			<arg line="all" />
		</exec>
	</target>

	<target name="install" >
		<echo message = "Installing tinyos-2.x support sdk c" />
		<exec executable="./bootstrap" failonerror="true">
		</exec>
		<exec executable="./configure" failonerror="true">
			<arg line="--prefix=$TOSTOOLS_PREFIX --quiet" />
			</exec>
		<exec executable="make" failonerror="true">
			<arg line="install" />
		</exec>
	</target>

</project>

--- NEW FILE: configure.ac ---
AC_INIT(cmotesdk, 1.0)
AC_CONFIG_SRCDIR(sfsource.c)
AM_CONFIG_HEADER(autoconf.h)
AC_CONFIG_AUX_DIR(config-aux)
AM_INIT_AUTOMAKE

AC_PROG_CC
AC_PROG_RANLIB

AC_OUTPUT(Makefile)

--- NEW FILE: message.c ---
/* Copyright (c) 2006 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */
/* Authors:  David Gay  <dgay at intel-research.net>
 *           Intel Research Berkeley Lab
 */

#include <stdlib.h>
#include "message.h"

struct tmsg {
  uint8_t *data;
  size_t len;
};

tmsg_t *new_tmsg(void *packet, size_t len)
{
  tmsg_t *x = malloc(sizeof(tmsg_t));

  if (x)
    {
      x->data = packet;
      x->len = len;
    }
  return x;
}

void free_tmsg(tmsg_t *msg)
{
  if (msg)
    free(msg);
}

void *tmsg_data(tmsg_t *msg)
{
  return msg->data;
}

size_t tmsg_length(tmsg_t *msg)
{
  return msg->len;
}

static void (*failfn)(void);

void tmsg_fail(void)
{
  if (failfn)
    failfn();
}

void (*tmsg_set_fail(void (*fn)(void)))(void)
{
  void (*oldfn)(void) = failfn;

  failfn = fn;

  return oldfn;
}

/* Check if a specified bit field is in range for a buffer, and invoke
   tmsg_fail if not. Return TRUE if in range, FALSE otherwise */
static int boundsp(tmsg_t *msg, size_t offset, size_t length)
{
  if (offset + length <= msg->len * 8)
    return 1;

  tmsg_fail();
  return 0;
}

/* Convert 2's complement 'length' bit integer 'x' from unsigned to signed
 */
static int64_t u2s(uint64_t x, size_t length)
{
  if (x & 1ULL << (length - 1))
    return (int64_t)x - (1LL << length);
  else
    return x;
}

uint64_t tmsg_read_ule(tmsg_t *msg, size_t offset, size_t length)
{
  uint64_t x = 0;

  if (boundsp(msg, offset, length))
    {
      size_t byte_offset = offset >> 3;
      size_t bit_offset = offset & 7;
      size_t shift = 0;

      /* all in one byte case */
      if (length + bit_offset <= 8)
	return (msg->data[byte_offset] >> bit_offset) & ((1 << length) - 1);

      /* get some high order bits */
      if (offset > 0)
	{
	  x = msg->data[byte_offset] >> bit_offset;
	  byte_offset++;
	  shift += 8 - bit_offset;
	  length -= 8 - bit_offset;
	}

      while (length >= 8)
	{
	  x |= (uint64_t)msg->data[byte_offset++] << shift;
	  shift += 8;
	  length -= 8;
	}

      /* data from last byte */
      if (length > 0)
	x |= (uint64_t)(msg->data[byte_offset] & ((1 << length) - 1)) << shift;
    }

  return x;
}

int64_t tmsg_read_le(tmsg_t *msg, size_t offset, size_t length)
{
  return u2s(tmsg_read_ule(msg, offset, length), length);
}

void tmsg_write_ule(tmsg_t *msg, size_t offset, size_t length, uint64_t x)
{
  if (boundsp(msg, offset, length))
    {
      size_t byte_offset = offset >> 3;
      size_t bit_offset = offset & 7;
      size_t shift = 0;

      /* all in one byte case */
      if (length + bit_offset <= 8)
	{
	  msg->data[byte_offset] = 
	    ((msg->data[byte_offset] & ~(((1 << length) - 1) << bit_offset))
	     | x << bit_offset);
	  return;
	}

      /* set some high order bits */
      if (bit_offset > 0)
	{
	  msg->data[byte_offset] =
	    ((msg->data[byte_offset] & ((1 << bit_offset) - 1)) | x << bit_offset);
	  byte_offset++;
	  shift += 8 - bit_offset;
	  length -= 8 - bit_offset;
	}

      while (length >= 8)
	{
	  msg->data[byte_offset++] = x >> shift;
	  shift += 8;
	  length -= 8;
	}

      /* data for last byte */
      if (length > 0)
	msg->data[byte_offset] = 
	  (msg->data[byte_offset] & ~((1 << length) - 1)) | x >> shift;
    }
}

void tmsg_write_le(tmsg_t *msg, size_t offset, size_t length, int64_t value)
{
  tmsg_write_ule(msg, offset, length, value);
}

uint64_t tmsg_read_ube(tmsg_t *msg, size_t offset, size_t length)
{
  uint64_t x = 0;

  if (boundsp(msg, offset, length))
    {
      size_t byte_offset = offset >> 3;
      size_t bit_offset = offset & 7;

      /* All in one byte case */
      if (length + bit_offset <= 8)
	return (msg->data[byte_offset] >> (8 - bit_offset - length)) &
	  ((1 << length) - 1);

      /* get some high order bits */
      if (bit_offset > 0)
	{
	  length -= 8 - bit_offset;
	  x = (uint64_t)(msg->data[byte_offset] & ((1 << (8 - bit_offset)) - 1)) << length;
	  byte_offset++;
	}

      while (length >= 8)
	{
	  length -= 8;
	  x |= (uint64_t)msg->data[byte_offset++] << length;
	}

      /* data from last byte */
      if (length > 0)
	x |= msg->data[byte_offset] >> (8 - length);

      return x;
    }

  return x;
}

int64_t tmsg_read_be(tmsg_t *msg, size_t offset, size_t length)
{
  return u2s(tmsg_read_ube(msg, offset, length), length);
}

void tmsg_write_ube(tmsg_t *msg, size_t offset, size_t length, uint64_t x)
{
  if (boundsp(msg, offset, length))
    {
      size_t byte_offset = offset >> 3;
      size_t bit_offset = offset & 7;

      /* all in one byte case */
      if (length + bit_offset <= 8) {
	size_t mask = ((1 << length) - 1) << (8 - bit_offset - length);

	msg->data[byte_offset] = 
	  ((msg->data[byte_offset] & ~mask) | x << (8 - bit_offset - length));
	return;
      }

      /* set some high order bits */
      if (bit_offset > 0)
	{
	  size_t mask = (1 << (8 - bit_offset)) - 1;

	  length -= 8 - bit_offset;
	  msg->data[byte_offset] = 
	    ((msg->data[byte_offset] & ~mask) | x >> length);
	  byte_offset++;
	}

      while (length >= 8)
	{
	  length -= 8;
	  msg->data[byte_offset++] = x >> length;
	}

      /* data for last byte */
      if (length > 0)
	{
	  size_t mask = (1 << (8 - length)) - 1;

	  msg->data[byte_offset] =
	    ((msg->data[byte_offset] & mask) | x << (8 - length));
	}
    }
}

void tmsg_write_be(tmsg_t *msg, size_t offset, size_t length, int64_t value)
{
  tmsg_write_ube(msg, offset, length, value);
}

/* u2f and f2u convert raw 32-bit values to/from float. This code assumes
   that the floating point rep in the uint32_t values:
     bit 31: sign, bits 30-23: exponent, bits 22-0: mantissa
   matches that of a floating point value when such a value is stored in
   memory.
*/

/* Note that C99 wants us to use the union approach rather than the
   cast-a-pointer approach... */
union f_and_u {
  uint32_t u;
  float f;
};

static float u2f(uint32_t x)
{
  union f_and_u y = { .u = x};
  return y.f;
}

static uint32_t f2u(float x)
{
  union f_and_u y = { .f = x};
  return y.u;
}

float tmsg_read_float_le(tmsg_t *msg, size_t offset)
{
  return u2f(tmsg_read_ule(msg, offset, 32));
}

void tmsg_write_float_le(tmsg_t *msg, size_t offset, float x)
{
  tmsg_write_ule(msg, offset, 32, f2u(x));
}

float tmsg_read_float_be(tmsg_t *msg, size_t offset)
{
  return u2f(tmsg_read_ube(msg, offset, 32));
}

void tmsg_write_float_be(tmsg_t *msg, size_t offset, float x)
{
  tmsg_write_ube(msg, offset, 32, f2u(x));
}

--- NEW FILE: message.h ---
/* Copyright (c) 2006 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */
/* Authors:  David Gay  <dgay at intel-research.net>
 *           Intel Research Berkeley Lab
 */
#ifndef MESSAGE_H
#define MESSAGE_H

#include <stdint.h>
#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif

/** The type of message buffers */
typedef struct tmsg tmsg_t;

/** Invoke the function set by tmsg_set_fail.
 *  tmsg_fail is called by the tmsg_read and tmsg_write functions when an
 *  out-of-buffer access is attempted.
*/
void tmsg_fail(void);

/** Set the function that tmsg_fail should call, and return the previous
 *  function. If the function is NULL, tmsg_fail does nothing.
*/
void (*tmsg_set_fail(void (*fn)(void)))(void);

/**
 * Create a message buffer from array 'packet' of 'len' bytes
 */
tmsg_t *new_tmsg(void *packet, size_t len);

/**
 * Free a message buffer. This does NOT free the underlying array.
 */
void free_tmsg(tmsg_t *msg);

/**
 * Return underlying array of a message buffer
 */
void *tmsg_data(tmsg_t *msg);

/**
 * Return length of a message buffer
 */
size_t tmsg_length(tmsg_t *msg);

/**
 * Read an unsigned little-endian integer of 'bit_length' bits from bit offset
 * 'bit_offset'
 * If the specified field is out of range for the buffer, tmsg_fail is called
 * and 0 is returned.
 */
uint64_t tmsg_read_ule(tmsg_t *msg, size_t bit_offset, size_t bit_length);

/**
 * Read a signed little-endian integer of 'bit_length' bits from bit offset
 * 'bit_offset'
 * If the specified field is out of range for the buffer, tmsg_fail is called
 * and 0 is returned.
 */
int64_t tmsg_read_le(tmsg_t *msg, size_t bit_offset, size_t bit_length);

/**
 * Write an unsigned little-endian integer of 'bit_length' bits to bit offset
 * 'bit_offset'.
 * If the specified field is out of range for the buffer, tmsg_fail is called
 * and no write occurs.
 */
void tmsg_write_ule(tmsg_t *msg, size_t bit_offset, size_t bit_length, uint64_t value);

/**
 * Write a signed little-endian integer of 'bit_length' bits to bit offset
 * 'bit_offset'.
 * If the specified field is out of range for the buffer, tmsg_fail is called
 * and no write occurs.
 */
void tmsg_write_le(tmsg_t *msg, size_t bit_offset, size_t bit_length, int64_t value);

/**
 * Read an unsigned big-endian integer of 'bit_length' bits from bit offset
 * 'bit_offset'
 * If the specified field is out of range for the buffer, tmsg_fail is called
 * and 0 is returned.
 */
uint64_t tmsg_read_ube(tmsg_t *msg, size_t bit_offset, size_t bit_length);

/**
 * Read a signed big-endian integer of 'bit_length' bits from bit offset
 * 'bit_offset'
 * If the specified field is out of range for the buffer, tmsg_fail is called
 * and 0 is returned.
 */
int64_t tmsg_read_be(tmsg_t *msg, size_t bit_offset, size_t bit_length);

/**
 * Write an unsigned big-endian integer of 'bit_length' bits to bit offset
 * 'bit_offset'.
 * If the specified field is out of range for the buffer, tmsg_fail is called
 * and no write occurs.
 */
void tmsg_write_ube(tmsg_t *msg, size_t bit_offset, size_t bit_length, uint64_t value);

/**
 * Write a signed big-endian integer of 'bit_length' bits to bit offset
 * 'bit_offset'.
 * If the specified field is out of range for the buffer, tmsg_fail is called
 * and no write occurs.
 */
void tmsg_write_be(tmsg_t *msg, size_t bit_offset, size_t bit_length, int64_t value);

/**
 * Read a 32-bit IEEE float stored in little-endian format (bit 31: sign, 
 * bits 30-23: exponent, bits 22-0: mantissa) from bit offset 'bit_offset'
 * If the specified field is out of range for the buffer, tmsg_fail is called
 * and 0 is returned.
 */
float tmsg_read_float_le(tmsg_t *msg, size_t offset);

/**
 * Write a 32-bit IEEE float in little-endian format (bit 31: sign, 
 * bits 30-23: exponent, bits 22-0: mantissa) to bit offset 'bit_offset'
 * If the specified field is out of range for the buffer, tmsg_fail is called
 * and no write occurs.
 */
void tmsg_write_float_le(tmsg_t *msg, size_t offset, float x);

/**
 * Read a 32-bit IEEE float stored in big-endian format (bit 31: sign, 
 * bits 30-23: exponent, bits 22-0: mantissa) from bit offset 'bit_offset'
 * If the specified field is out of range for the buffer, tmsg_fail is called
 * and 0 is returned.
 */
float tmsg_read_float_be(tmsg_t *msg, size_t offset);

/**
 * Write a 32-bit IEEE float in big-endian format (bit 31: sign, 
 * bits 30-23: exponent, bits 22-0: mantissa) to bit offset 'bit_offset'
 * If the specified field is out of range for the buffer, tmsg_fail is called
 * and no write occurs.
 */
void tmsg_write_float_be(tmsg_t *msg, size_t offset, float x);

#ifdef __cplusplus
}
#endif

#endif

--- NEW FILE: prettylisten.c ---
#include <stdio.h>
#include <stdlib.h>

#include "sfsource.h"
#include "serialpacket.h"
#include "serialprotocol.h"

void hexprint(uint8_t *packet, int len)
{
  int i;

  for (i = 0; i < len; i++)
    printf("%02x ", packet[i]);
}

int main(int argc, char **argv)
{
  int fd;

  if (argc != 3)
    {
      fprintf(stderr, "Usage: %s <host> <port> - dump packets from a serial forwarder\n", argv[0]);
      exit(2);
    }
  fd = open_sf_source(argv[1], atoi(argv[2]));
  if (fd < 0)
    {
      fprintf(stderr, "Couldn't open serial forwarder at %s:%s\n",
	      argv[1], argv[2]);
      exit(1);
    }
  for (;;)
    {
      int len, i;
      uint8_t *packet = read_sf_packet(fd, &len);

      if (!packet)
	exit(0);

      if (len >= 1 + SPACKET_SIZE &&
	  packet[0] == SERIAL_TOS_SERIAL_ACTIVE_MESSAGE_ID)
	{
	  tmsg_t *msg = new_tmsg(packet + 1, len - 1);

	  if (!msg)
	    exit(0);

	  printf("dest %u, src %u, length %u, group %u, type %u\n  ",
		 spacket_header_dest_get(msg),
		 spacket_header_src_get(msg),
		 spacket_header_length_get(msg),
		 spacket_header_group_get(msg),
		 spacket_header_type_get(msg));
	  hexprint((uint8_t *)tmsg_data(msg) + spacket_data_offset(0),
		   tmsg_length(msg) - spacket_data_offset(0));

	  free(msg);
	}
      else
	{
	  printf("non-AM packet: ");
	  hexprint(packet, len);
	}
      putchar('\n');
      fflush(stdout);
      free((void *)packet);
    }
}

--- NEW FILE: seriallisten.c ---
#include <stdio.h>
#include <stdlib.h>

#include "serialsource.h"

static char *msgs[] = {
  "unknown_packet_type",
  "ack_timeout"	,
  "sync"	,
  "too_long"	,
  "too_short"	,
  "bad_sync"	,
  "bad_crc"	,
  "closed"	,
  "no_memory"	,
  "unix_error"
};

void stderr_msg(serial_source_msg problem)
{
  fprintf(stderr, "Note: %s\n", msgs[problem]);
}

int main(int argc, char **argv)
{
  serial_source src;

  if (argc != 3)
    {
      fprintf(stderr, "Usage: %s <device> <rate> - dump packets from a serial port\n", argv[0]);
      exit(2);
    }
  src = open_serial_source(argv[1], platform_baud_rate(argv[2]), 0, stderr_msg);
  if (!src)
    {
      fprintf(stderr, "Couldn't open serial port at %s:%s\n",
	      argv[1], argv[2]);
      exit(1);
    }
  for (;;)
    {
      int len, i;
      const unsigned char *packet = read_serial_packet(src, &len);

      if (!packet)
	exit(0);
      for (i = 0; i < len; i++)
	printf("%02x ", packet[i]);
      putchar('\n');
      free((void *)packet);
    }
}

--- NEW FILE: serialsend.c ---
#include <stdio.h>
#include <stdlib.h>

#include "serialsource.h"

static char *msgs[] = {
  "unknown_packet_type",
  "ack_timeout"	,
  "sync"	,
  "too_long"	,
  "too_short"	,
  "bad_sync"	,
  "bad_crc"	,
  "closed"	,
  "no_memory"	,
  "unix_error"
};

void stderr_msg(serial_source_msg problem)
{
  fprintf(stderr, "Note: %s\n", msgs[problem]);
}

void send_packet(serial_source src, char **bytes, int count)
{
  int i;
  unsigned char *packet;

  packet = malloc(count);
  if (!packet)
    exit(2);

  for (i = 0; i < count; i++)
    packet[i] = strtol(bytes[i], NULL, 0);
      
  fprintf(stderr,"Sending ");
  for (i = 0; i < count; i++)
    fprintf(stderr, " %02x", packet[i]);
  fprintf(stderr, "\n");

  if (write_serial_packet(src, packet, count) == 0)
    printf("ack\n");
  else
    printf("noack\n");
}

int main(int argc, char **argv)
{
  serial_source src;

  if (argc < 3)
    {
      fprintf(stderr, "Usage: %s <device> <rate> <bytes> - send a raw packet to a serial port\n", argv[0]);
      exit(2);
    }
  src = open_serial_source(argv[1], platform_baud_rate(argv[2]), 0, stderr_msg);
  if (!src)
    {
      fprintf(stderr, "Couldn't open serial port at %s:%s\n",
	      argv[1], argv[2]);
      exit(1);
    }

  send_packet(src, argv + 3, argc - 3);
}

--- NEW FILE: serialsource.c ---
#include <sys/types.h>
#include <sys/stat.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/time.h>
#include <stdio.h>
#ifdef __CYGWIN__
#include <windows.h>
#include <io.h>
#else
#include <stdint.h>
#endif

/* C implementation of the mote serial protocol. See
   net.tinyos.packet.Packetizer for more details */

#undef DEBUG

#include "serialsource.h"
#include "serialprotocol.h"

typedef int bool;

enum {
#ifndef __CYGWIN__
  FALSE = 0,
  TRUE = 1,
#endif
  BUFSIZE = 256,
  MTU = 256,
  ACK_TIMEOUT = 1000000, /* in us */
  SYNC_BYTE = SERIAL_HDLC_FLAG_BYTE,
  ESCAPE_BYTE = SERIAL_HDLC_CTLESC_BYTE,

  P_ACK = SERIAL_SERIAL_PROTO_ACK,
  P_PACKET_ACK = SERIAL_SERIAL_PROTO_PACKET_ACK,
  P_PACKET_NO_ACK = SERIAL_SERIAL_PROTO_PACKET_NOACK,
  P_UNKNOWN = SERIAL_SERIAL_PROTO_PACKET_UNKNOWN
};

struct packet_list
{
  uint8_t *packet;
  int len;
  struct packet_list *next;
};

struct serial_source {
  int fd;
  bool non_blocking;
  void (*message)(serial_source_msg problem);

  /* Receive state */
  struct {
    uint8_t buffer[BUFSIZE];
    int bufpos, bufused;
    uint8_t packet[MTU];
    bool in_sync, escaped;
    int count;
    struct packet_list *queue[256]; // indexed by protocol
  } recv;
  struct {
    uint8_t seqno;
    uint8_t *escaped;
    int escapeptr;
    uint16_t crc;
  } send;
};

static tcflag_t parse_baudrate(int requested)
{
  int baudrate;

  switch (requested)
    {
#ifdef B50
    case 50: baudrate = B50; break;
#endif
#ifdef B75
    case 75: baudrate = B75; break;
#endif
#ifdef B110
    case 110: baudrate = B110; break;
#endif
#ifdef B134
    case 134: baudrate = B134; break;
#endif
#ifdef B150
    case 150: baudrate = B150; break;
#endif
#ifdef B200
    case 200: baudrate = B200; break;
#endif
#ifdef B300
    case 300: baudrate = B300; break;
#endif
#ifdef B600
    case 600: baudrate = B600; break;
#endif
#ifdef B1200
    case 1200: baudrate = B1200; break;
#endif
#ifdef B1800
    case 1800: baudrate = B1800; break;
#endif
#ifdef B2400
    case 2400: baudrate = B2400; break;
#endif
#ifdef B4800
    case 4800: baudrate = B4800; break;
#endif
#ifdef B9600
    case 9600: baudrate = B9600; break;
#endif
#ifdef B19200
    case 19200: baudrate = B19200; break;
#endif
#ifdef B38400
    case 38400: baudrate = B38400; break;
#endif
#ifdef B57600
    case 57600: baudrate = B57600; break;
#endif
#ifdef B115200
    case 115200: baudrate = B115200; break;
#endif
#ifdef B230400
    case 230400: baudrate = B230400; break;
#endif
#ifdef B460800
    case 460800: baudrate = B460800; break;
#endif
#ifdef B500000
    case 500000: baudrate = B500000; break;
#endif
#ifdef B576000
    case 576000: baudrate = B576000; break;
#endif
#ifdef B921600
    case 921600: baudrate = B921600; break;
#endif
#ifdef B1000000
    case 1000000: baudrate = B1000000; break;
#endif
#ifdef B1152000
    case 1152000: baudrate = B1152000; break;
#endif
#ifdef B1500000
    case 1500000: baudrate = B1500000; break;
#endif
#ifdef B2000000
    case 2000000: baudrate = B2000000; break;
#endif
#ifdef B2500000
    case 2500000: baudrate = B2500000; break;
#endif
#ifdef B3000000
    case 3000000: baudrate = B3000000; break;
#endif
#ifdef B3500000
    case 3500000: baudrate = B3500000; break;
#endif
#ifdef B4000000
    case 4000000: baudrate = B4000000; break;
#endif
    default:
      baudrate = 0;
    }
  return baudrate;
}

#ifdef DEBUG
static void dump(const char *msg, unsigned char *packet, int len)
{
  int i;

  printf("%s", msg);
  for (i = 0; i < len; i++)
    printf(" %02x", packet[i]);
  putchar('\n');
}
#endif

static void message(serial_source src, serial_source_msg msg)
{
  if (src->message)
    src->message(msg);
}

static int serial_read(serial_source src, int non_blocking, void *buffer, int n)
{
  fd_set fds;
  int cnt;

  if (non_blocking)
    {
      cnt = read(src->fd, buffer, n);

      /* Work around buggy usb serial driver (returns 0 when no data
	 is available). Mac OS X seems to like to do this too (at
	 least with a Keyspan 49WG).
      */
      if (cnt == 0)
	{
	  cnt = -1;
	  errno = EAGAIN;
	}
      return cnt;
    }
  else
    for (;;)
      {
	FD_ZERO(&fds);
	FD_SET(src->fd, &fds);
	cnt = select(src->fd + 1, &fds, NULL, NULL, NULL);
	if (cnt < 0)
	  return -1;

	cnt = read(src->fd, buffer, n);
	if (cnt != 0)
	  return cnt;
      }
}

serial_source open_serial_source(const char *device, int baud_rate,
				 int non_blocking,
				 void (*message)(serial_source_msg problem))
/* Effects: opens serial port device at specified baud_rate. If non_blocking
     is true, read_serial_packet calls will be non-blocking (writes are
     always blocking, for now at least)
   Returns: descriptor for serial forwarder at host:port, or
     NULL for failure (bad device or bad baud rate)
 */
{
  struct termios newtio;
  int fd;
  tcflag_t baudflag = parse_baudrate(baud_rate);

  if (!baudflag)
    return NULL;

  fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK);
  if (fd < 0)
    return NULL;

#ifdef __CYGWIN__
  /* For some very mysterious reason, this incantation is necessary to make
     the serial port work under some windows machines */
  HANDLE handle = (HANDLE)get_osfhandle(fd);
  DCB dcb;
  if (!(GetCommState(handle, &dcb) && SetCommState(handle, &dcb)))
    {
      close(fd);
      return NULL;
    }
#endif
  /* Serial port setting */
  memset(&newtio, 0, sizeof(newtio));
  newtio.c_cflag = CS8 | CLOCAL | CREAD;
  newtio.c_iflag = IGNPAR | IGNBRK;
  cfsetispeed(&newtio, baudflag);
  cfsetospeed(&newtio, baudflag);

  /* Raw output_file */
  newtio.c_oflag = 0;

  if (tcflush(fd, TCIFLUSH) >= 0 &&
      tcsetattr(fd, TCSANOW, &newtio) >= 0)
    {
      serial_source src = malloc(sizeof *src);

      if (src)
	{
	  memset(src, 0, sizeof *src);
	  src->fd = fd;
	  src->non_blocking = non_blocking;
	  src->message = message;
	  src->send.seqno = 37;

	  return src;
	}
    }
  close(fd);

  return NULL;
}

int serial_source_fd(serial_source src)
/* Returns: the file descriptor used by serial source src (useful when
     non-blocking reads were requested)
*/
{
  return src->fd;
}

int close_serial_source(serial_source src)
/* Effects: closes serial source src
   Returns: 0 if successful, -1 if some problem occured (but source is
     considered closed anyway)
 */
{
  int ok = close(src->fd);

  free(src);

  return ok;
}

static int source_wait(serial_source src, struct timeval *deadline)
/* Effects: waits until deadline for some data on source. deadline
     can be NULL for indefinite waiting.
   Returns: 0 if data is available, -1 if the deadline expires
*/
{
  struct timeval tv;
  fd_set fds;
  int cnt;

  if (src->recv.bufpos < src->recv.bufused)
    return 0;

  for (;;)
    {
      if (deadline)
	{
	  gettimeofday(&tv, NULL);
	  tv.tv_sec = deadline->tv_sec - tv.tv_sec;
	  tv.tv_usec = deadline->tv_usec - tv.tv_usec;
	  if (tv.tv_usec < 0)
	    {
	      tv.tv_usec += 1000000;
	      tv.tv_sec--;
	    }
	  if (tv.tv_sec < 0)
	    return -1;
	}

      FD_ZERO(&fds);
      FD_SET(src->fd, &fds);
      cnt = select(src->fd + 1, &fds, NULL, NULL, deadline ? &tv : NULL);
      if (cnt < 0)
	{
	  if (errno == EINTR)
	    continue;
	  message(src, msg_unix_error);
	  return -1;
	}
      if (cnt == 0)
	return -1;
      return 0;
    }
}

static int source_write(serial_source src, const void *buffer, int count)
{
  int actual = 0;

  if (fcntl(src->fd, F_SETFL, 0) < 0)
    {
      message(src, msg_unix_error);
      return -1;
    }
  while (count > 0)
    {
      int n = write(src->fd, buffer, count);

      if (n < 0 && errno == EINTR)
	continue;
      if (n < 0)
	{
	  message(src, msg_unix_error);
	  actual = -1;
	  break;
	}

      count -= n;
      actual += n;
      buffer += n;
    }
  if (fcntl(src->fd, F_SETFL, O_NONBLOCK) < 0)
    {
      message(src, msg_unix_error);
      /* We're in trouble, but there's no obvious fix. */
    }
  return actual;
}

static void push_protocol_packet(serial_source src,
				 uint8_t type, uint8_t *packet, uint8_t len)
{
  /* I'm assuming short queues */
  struct packet_list *entry = malloc(sizeof *entry), **last;

  if (!entry)
    {
      message(src, msg_no_memory);
      free(packet);
      return;
    }

  entry->packet = packet;
  entry->len = len;
  entry->next = NULL;

  last = &src->recv.queue[type];
  while (*last)
    last = &(*last)->next;
  *last = entry;
}

static struct packet_list *pop_protocol_packet(serial_source src, uint8_t type)
{
  struct packet_list *entry = src->recv.queue[type];

  if (entry)
    src->recv.queue[type] = entry->next;

  return entry;
}

static bool packet_available(serial_source src, uint8_t type)
{
  return src->recv.queue[type] != NULL;
}

int serial_source_empty(serial_source src)
/* Returns: true if serial source does not contain any pending data, i.e.,
     if the result is true and there is no data available on the source's
     file descriptor, then read_serial_packet will:
       - return NULL if the source is non-blocking
       - block if it is blocking

    (Note: the presence of this calls allows the serial_source to do some
    internal buffering)
*/
{
  return src->recv.bufpos >= src->recv.bufused &&
    !packet_available(src, P_PACKET_NO_ACK);
}

/* Slow implementation of crc function */
static uint16_t crc_byte(uint16_t crc, uint8_t b)
{
  uint8_t i;
  
  crc = crc ^ b << 8;
  i = 8;
  do
    if (crc & 0x8000)
      crc = crc << 1 ^ 0x1021;
    else
      crc = crc << 1;
  while (--i);

  return crc;
}

static uint16_t crc_packet(uint8_t *data, int len)
{
  uint16_t crc = 0;

  while (len-- > 0)
    crc = crc_byte(crc, *data++);

  return crc;
}

static int read_byte(serial_source src, int non_blocking)
/* Returns: next byte (>= 0), or -1 if no data available and non-blocking is true.
*/
{
  if (src->recv.bufpos >= src->recv.bufused)
    {
      for (;;)
	{
	  int n = serial_read(src, non_blocking, src->recv.buffer, sizeof src->recv.buffer);

	  if (n == 0) /* Can't occur because of serial_read bug workaround */
	    {
	      message(src, msg_closed);
	      return -1;
	    }
	  if (n > 0)
	    {
#ifdef DEBUG
	      dump("raw", src->recv.buffer, n);
#endif
	      src->recv.bufpos = 0;
	      src->recv.bufused = n;
	      break;
	    }
	  if (errno == EAGAIN)
	    return -1;
	  if (errno != EINTR)
	    message(src, msg_unix_error);
	}
    }
  //printf("in %02x\n", src->recv.buffer[src->recv.bufpos]);
  return src->recv.buffer[src->recv.bufpos++];
}

static void process_packet(serial_source src, uint8_t *packet, int len);
static int write_framed_packet(serial_source src,
			       uint8_t packet_type, uint8_t first_byte,
			       const uint8_t *packet, int count);

static void read_and_process(serial_source src, int non_blocking)
/* Effects: reads and processes up to one packet.
*/
{
  uint8_t *packet = src->recv.packet;

  for (;;)
    {
      int byte = read_byte(src, non_blocking);

      if (byte < 0)
	return;

      if (!src->recv.in_sync)
	{
	  if (byte == SYNC_BYTE)
	    {
	      src->recv.in_sync = TRUE;
	      message(src, msg_sync);
	      src->recv.count = 0;
	      src->recv.escaped = FALSE;
	    }
	  continue;
	}
      if (src->recv.count >= MTU)
	{
	  message(src, msg_too_long);
	  src->recv.in_sync = FALSE;
	  continue;
	}
      if (src->recv.escaped)
	{
	  if (byte == SYNC_BYTE)
	    {
	      /* sync byte following escape is an error, resync */
	      message(src, msg_bad_sync);
	      src->recv.in_sync = FALSE;
	      continue;
	    }
	  byte ^= 0x20;
	  src->recv.escaped = FALSE;
	}
      else if (byte == ESCAPE_BYTE)
	{
	  src->recv.escaped = TRUE;
	  continue;
	}
      else if (byte == SYNC_BYTE)
	{
	  int count = src->recv.count;
	  uint8_t *received;
	  uint16_t read_crc, computed_crc;

	  src->recv.count = 0; /* ready for next packet */

	  if (count < 4)
	    /* frames that are too small are ignored */
	    continue;

	  received = malloc(count - 2);
	  if (!received)
	    {
	      message(src, msg_no_memory);
	      continue;
	    }
	  memcpy(received, packet, count - 2);

	  read_crc = packet[count - 2] | packet[count - 1] << 8;
	  computed_crc = crc_packet(received, count - 2);

#ifdef DEBUG
	  dump("received", packet, count);
	  printf("  crc %x comp %x\n", read_crc, computed_crc);
#endif
	  if (read_crc == computed_crc) 
	    {
	      process_packet(src, received, count - 2);
	      return; /* give rest of world chance to do something */
	    }
	  else
	    {
	      message(src, msg_bad_crc);
	      free(received);
	      /* We don't lose sync here. If we did, garbage on the line
		 at startup will cause loss of the first packet. */
	      continue;
	    }
	}
      packet[src->recv.count++] = byte;
    }
}

static void process_packet(serial_source src, uint8_t *packet, int len)
{
  int packet_type = packet[0], offset = 1;

  if (packet_type == P_PACKET_ACK)
    {
      /* send ack */
      write_framed_packet(src, P_ACK, packet[1], NULL, 0);
      /* And merge with un-acked packets */
      packet_type = P_PACKET_NO_ACK;
      offset = 2;
    }
  /* packet must remain a valid pointer to pass to free. So we move the
     data rather than pass an internal pointer */
  memmove(packet, packet + offset, len - offset);
  push_protocol_packet(src, packet_type, packet, len - offset);
}

void *read_serial_packet(serial_source src, int *len)
/* Effects: Read the serial source src. If a packet is available, return it.
     If in blocking mode and no packet is available, wait for one.
   Returns: the packet read (in newly allocated memory), with *len is
     set to the packet length, or NULL if no packet is yet available and
     the serial source is in non-blocking mode
*/
{
  read_and_process(src, TRUE);
  for (;;)
    {
      struct packet_list *entry;

      entry = pop_protocol_packet(src, P_PACKET_NO_ACK);
      if (entry)
	{
	  uint8_t *packet = entry->packet;

	  *len = entry->len;
	  free(entry);

	  return packet;
	}
      if (src->non_blocking && serial_source_empty(src))
	return NULL;
      source_wait(src, NULL);
      read_and_process(src, src->non_blocking);
    }
}

/* The escaper does the sync bytes+escape-like encoding+crc of packets */

static void escape_add(serial_source src, uint8_t b)
{
  src->send.escaped[src->send.escapeptr++] = b;
}

static int init_escaper(serial_source src, int count)
{
  src->send.escaped = malloc(count * 2 + 2);
  if (!src->send.escaped)
    {
      message(src, msg_no_memory);
      return -1;
    }
  src->send.escapeptr = 0;
  src->send.crc = 0;

  escape_add(src, SYNC_BYTE);

  return 0;
}

static void terminate_escaper(serial_source src)
{
  escape_add(src, SYNC_BYTE);
}

static void escape_byte(serial_source src, uint8_t b)
{
  src->send.crc = crc_byte(src->send.crc, b);
  if (b == SYNC_BYTE || b == ESCAPE_BYTE)
    {
      escape_add(src, ESCAPE_BYTE);
      escape_add(src, b ^ 0x20);
    }
  else
    escape_add(src, b);
}

static void free_escaper(serial_source src)
{
  free(src->send.escaped);
}

// Write a packet of type 'packetType', first byte 'firstByte'
// and bytes 2..'count'+1 in 'packet'
static int write_framed_packet(serial_source src,
			       uint8_t packet_type, uint8_t first_byte,
			       const uint8_t *packet, int count)
{
  int i, crc;

#ifdef DEBUG
  printf("writing %02x %02x", packet_type, first_byte);
  dump("", packet, count);
#endif

  if (init_escaper(src, count + 4) < 0)
    return -1;
	
  escape_byte(src, packet_type);
  escape_byte(src, first_byte);
  for (i = 0; i < count; i++)
    escape_byte(src, packet[i]);

  crc = src->send.crc;
  escape_byte(src, crc & 0xff);
  escape_byte(src, crc >> 8);
  
  terminate_escaper(src);

#ifdef DEBUG
  dump("encoded", src->send.escaped, src->send.escapeptr);
#endif

  if (source_write(src, src->send.escaped, src->send.escapeptr) < 0)
    {
      free_escaper(src);
      return -1;
    }
  free_escaper(src);
  return 0;
}

static void add_timeval(struct timeval *tv, long us)
/* Specialised for this app */
{
  tv->tv_sec += us / 1000000;
  tv->tv_usec += us % 1000000;
  if (tv->tv_usec > 1000000)
    {
      tv->tv_usec -= 1000000;
      tv->tv_sec++;
    }
}

int write_serial_packet(serial_source src, const void *packet, int len)
/* Effects: writes len byte packet to serial source src
   Returns: 0 if packet successfully written, 1 if successfully written
     but not acknowledged, -1 otherwise
*/
{
  struct timeval deadline;

  src->send.seqno++;
  if (write_framed_packet(src, P_PACKET_ACK, src->send.seqno, packet, len) < 0)
    return -1;

  gettimeofday(&deadline, NULL);
  add_timeval(&deadline, ACK_TIMEOUT);
  for (;;) 
    {
      struct packet_list *entry;
      
      read_and_process(src, TRUE);
      entry = pop_protocol_packet(src, P_ACK);
      if (entry)
	{
	  uint8_t acked = entry->packet[0];

	  free(entry->packet);
	  free(entry);
	  if (acked == src->send.seqno)
	    return 0;
	}
      else if (source_wait(src, &deadline) < 0)
	return 1;
    }
}

/* This somewhat convoluted code allows us to use a common baudrate table
   with the Java code. This could be improved if we generated the Java
   code from a common table.
*/

struct pargs {
  char *name;
  int rate;
};

static void padd(struct pargs *args, const char *name, int baudrate)
{
  if (!strcmp(args->name, name))
    args->rate = baudrate;
}

static void init(void) { }

int platform_baud_rate(char *platform_name)
/* Returns: The baud rate of the specified platform, or -1 for unknown
     platforms
*/
{
  /* The Java code looks like Platform.add(Platform.x, "name", baudrate); 
     Fake up some C stuff which will make that work right. */
  struct pargs args;
  struct {
    void (*add)(struct pargs *args, const char *name, int baudrate);
    struct pargs *x;
  } Platform = { padd, &args };
  static struct {
    struct {
      int packet;
    } tinyos;
  } net;

  if (isdigit(platform_name[0]))
    return atoi(platform_name);

  args.name = platform_name;
  args.rate = -1;

#define class
#define BaudRate
#define static
#define void
#define throws ;
#define Exception
#define package
#include "../java/net/tinyos/packet/BaudRate.java"

  return args.rate;
}

--- NEW FILE: serialsource.h ---
#ifndef SERIALSOURCE_H
#define SERIALSOURCE_H

#ifdef __cplusplus
extern "C" {
#endif

typedef struct serial_source *serial_source;

typedef enum {
  msg_unknown_packet_type,	/* packet of unknown type received */
  msg_ack_timeout, 		/* ack not received within timeout */
  msg_sync,			/* sync achieved */
  msg_too_long,			/* greater than MTU (256 bytes) */
  msg_too_short,		/* less than 4 bytes */
  msg_bad_sync,			/* unexpected sync byte received */
  msg_bad_crc,			/* received packet has bad crc */
  msg_closed,			/* serial port closed itself */
  msg_no_memory,		/* malloc failed */
  msg_unix_error		/* check errno for details */
} serial_source_msg;

serial_source open_serial_source(const char *device, int baud_rate,
				 int non_blocking,
				 void (*message)(serial_source_msg problem));
/* Effects: opens serial port device at specified baud_rate. If non_blocking
     is true, read_serial_packet calls will be non-blocking (writes are
     always blocking, for now at least)
     If non-null, message will be called to signal various problems during
     execution.
   Returns: descriptor for serial forwarder at host:port, or
     NULL for failure
 */

int serial_source_fd(serial_source src);
/* Returns: the file descriptor used by serial source src (useful when
     non-blocking reads were requested)
*/

int serial_source_empty(serial_source src);
/* Returns: true if serial source does not contain any pending data, i.e.,
     if the result is true and there is no data available on the source's
     file descriptor, then read_serial_packet will:
       - return NULL if the source is non-blocking
       - block if it is blocking

    (Note: the presence of this calls allows the serial_source to do some
    internal buffering)
*/

int close_serial_source(serial_source src);
/* Effects: closes serial source src
   Returns: 0 if successful, -1 if some problem occured (but source is
     considered closed anyway)
 */

void *read_serial_packet(serial_source src, int *len);
/* Effects: Read the serial source src. If a packet is available, return it.
     If in blocking mode and no packet is available, wait for one.
   Returns: the packet read (in newly allocated memory), with *len is
     set to the packet length, or NULL if no packet is yet available and
     the serial source is in non-blocking mode
*/

int write_serial_packet(serial_source src, const void *packet, int len);
/* Effects: writes len byte packet to serial source src
   Returns: 0 if packet successfully written, 1 if successfully written
     but not acknowledged, -1 otherwise
*/

int platform_baud_rate(char *platform_name);
/* Returns: The baud rate of the specified platform, or -1 for unknown
     platforms. If platform_name starts with a digit, just return 
     atoi(platform_name).
*/

#ifdef __cplusplus
}
#endif

#endif

--- NEW FILE: sf.c ---
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>

#include "sfsource.h"
#include "serialsource.h"

serial_source src;
int server_socket;
int packets_read, packets_written, num_clients;

struct client_list
{
  struct client_list *next;
  int fd;
} *clients;

int unix_check(const char *msg, int result)
{
  if (result < 0)
    {
      perror(msg);
      exit(2);
    }

  return result;
}

void *xmalloc(size_t s)
{
  void *p = malloc(s);

  if (!p)
    {
      fprintf(stderr, "out of memory\n");
      exit(2);
    }
  return p;
}

void fd_wait(fd_set *fds, int *maxfd, int fd)
{
  if (fd > *maxfd)
    *maxfd = fd;
  FD_SET(fd, fds);
}

void pstatus(void)
{
  printf("clients %d, read %d, wrote %d\n", num_clients, packets_read,
	 packets_written);
}

void forward_packet(const void *packet, int len);


void add_client(int fd)
{
  struct client_list *c = xmalloc(sizeof *c);

  c->next = clients;
  clients = c;
  num_clients++;
  pstatus();

  c->fd = fd;
}

void rem_client(struct client_list **c)
{
  struct client_list *dead = *c;

  *c = dead->next;
  num_clients--;
  pstatus();
  close(dead->fd);
  free(dead);
}

void new_client(int fd)
{
  fcntl(fd, F_SETFL, 0);
  if (init_sf_source(fd) < 0)
    close(fd);
  else
    add_client(fd);
}

void check_clients(fd_set *fds)
{
  struct client_list **c;

  for (c = &clients; *c; )
    {
      int next = 1;

      if (FD_ISSET((*c)->fd, fds))
	{
	  int len;
	  const void *packet = read_sf_packet((*c)->fd, &len);

	  if (packet)
	    {
	      forward_packet(packet, len);
	      free((void *)packet);
	    }
	  else
	    {
	      rem_client(c);
	      next = 0;
	    }
	}
      if (next)
	c = &(*c)->next;
    }
}

void wait_clients(fd_set *fds, int *maxfd)
{
  struct client_list *c;

  for (c = clients; c; c = c->next)
    fd_wait(fds, maxfd, c->fd);
}

void dispatch_packet(const void *packet, int len)
{
  struct client_list **c;

  for (c = &clients; *c; )
    if (write_sf_packet((*c)->fd, packet, len) >= 0)
      c = &(*c)->next;
    else
      rem_client(c);
}

void open_server_socket(int port)
{
  struct sockaddr_in me;
  int opt;

  server_socket = unix_check("socket", socket(AF_INET, SOCK_STREAM, 0));
  unix_check("socket", fcntl(server_socket, F_SETFL, O_NONBLOCK));
  memset(&me, 0, sizeof me);
  me.sin_family = AF_INET;
  me.sin_port = htons(port);

  opt = 1;
  unix_check("setsockopt", setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR,
				     (char *)&opt, sizeof(opt)));
                                                                           
  unix_check("bind", bind(server_socket, (struct sockaddr *)&me, sizeof me));
  unix_check("listen", listen(server_socket, 5));
}

void check_new_client(void)
{
  int clientfd = accept(server_socket, NULL, NULL);

  if (clientfd >= 0)
    new_client(clientfd);
}





void stderr_msg(serial_source_msg problem)
{
  static char *msgs[] = {
    "unknown_packet_type",
    "ack_timeout"	,
    "sync"	,
    "too_long"	,
    "too_short"	,
    "bad_sync"	,
    "bad_crc"	,
    "closed"	,
    "no_memory"	,
    "unix_error"
  };

  fprintf(stderr, "Note: %s\n", msgs[problem]);
}

void open_serial(const char *dev, int baud)
{
    char ldev[80]; 
#ifdef __CYGWIN__
    int portnum;
    if (strncasecmp(dev, "COM", 3) == 0)
      {
	fprintf(stderr, "Warning: you're attempting to open a Windows rather that a Cygwin device.  Retrying with "); 
	portnum=atoi(dev+3);
	sprintf(ldev, "/dev/ttyS%d",portnum-1);
	fprintf(stderr,ldev);
	fprintf(stderr, "\n");
      } 
    else
#endif
    strcpy(ldev, dev); 

  src = open_serial_source(ldev, baud, 1, stderr_msg);
  if (!src)
    {
      fprintf(stderr, "Couldn't open serial port at %s:%d\n", dev, baud);
      exit(1);
    }
}

void check_serial(void)
{
  int len;
  const unsigned char *packet = read_serial_packet(src, &len);

  if (packet)
    {
      packets_read++;
      dispatch_packet(packet, len);
      free((void *)packet);
    }
}

void forward_packet(const void *packet, int len)
{
  int ok = write_serial_packet(src, packet, len);

  packets_written++;
  if (ok < 0)
    exit(2);
  if (ok > 0)
    fprintf(stderr, "Note: write failed\n");
}

int main(int argc, char **argv)
{
  int serfd;

  if (argc != 4)
    {
      fprintf(stderr,
	      "Usage: %s <port> <device> <rate> - act as a serial forwarder on <port>\n"
	      "(listens to serial port <device> at baud rate <rate>)\n" ,
	      argv[0]);
      exit(2);
    }

  if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
    fprintf(stderr, "Warning: failed to ignore SIGPIPE.\n");

  open_serial(argv[2], platform_baud_rate(argv[3]));
  serfd = serial_source_fd(src);
  open_server_socket(atoi(argv[1]));

  for (;;)
    {
      fd_set rfds;
      int maxfd = -1;
      struct timeval zero;
      int serial_empty;
      int ret;

      zero.tv_sec = zero.tv_usec = 0;

      FD_ZERO(&rfds);
      fd_wait(&rfds, &maxfd, serfd);
      fd_wait(&rfds, &maxfd, server_socket);
      wait_clients(&rfds, &maxfd);

      serial_empty = serial_source_empty(src);
      if (serial_empty)
	ret = select(maxfd + 1, &rfds, NULL, NULL, NULL);
      else
	{
	  ret = select(maxfd + 1, &rfds, NULL, NULL, &zero);
	  check_serial();
	}
      if (ret >= 0)
	{
	  if (FD_ISSET(serfd, &rfds))
	    check_serial();

	  if (FD_ISSET(server_socket, &rfds))
	    check_new_client();

	  check_clients(&rfds);
	}
    }
}

--- NEW FILE: sflisten.c ---
#include <stdio.h>
#include <stdlib.h>

#include "sfsource.h"

int main(int argc, char **argv)
{
  int fd;

  if (argc != 3)
    {
      fprintf(stderr, "Usage: %s <host> <port> - dump packets from a serial forwarder\n", argv[0]);
      exit(2);
    }
  fd = open_sf_source(argv[1], atoi(argv[2]));
  if (fd < 0)
    {
      fprintf(stderr, "Couldn't open serial forwarder at %s:%s\n",
	      argv[1], argv[2]);
      exit(1);
    }
  for (;;)
    {
      int len, i;
      const unsigned char *packet = read_sf_packet(fd, &len);

      if (!packet)
	exit(0);
      for (i = 0; i < len; i++)
	printf("%02x ", packet[i]);
      putchar('\n');
      fflush(stdout);
      free((void *)packet);
    }
}

--- NEW FILE: sfsend.c ---
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "sfsource.h"

void send_packet(int fd, char **bytes, int count)
{
  int i;
  unsigned char *packet;

  packet = malloc(count);
  if (!packet)
    exit(2);

  for (i = 0; i < count; i++)
    packet[i] = strtol(bytes[i], NULL, 0);
      
  fprintf(stderr,"Sending ");
  for (i = 0; i < count; i++)
    fprintf(stderr, " %02x", packet[i]);
  fprintf(stderr, "\n");

  write_sf_packet(fd, packet, count);
}

int main(int argc, char **argv)
{
  int fd;

  if (argc < 4)
    {
      fprintf(stderr, "Usage: %s <host> <port> <bytes> - send a raw packet to a serial forwarder\n", argv[0]);
      exit(2);
    }
  fd = open_sf_source(argv[1], atoi(argv[2]));
  if (fd < 0)
    {
      fprintf(stderr, "Couldn't open serial forwarder at %s:%s\n",
	      argv[1], argv[2]);
      exit(1);
    }

  send_packet(fd, argv + 3, argc - 3);

  close(fd);
}

--- NEW FILE: sfsource.c ---
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

#include "sfsource.h"

int saferead(int fd, void *buffer, int count)
{
  int actual = 0;

  while (count > 0)
    {
      int n = read(fd, buffer, count);

      if (n == -1 && errno == EINTR)
	continue;
      if (n == -1)
	return -1;
      if (n == 0)
	return actual;

      count -= n;
      actual += n;
      buffer = (char*)buffer + n;
    }
  return actual;
}

int safewrite(int fd, const void *buffer, int count)
{
  int actual = 0;

  while (count > 0)
    {
      int n = write(fd, buffer, count);

      if (n == -1 && errno == EINTR)
	continue;
      if (n == -1)
	return -1;

      count -= n;
      actual += n;
      buffer = (char*)buffer + n;
    }
  return actual;
}

int open_sf_source(const char *host, int port)
/* Returns: file descriptor for serial forwarder at host:port
 */
{
  int fd = socket(AF_INET, SOCK_STREAM, 0);
  struct hostent *entry;
  struct sockaddr_in addr;

  if (fd < 0)
    return fd;

  entry = gethostbyname(host);
  if (!entry)
    {
      close(fd);
      return -1;
    }      

  addr.sin_family = entry->h_addrtype;
  memcpy(&addr.sin_addr, entry->h_addr, entry->h_length);
  addr.sin_port = htons(port);
  if (connect(fd, (struct sockaddr *)&addr, sizeof addr) < 0)
    {
      close(fd);
      return -1;
    }

  if (init_sf_source(fd) < 0)
    {
      close(fd);
      return -1;
    }

  return fd;
}

int init_sf_source(int fd)
/* Effects: Checks that fd is following the TinyOS 2.0 serial forwarder 
     protocol. Use this if you obtain your file descriptor from some other
     source than open_sf_source (e.g., you're a server)
   Returns: 0 if it is, -1 otherwise
 */
{
  char check[2], us[2];
  int version;

  /* Indicate version and check if a TinyOS 2.0 serial forwarder on the
     other end */
  us[0] = 'U'; us[1] = ' ';
  if (safewrite(fd, us, 2) != 2 ||
      saferead(fd, check, 2) != 2 ||
      check[0] != 'U')
    return -1;

  version = check[1];
  if (us[1] < version)
    version = us[1];

  /* Add other cases here for later protocol versions */
  switch (version)
    {
    case ' ': break;
    default: return -1; /* not a valid version */
    }

  return 0;
}

void *read_sf_packet(int fd, int *len)
/* Effects: reads packet from serial forwarder on file descriptor fd
   Returns: the packet read (in newly allocated memory), and *len is
     set to the packet length, or NULL for failure
*/
{
  unsigned char l;
  void *packet;

  if (saferead(fd, &l, 1) != 1)
    return NULL;

  packet = malloc(l);
  if (!packet)
    return NULL;

  if (saferead(fd, packet, l) != l)
    {
      free(packet);
      return NULL;
    }
  *len = l;
  
  return packet;
}

int write_sf_packet(int fd, const void *packet, int len)
/* Effects: writes len byte packet to serial forwarder on file descriptor
     fd
   Returns: 0 if packet successfully written, -1 otherwise
*/
{
  unsigned char l = len;

  if (safewrite(fd, &l, 1) != 1 ||
      safewrite(fd, packet, l) != l)
    return -1;

  return 0;
}

--- NEW FILE: sfsource.h ---
#ifndef SFSOURCE_H
#define SFSOURCE_H

#ifdef __cplusplus
extern "C" {
#endif

int open_sf_source(const char *host, int port);
/* Returns: file descriptor for TinyOS 2.0 serial forwarder at host:port, or
     -1 for failure
 */

int init_sf_source(int fd);
/* Effects: Checks that fd is following the TinyOS 2.0 serial forwarder 
     protocol. Use this if you obtain your file descriptor from some other
     source than open_sf_source (e.g., you're a server)
   Returns: 0 if it is, -1 otherwise
 */

void *read_sf_packet(int fd, int *len);
/* Effects: reads packet from serial forwarder on file descriptor fd
   Returns: the packet read (in newly allocated memory), and *len is
     set to the packet length
*/

int write_sf_packet(int fd, const void *packet, int len);
/* Effects: writes len byte packet to serial forwarder on file descriptor
     fd
   Returns: 0 if packet successfully written, -1 otherwise
*/

#ifdef __cplusplus
}
#endif

#endif



More information about the Tinyos-2-commits mailing list