]> oss.titaniummirror.com Git - tinyos-2.x.git/commitdiff
moving from sdk/c
authorgnawali <gnawali>
Wed, 5 Dec 2007 22:49:45 +0000 (22:49 +0000)
committergnawali <gnawali>
Wed, 5 Dec 2007 22:49:45 +0000 (22:49 +0000)
18 files changed:
support/sdk/c/sf/Makefile.am [new file with mode: 0644]
support/sdk/c/sf/README [new file with mode: 0644]
support/sdk/c/sf/autoconf.h [new file with mode: 0644]
support/sdk/c/sf/bootstrap [new file with mode: 0755]
support/sdk/c/sf/build.xml [new file with mode: 0644]
support/sdk/c/sf/configure.ac [new file with mode: 0644]
support/sdk/c/sf/message.c [new file with mode: 0644]
support/sdk/c/sf/message.h [new file with mode: 0644]
support/sdk/c/sf/prettylisten.c [new file with mode: 0644]
support/sdk/c/sf/seriallisten.c [new file with mode: 0644]
support/sdk/c/sf/serialsend.c [new file with mode: 0644]
support/sdk/c/sf/serialsource.c [new file with mode: 0644]
support/sdk/c/sf/serialsource.h [new file with mode: 0644]
support/sdk/c/sf/sf.c [new file with mode: 0644]
support/sdk/c/sf/sflisten.c [new file with mode: 0644]
support/sdk/c/sf/sfsend.c [new file with mode: 0644]
support/sdk/c/sf/sfsource.c [new file with mode: 0644]
support/sdk/c/sf/sfsource.h [new file with mode: 0644]

diff --git a/support/sdk/c/sf/Makefile.am b/support/sdk/c/sf/Makefile.am
new file mode 100644 (file)
index 0000000..b26b805
--- /dev/null
@@ -0,0 +1,40 @@
+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
diff --git a/support/sdk/c/sf/README b/support/sdk/c/sf/README
new file mode 100644 (file)
index 0000000..100865c
--- /dev/null
@@ -0,0 +1,51 @@
+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.
+
+
diff --git a/support/sdk/c/sf/autoconf.h b/support/sdk/c/sf/autoconf.h
new file mode 100644 (file)
index 0000000..8285508
--- /dev/null
@@ -0,0 +1,23 @@
+/* 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"
diff --git a/support/sdk/c/sf/bootstrap b/support/sdk/c/sf/bootstrap
new file mode 100755 (executable)
index 0000000..f35ba82
--- /dev/null
@@ -0,0 +1,5 @@
+mkdir config-aux
+aclocal
+autoheader
+autoconf
+automake -a -c
diff --git a/support/sdk/c/sf/build.xml b/support/sdk/c/sf/build.xml
new file mode 100644 (file)
index 0000000..b966962
--- /dev/null
@@ -0,0 +1,27 @@
+<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>
diff --git a/support/sdk/c/sf/configure.ac b/support/sdk/c/sf/configure.ac
new file mode 100644 (file)
index 0000000..c064fd6
--- /dev/null
@@ -0,0 +1,10 @@
+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)
diff --git a/support/sdk/c/sf/message.c b/support/sdk/c/sf/message.c
new file mode 100644 (file)
index 0000000..9739c15
--- /dev/null
@@ -0,0 +1,312 @@
+/* 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@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));
+}
diff --git a/support/sdk/c/sf/message.h b/support/sdk/c/sf/message.h
new file mode 100644 (file)
index 0000000..8655f7b
--- /dev/null
@@ -0,0 +1,156 @@
+/* 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@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
diff --git a/support/sdk/c/sf/prettylisten.c b/support/sdk/c/sf/prettylisten.c
new file mode 100644 (file)
index 0000000..4a24f7d
--- /dev/null
@@ -0,0 +1,68 @@
+#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);
+    }
+}
diff --git a/support/sdk/c/sf/seriallisten.c b/support/sdk/c/sf/seriallisten.c
new file mode 100644 (file)
index 0000000..f7d5aeb
--- /dev/null
@@ -0,0 +1,52 @@
+#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);
+    }
+}
diff --git a/support/sdk/c/sf/serialsend.c b/support/sdk/c/sf/serialsend.c
new file mode 100644 (file)
index 0000000..7735f36
--- /dev/null
@@ -0,0 +1,65 @@
+#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);
+}
diff --git a/support/sdk/c/sf/serialsource.c b/support/sdk/c/sf/serialsource.c
new file mode 100644 (file)
index 0000000..4e4afab
--- /dev/null
@@ -0,0 +1,835 @@
+#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;
+}
diff --git a/support/sdk/c/sf/serialsource.h b/support/sdk/c/sf/serialsource.h
new file mode 100644 (file)
index 0000000..28ba5bd
--- /dev/null
@@ -0,0 +1,81 @@
+#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
diff --git a/support/sdk/c/sf/sf.c b/support/sdk/c/sf/sf.c
new file mode 100644 (file)
index 0000000..ada9bc5
--- /dev/null
@@ -0,0 +1,297 @@
+#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);
+       }
+    }
+}
diff --git a/support/sdk/c/sf/sflisten.c b/support/sdk/c/sf/sflisten.c
new file mode 100644 (file)
index 0000000..845780c
--- /dev/null
@@ -0,0 +1,35 @@
+#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);
+    }
+}
diff --git a/support/sdk/c/sf/sfsend.c b/support/sdk/c/sf/sfsend.c
new file mode 100644 (file)
index 0000000..7304315
--- /dev/null
@@ -0,0 +1,47 @@
+#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);
+}
diff --git a/support/sdk/c/sf/sfsource.c b/support/sdk/c/sf/sfsource.c
new file mode 100644 (file)
index 0000000..24df960
--- /dev/null
@@ -0,0 +1,161 @@
+#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;
+}
diff --git a/support/sdk/c/sf/sfsource.h b/support/sdk/c/sf/sfsource.h
new file mode 100644 (file)
index 0000000..b6c2b92
--- /dev/null
@@ -0,0 +1,36 @@
+#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