[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
- Previous message: [Tinyos-2-commits] CVS: tinyos-2.x/support/sdk/c/sf - New directory
- Next message: [Tinyos-2-commits] CVS: tinyos-2.x/support/sdk/c Makefile.am, 1.3,
NONE README, 1.2, NONE autoconf.h, 1.3, NONE bootstrap, 1.2,
NONE build.xml, 1.4, NONE configure.ac, 1.2, NONE message.c,
1.2, NONE message.h, 1.3, NONE prettylisten.c, 1.3,
NONE seriallisten.c, 1.2, NONE serialsend.c, 1.1,
NONE serialsource.c, 1.5, NONE serialsource.h, 1.3, NONE sf.c,
1.3, NONE sflisten.c, 1.2, NONE sfsend.c, 1.2, NONE sfsource.c,
1.3, NONE sfsource.h, 1.3, NONE
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
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
- Previous message: [Tinyos-2-commits] CVS: tinyos-2.x/support/sdk/c/sf - New directory
- Next message: [Tinyos-2-commits] CVS: tinyos-2.x/support/sdk/c Makefile.am, 1.3,
NONE README, 1.2, NONE autoconf.h, 1.3, NONE bootstrap, 1.2,
NONE build.xml, 1.4, NONE configure.ac, 1.2, NONE message.c,
1.2, NONE message.h, 1.3, NONE prettylisten.c, 1.3,
NONE seriallisten.c, 1.2, NONE serialsend.c, 1.1,
NONE serialsource.c, 1.5, NONE serialsource.h, 1.3, NONE sf.c,
1.3, NONE sflisten.c, 1.2, NONE sfsend.c, 1.2, NONE sfsource.c,
1.3, NONE sfsource.h, 1.3, NONE
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the Tinyos-2-commits
mailing list