[Tinyos] genc.pm and genpgsql.pm

doolin at ce.berkeley.edu doolin at ce.berkeley.edu
Mon Aug 1 13:33:51 PDT 2005


Some perl scripts for using mig to generate c and
postgres code are attached.  They are derived from
genjava.pm.  Comments welcome.
-dmd


-------------- next part --------------
# This file is part of the nesC compiler.
#    Copyright (C) 2002 Intel Corporation
# 
# The attached "nesC" software is provided to you under the terms and
# conditions of the GNU General Public License Version 2 as published by the
# Free Software Foundation.
# 
# nesC is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with nesC; see the file COPYING.  If not, write to
# the Free Software Foundation, 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.


## TODO for autogenerating C code.
## ----------------------------------------------------------
## Several things need to be done to make this viable for the
## kinds of messages we want to process.  The first part is
## to get rid of the java type conversions, and preserve the
## structure as defined the tinyos header file.  We can do this
## because nesc native types are identical to c native types.
##

## Parts of this code were written for the NSF_ITR funded 
## firebug project.
##
## Code based on genjava.pm written by David Gay (?)
## authors David Gay (? + others?),  Dave Doolin


true;




sub gen() {

  my %struct_hash;

  my ($tmp,$fmtstr);

  my ($classname, @spec) = @_;

  require migdecode;
  &decode(@spec);

  &usage("no classname name specified") if !defined($java_classname);

  $java_extends = "net.tinyos.message.Message" if !defined($java_extends);
  # See if name has a package specifier
  if ($java_classname =~ /(.*)\.([^.]*)$/) {
    $package = $1;
    $java_classname = $2;
    $structname = $java_classname."P";
  }

  $I = "   ";
  $smallskip = "\n\n";
  $medskip   = "\n\n\n\n";
  $bigskip   = "\n\n\n\n\n\n";


  print "/**\n";
  print " * This class is automatically generated by mig. DO NOT EDIT THIS FILE.\n";
  print " * This code implements C interface to the '$structname'\n";
  print " * message type.\n";
  print " */\n\n";

  print "#include <stdio.h>\n";
  print "#include <stdlib.h>\n";
  print "#include <memory.h>\n";

  print $medskip;

  print "/** Private header is programmer specified for handling\n";
  print " * conversion functions, etc.\n */\n";
  print "//#include \"$structname\_private.h\"\n";

  print "/** Not the best way to handle xbow dependencies. */\n";
  print "#ifdef TELOS_MOTE\n";
  print "#include \"../xdb.h\"\n";
  print "#include \"../xsensors.h\"\n";
  print "#endif\n";

  print $medskip;

  print "/** These need to be moved to a header file. */\n";
  print "typedef struct _$structname $structname;\n";
  print "#ifndef TELOS_MOTE\n";
  print "typedef struct _XbowSensorboardPacket XbowSensorboardPacket;\n";
  print "#endif\n";

  print $medskip

  print "/** The Active Message type associated with this message. */\n";
  print "//static const int AM_TYPE = $amtype;\n\n";
  print "//#define AM_TYPE $amtype\n\n";

  print $smallskip;

  print "// This struct is defined to keep gcc happy while the module\n";
  print "// is under development.  At some point in the near future, a\n";
  print "// a convention for passing arguments into the functions will\n";
  print "// have to be defined.\n";
  print "struct _XbowSensorboardPacket {\n";
  print "  unsigned char data[29];\n";
  print "};\n";

  print $medskip;

  #    print "struct _$structname {\n";
  #    for (@fields) {
  #	($field, $type, $bitlength, $offset, $amax, $abitsize, $aoffset) = @{$_};
  #        ($ctype, $java_access, $arrayspec) = &cbasetype($type, $bitlength, 0);
  #        if ($field =~ /(.*)\.([^.]*)$/) {
  #	   $struct = $1;
  #	   $member = $2;
  #        }
  #        push(@format, &formatstring($type, $bitlength, 0));
  #	$field =~  s/\./_/g;
  #	printf "$I$ctype $field;\n";
  #      }
  #    print "};";



  print $medskip;


  &gen_struct();
  print $medskip;

  &gen_get_set();
  print $medskip;

  print "//Format string generated automatically,\n";
  $tmp = @format[$#format-1];
  $tmp =~ s/,//g;
  $fmtstr = "@format[0..($#format-1)] $tmp";
  #print "Fmt: $fmtstr\n";
  print "//static char formatstring[] = \"@format[0..($#format-1)] $tmp\";\n\n\n";
  print "//static char formatstring[] = \"$fmtstr\";\n\n\n";

  &gen_insert_stmt($fmtstr);
  print $medskip;

  ## Default behavior is to return the input as output.
  ## User is responsible for "cooking" the data.
  for (@fields) {
    ($field, $type, $bitlength, $offset, $amax, $abitsize, $aoffset) = @{$_};
    ($ctype, $java_access, $arrayspec) = &cbasetype($type, $bitlength, 0);
    $field =~ s/\./_/g;
    print "/** \@brief Default behavior is to return the input as output.\n";
    print " *  User is responsible for \"cooking\" the data.\n */\n";
    print "static $ctype\n";
    print "$field\_convert($ctype $field) {\n";
    print "   return $field;\n";
    print "}\n\n";
  }



  ## Function for cooking whole packet.  Fields are
  ## by calling the individual "cook" functions for
  ## each member.
  print "void\n";
  print "$structname\_cook\_packet($structname * userdata) {\n";
  for (@fields) {
    ($field, $type, $bitlength, $offset, $amax, $abitsize, $aoffset) = @{$_};
    ($ctype, $java_access, $arrayspec) = &cbasetype($type, $bitlength, 0);
    $field =~ s/\./_/g;
    print "   userdata->$field = $field\_convert(userdata->$field);\n";
  }
  print "}\n\n";


  print $medskip;


  ## In the code for the xlisten boards, the conversions are
  ## in the print statement.  If the conversions were done
  ## before the print statement, then the conversion function
  ## becomes the only function needing to be stubbed.  The
  ## runtime differences are neglible.

  print "/** User has to fill in any conversion code\n";
  print " * necessary for processing.\n";
  print " */\n";
  print "$structname *\n $structname\_convert(char * data) {\n";
  print "   // Just to keep gcc happy.\n";
  print "   return ($structname*)data;\n";
  print "}\n";

  print $medskip;

  ##  Start printing output functions.

  &gen_byte_output();
  &gen_cooked_output();
  #&gen_cooked_with_tabs();

  &gen_handler_table();


  #    print "package $package;\n\n" if $package;

  #    print "public class $structname extends $java_extends {\n\n";

  print "/** The default size of this message type in bytes. */\n";
  print "//static int DEFAULT_MESSAGE_SIZE = $size;\n\n";


  print "/** If incomplete types are used, we need to provide a way\n";
  print " * to manage memory.\n";
  print " */\n";
  print "$structname *\n";
  print "$structname\_new() {\n";
  print "   $structname * userdata = ($structname*)malloc(sizeof($structname));\n";
  print "   memset((void*)userdata,0xda,sizeof($structname));\n";
  print "   return userdata;\n";
  print "}\n";

  print $medskip;


  print "void\n";
  print "$structname\_delete($structname * userdata) {\n";
  print "   memset((void*)userdata,0xdd,sizeof($structname));\n";
  print "   free(userdata);\n";
  print "}\n";

}



sub gen_insert_stmt ()  {

my($fmtstr1) = $_[0];
my($fmtstr);

my ($tmp,$fmtstr);

  $i = 0;
  $numfields = $#fields;

  print "static char insert_stmt[] = \"INSERT into $structname (\"\n";

  for (@fields) {
    ($field, $type, $bitlength, $offset, $amax, $abitsize, $aoffset) = @{$_};
    ($ctype, $java_access, $arrayspec) = &cbasetype($type, $bitlength, 0);

    # This is clunky but will work. A better way to do it would be to store
    # the nested struct internally in the field array somehow.
    # Maybe a perl guru can figure that out.
    # What needs to be done is to find one of these, then
    # store it until all the members written out,
    # then print it.
    if ($field =~ /(.*)\.([^.]*)$/) {
      $struct = $1;
      $member = $2;
      #print STDERR $struct;#.", "$member."\n";
    }

    ##  Gets an array of format specifiers useful in *print* functions
    ## in libc.  the @format array can be passed
    #push(@format, &formatstring($type, $bitlength, 0));
    $field =~  s/\./_/g;

    if ($i < $numfields) {
      printf "\"$field,\"\n";
    } else {
      printf "\"$field) values (";
    }

    $i++;
  }

  $tmp = @format[$#format-1];
  $tmp =~ s/,//g;
  $fmtstr = "@format[0..($#format-1)] $tmp";
  print "$fmtstr)\";\n\n\n";


  &gen_struct_array();



  print "void\n$structname\_pg\_log(XbowSensorboardPacket * userdata) {\n";
  print "char pg_command[255];\n";
  print "$structname * data = ($structname*)userdata;\n";
  print "sprintf(pg_command,insert_stmt,\n";
  # traverse struct here.
  $i = 0;
  for (@fields) {
    ($field, $type, $bitlength, $offset, $amax, $abitsize, $aoffset) = @{$_};
    ($ctype, $java_access, $arrayspec) = &cbasetype($type, $bitlength, 0);

    # This is clunky but will work. A better way to do it would be to store
    # the nested struct internally in the field array somehow.
    # Maybe a perl guru can figure that out.
    # What needs to be done is to find one of these, then
    # store it until all the members written out,
    # then print it.
    if ($field =~ /(.*)\.([^.]*)$/) {
      $struct = $1;
      $member = $2;
      #print STDERR $struct;#.", "$member."\n";
    }

    ##  Gets an array of format specifiers useful in *print* functions
    ## in libc.  the @format array can be passed
    push(@format, &formatstring($type, $bitlength, 0));
    $field =~  s/\./_/g;

    if ($i < $numfields) {
	    print "data->$field,\n"
    } else {
	    print "data->$field);\n";
    }
    $i++;
  }

  print "#ifdef TELOS_MOTE\n";
  print "xdb_execute(pg_command);\n";
  print "#endif\n";

  print "}\n";

}



sub gen_cooked_with_tabs() {

  print "/** Print cooked with tabs. */\n";
  print "void\n$structname\_print\_tabbed (XbowSensorboardPacket *packet) {\n\n";
  print "$I$structname * userdata = ($structname*)packet->data;\n";
  print "}\n\n";
}


sub gen_byte_output() {
  
  print "/** Print the bytes of the packet. */\n";
  print "void\n$structname\_print\_raw (XbowSensorboardPacket *packet) {\n\n";
  #    print "$I$structname * userdata = ($structname*)packet->data;\n";
  print "   printf(\"$structname print raw.\\n\");\n";
  print "}\n\n";
}


sub gen_handler_table() {

  print "#ifdef TELOS_MOTE\n";

  print "XPacketHandler $structname\_packet\_handler = {\n";
  print "// This should be replaced with the AM_TYPE\n";
  print "  $amtype,\n";
  print "  \"\$Id: \$\",\n";
  print "  $structname\_print\_raw,\n";
  print "  $structname\_print\_cooked,\n";
  print "  $structname\_print\_raw,\n";
  print "  $structname\_print\_cooked,\n";
  print "  $structname\_pg\_log,\n";
  print "  {0}\n";
  print "};\n\n\n";

###  Add handler table to xlisten.
  print "void\n$structname\_initialize() {\n";
  print "xpacket_add_type(&$structname\_packet\_handler);\n";
  print "}\n";

  print "#endif\n";

}

sub gen_cooked_output() {

  print "/** Print cooked output. */\n";
  print "void\n$structname\_print\_cooked (XbowSensorboardPacket * userdata) {\n\n";
  print "$I$structname * data = ($structname*)userdata;\n";

  print "   printf(\"$structname print cooked:\\n\");\n";

  for (@fields) {
    ($field, $type, $bitlength, $offset, $amax, $abitsize, $aoffset) = @{$_};
    ($ctype, $java_access, $arrayspec) = &cbasetype($type, $bitlength, 0);
    if ($field =~ /(.*)\.([^.]*)$/) {
      $struct = $1;
      $member = $2;
      #print STDERR $struct;#.", "$member."\n";
    }
    ##  Gets an array of format specifiers useful in *print* functions
    ## in libc.  the @format array can be passed
    #push(@format, &formatstring($type, $bitlength, 0));
    $field =~  s/\./_/g;
    print "   printf(\"$I$field: ".&formatstring($type, $bitlength, 0)."\\n\",data->$field);\n";
  }



  print "}\n\n";

}




sub gen_struct() {

  print "struct _$structname {\n";

  ## todo move this to sub print_msg_struct().
  for (@fields) {
    ($field, $type, $bitlength, $offset, $amax, $abitsize, $aoffset) = @{$_};

    ($ctype, $java_access, $arrayspec) = &cbasetype($type, $bitlength, 0);

    # This is clunky but will work. A better way to do it would be to store
    # the nested struct internally in the field array somehow.
    # Maybe a perl guru can figure that out.
    # What needs to be done is to find one of these, then
    # store it until all the members written out,
    # then print it.
    if ($field =~ /(.*)\.([^.]*)$/) {
      $struct = $1;
      $member = $2;
      #print STDERR $struct;#.", "$member."\n";
    }

    ##  Gets an array of format specifiers useful in *print* functions
    ## in libc.  the @format array can be passed
    push(@format, &formatstring($type, $bitlength, 0));
    $field =~  s/\./_/g;
    printf "$I$ctype $field;\n";
  }
  print "};";
}


sub gen_struct_array() {

  for (@fields) {
    ($field, $type, $bitlength, $offset, $amax, $abitsize, $aoffset) = @{$_};

    ($ctype, $java_access, $arrayspec) = &cbasetype($type, $bitlength, 0);

    # This is clunky but will work. A better way to do it would be to store
    # the nested struct internally in the field array somehow.
    # Maybe a perl guru can figure that out.
    # What needs to be done is to find one of these, then
    # store it until all the members written out,
    # then print it.
    if ($field =~ /(.*)\.([^.]*)$/) {
      $struct = $1;
      $member = $2;
      #print STDERR $struct;#.", "$member."\n";
    }

    ##  Gets an array of format specifiers useful in *print* functions
    ## in libc.  the @format array can be passed
    push(@format, &formatstring($type, $bitlength, 0));
    $field =~  s/\./_/g;
    $struct_hash{$field} = $ctype;
  }

}


sub gen_get_set() {

  ## The get/set code is more to investigate the mechanics of
  ## the autogeneration of structs.  It's probably more useful
  ## use the defined type directly, at least for now.
  ##
  ## todo move this to sub_get_set_methods()
  for (@fields) {
    ($field, $type, $bitlength, $offset, $amax, $abitsize, $aoffset) = @{$_};
    ($ctype, $java_access, $arrayspec) = &cbasetype($type, $bitlength, 0);
    $field =~ s/\./_/g;
    print "void\n";
    print "$structname\_set\_$field($structname * userdata, $ctype $field) {\n";
    print "   userdata->$field = $field;\n";
    print "}\n\n";
    ####  Get methods
    print "$ctype\n";
    print "$structname\_get\_$field($structname * userdata) {\n";
    print "   return userdata->$field;\n";
    print "}\n\n";
  }
}



## TODO Change all these back to the base types available in c, which are
## the same as in nesc.  Probably need to add a "bitfield" handler to 
## do it right.
sub cbasetype() {

  my ($basetype, $bitlength, $arraydims) = @_;
  my $jtype, $acc;

  # Pick the java type whose range is closest to the corresponding C type
  if ($basetype eq "U") {
    $acc = "UIntElement";
    if ($bitlength < 8) {
      $jtype = "unsigned char";
    } elsif ($bitlength < 16) {
      $jtype = "uint8_t";
    } elsif ($bitlength < 32) {
      $jtype = "uint16_t";
    } else {
      $jtype = "uint32_t";
    }
  } elsif ($basetype eq "I") {
    $acc = "SIntElement";
    if ($bitlength <= 8) {
      $jtype = "char";
    } elsif ($bitlength <= 16) {
      $jtype = "short";
    } elsif ($bitlength <= 32) {
      $jtype = "int";
    } else {
      $jtype = "long";
    }
  } elsif ($basetype eq "F" || $basetype eq "D" || $basetype eq "LD") {
    $acc = "FloatElement";
    $jtype = "float";
  }

  if ($arraydims > 0) {
    # For array types
    $arrayspec = "";
    for ($i = 0; $i < $arraydims; $i++) {
      $arrayspec = "[]" . $arrayspec;
    }
  } 

  return ($jtype, $acc, $arrayspec);
}



## TODO Get rid of all the superfluous code, 
## or move the functionality into cbasetype.
sub formatstring() 
  {
    my ($basetype, $bitlength, $arraydims) = @_;
    my $jtype, $acc, $formatstring;

    # Pick the java type whose range is closest to the corresponding C type
    if ($basetype eq "U") {
      $acc = "UIntElement";
      if ($bitlength < 8) {
	$jtype = "byte"; $formatstring = "%c,";
      } elsif ($bitlength < 16) {
	$jtype = "short"; $formatstring = "%i,";
      } elsif ($bitlength < 32) {
	$jtype = "int"; $formatstring = "%i,";
      } else {
	$jtype = "long"; $formatstring = "%i,";
      }
    } elsif ($basetype eq "I") {
      $acc = "SIntElement";
      if ($bitlength <= 8) {
	$jtype = "byte"; $formatstring = "%c,";
      } elsif ($bitlength <= 16) {
	$jtype = "short"; $formatstring = "%i,";
      } elsif ($bitlength <= 32) {
	$jtype = "int"; $formatstring = "%i,";
      } else {
	$jtype = "long";
      }
    } elsif ($basetype eq "F" || $basetype eq "D" || $basetype eq "LD") {
      $acc = "FloatElement";
      $jtype = "float";
      $formatstring = "f";
    }

    if ($arraydims > 0) {
      # For array types
      $arrayspec = "";
      for ($i = 0; $i < $arraydims; $i++) {
	$arrayspec = "[]" . $arrayspec;
      }
    } 

    #return ($jtype, $acc, $arrayspec, $formatstring);
    return ($formatstring);
  }



sub printoffset()
  {
    my ($offset, $max, $bitsize, $aoffset, $inbits) = @_;

    print "        int offset = $offset;\n";
    for ($i = 1; $i <= @$max; $i++) {
      # check index bounds. 0-sized arrays don't get an upper-bound check
      # (they represent variable size arrays. Normally they should only
      # occur as the first-dimension of the last element of the structure)
      if ($$max[$i - 1] != 0) {
	print "        if (index$i < 0 || index$i >= $$max[$i - 1]) throw new ArrayIndexOutOfBoundsException();\n";
      } else {
	print "        if (index$i < 0) throw new ArrayIndexOutOfBoundsException();\n";
      }
      print "        offset += $$aoffset[$i - 1] + index$i * $$bitsize[$i - 1];\n";
    }
    if ($inbits) {
      print "        return offset;\n";
    } else {
      print "        return (offset / 8);\n";
    }
  }

sub printarrayget() {
  my ($javafield, $javatype, $arrayspec, $bitlength, $amax, $abitsize) = @_;

  # Check whether array has known size
  for ($i = 0; $i < @$amax; $i++) {
    if ($$amax[$i] == 0) {
      print "        throw new IllegalArgumentException(\"Cannot get field as array - unknown size\");\n";
      return;
    }
  }

  print "        $javatype$arrayspec tmp = new $javatype";
  for ($i = 0; $i < @$amax; $i++) {
    print "[$$amax[$i]]";
  }
  print ";\n";

  $indent = " ";
  for ($i = 0; $i < @$amax; $i++) {
    print "      $indent for (int index$i = 0; index$i < numElements_$javafield($i); index$i++) {\n";
    $indent = $indent . "  ";
  }
  $indent = $indent . "  ";
  print "      $indent tmp";
  for ($i = 0; $i < @$amax; $i++) {
    print "[index$i]";
  }
  print " = getElement_$javafield(";
  for ($i = 0; $i < @$amax; $i++) {
    print "index$i";
    if ($i != @$amax-1) {
      print ",";
    }
  }
  print ");\n";

  $indent = substr($indent, 0, length($indent)-2);
  for ($i = 0; $i < @$amax; $i++) {
    $indent = substr($indent, 0, length($indent)-2);
    print "      $indent }\n";
  }
  print "        return tmp;\n";
}

sub printarrayset() {
  my ($javafield, $javatype, $arrayspec, $bitlength, $amax, $abitsize) = @_;

  $indent = " ";
  $val = "";
  for ($i = 0; $i < @$amax; $i++) {
    print "      $indent for (int index$i = 0; index$i < value$val.length; index$i++) {\n";
    $val = $val . "[index$i]";
    $indent = $indent . "  ";
  }
  $indent = $indent . "  ";
  print "      $indent setElement_$javafield(";
  for ($i = 0; $i < @$amax; $i++) {
    print "index$i";
    if ($i != @$amax-1) {
      print ",";
    }
  }
  print ", value";
  for ($i = 0; $i < @$amax; $i++) {
    print "[index$i]";
  }
  print ");\n";

  $indent = substr($indent, 0, length($indent)-2);
  for ($i = 0; $i < @$amax; $i++) {
    $indent = substr($indent, 0, length($indent)-2);
    print "      $indent }\n";
  }
}
-------------- next part --------------
# This file is part of the nesC compiler.
#    Copyright (C) 2002 Intel Corporation
# 
# The attached "nesC" software is provided to you under the terms and
# conditions of the GNU General Public License Version 2 as published by the
# Free Software Foundation.
# 
# nesC is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with nesC; see the file COPYING.  If not, write to
# the Free Software Foundation, 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.

true;

sub gen() {
    my ($classname, @spec) = @_;

    require migdecode;
    &decode(@spec);

    &usage("no classname name specified") if !defined($java_classname);

    $java_extends = "net.tinyos.message.Message" if !defined($java_extends);
    # See if name has a package specifier
    if ($java_classname =~ /(.*)\.([^.]*)$/) {
	$package = $1;
	$java_classname = $2;
    }

    print "/**\n";
    print " * This class is automatically generated by mig. DO NOT EDIT THIS FILE.\n";
    print " * This class implements a Java interface to the '$java_classname'\n";
    print " * message type.\n";
    print " */\n\n";

    print "package $package;\n\n" if $package;

    print "public class $java_classname extends $java_extends {\n\n";

    print "    /** The default size of this message type in bytes. */\n";
    print "    public static final int DEFAULT_MESSAGE_SIZE = $size;\n\n";

    print "    /** The Active Message type associated with this message. */\n";
    print "    public static final int AM_TYPE = $amtype;\n\n";

    print "    /** Create a new $java_classname of size $size. */\n";
    print "    public $java_classname() {\n";
    print "        super(DEFAULT_MESSAGE_SIZE);\n";
    print "        amTypeSet(AM_TYPE);\n";
    print "    }\n\n";

    print "    /** Create a new $java_classname of the given data_length. */\n";
    print "    public $java_classname(int data_length) {\n";
    print "        super(data_length);\n";
    print "        amTypeSet(AM_TYPE);\n";
    print "    }\n\n";

    print "    /**\n";
    print "     * Create a new $java_classname with the given data_length\n";
    print "     * and base offset.\n";
    print "     */\n";
    print "    public $java_classname(int data_length, int base_offset) {\n";
    print "        super(data_length, base_offset);\n";
    print "        amTypeSet(AM_TYPE);\n";
    print "    }\n\n";

    print "    /**\n";
    print "     * Create a new $java_classname using the given byte array\n";
    print "     * as backing store.\n";
    print "     */\n";
    print "    public $java_classname(byte[] data) {\n";
    print "        super(data);\n";
    print "        amTypeSet(AM_TYPE);\n";
    print "    }\n\n";

    print "    /**\n";
    print "     * Create a new $java_classname using the given byte array\n";
    print "     * as backing store, with the given base offset.\n";
    print "     */\n";
    print "    public $java_classname(byte[] data, int base_offset) {\n";
    print "        super(data, base_offset);\n";
    print "        amTypeSet(AM_TYPE);\n";
    print "    }\n\n";

    print "    /**\n";
    print "     * Create a new $java_classname using the given byte array\n";
    print "     * as backing store, with the given base offset and data length.\n";
    print "     */\n";
    print "    public $java_classname(byte[] data, int base_offset, int data_length) {\n";
    print "        super(data, base_offset, data_length);\n";
    print "        amTypeSet(AM_TYPE);\n";
    print "    }\n\n";

    print "    /**\n";
    print "     * Create a new $java_classname embedded in the given message\n";
    print "     * at the given base offset.\n";
    print "     */\n";
    print "    public $java_classname(net.tinyos.message.Message msg, int base_offset) {\n";
    print "        super(msg, base_offset, DEFAULT_MESSAGE_SIZE);\n";
    print "        amTypeSet(AM_TYPE);\n";
    print "    }\n\n";

    print "    /**\n";
    print "     * Create a new $java_classname embedded in the given message\n";
    print "     * at the given base offset and length.\n";
    print "     */\n";
    print "    public $java_classname(net.tinyos.message.Message msg, int base_offset, int data_length) {\n";
    print "        super(msg, base_offset, data_length);\n";
    print "        amTypeSet(AM_TYPE);\n";
    print "    }\n\n";

    print "    /**\n";
    print "    /* Return a String representation of this message. Includes the\n";
    print "     * message type name and the non-indexed field values.\n";
    print "     */\n";
    print "    public String toString() {\n";
    print "      String s = \"Message <$java_classname> \\n\";\n";
    for (@fields) {
	($field, $type, $bitlength, $offset, $amax, $abitsize, $aoffset) = @{$_};
        print "      try {\n";
	$javafield = $field;
	$javafield =~ s/\./_/g;
	if (!@$amax) {
	  ($javatype, $java_access, $arrayspec) = &javabasetype($type, $bitlength, 0);
	  if ($javatype eq "float") {
	    print "        s += \"  [$field=\"+Float.toString(get_$javafield())+\"]\\n\";\n";
	  } else {
	    print "        s += \"  [$field=0x\"+Long.toHexString(get_$javafield())+\"]\\n\";\n";
	  }
	} elsif (@$amax == 1 && $$amax[0] != 0) {
	  ($javatype, $java_access, $arrayspec) = &javabasetype($type, $bitlength, @$amax);
          print "        s += \"  [$field=\";\n";
          print "        for (int i = 0; i < $$amax[0]; i++) {\n";
	  if ($javatype eq "float") {
	    print "          s += Float.toString(getElement_$javafield(i))+\" \";\n";
	  } else {
	    if ($bitlength > 32) {
	      print "          s += \"0x\"+Long.toHexString(getElement_$javafield(i))+\" \";\n";
	    }
	    elsif (bitlength > 16) {
	      print "          s += \"0x\"+Long.toHexString(getElement_$javafield(i) & 0xffffffff)+\" \";\n";
	    }
	    elsif (bitlength > 8) {
	      print "          s += \"0x\"+Long.toHexString(getElement_$javafield(i) & 0xffff)+\" \";\n";
	    }
	    else {
	      print "          s += \"0x\"+Long.toHexString(getElement_$javafield(i) & 0xff)+\" \";\n";
	    }
	  }
          print "        }\n";
          print "        s += \"]\\n\";\n";
	}
        print "      } catch (ArrayIndexOutOfBoundsException aioobe) { /* Skip field */ }\n";
    }
    print "      return s;\n";
    print "    }\n\n";

    print "    // Message-type-specific access methods appear below.\n\n";
    for (@fields) {
	($field, $type, $bitlength, $offset, $amax, $abitsize, $aoffset) = @{$_};

        # Determine if array
	if (@$amax) {
	  $isarray = 1;
	  $arraydims = @$amax;
	  $arraysize_bits = $$amax[0] * $$abitsize[0];
	  $index = 0;
	  @args = map { $index++; "int index$index" } @{$amax};
	  $argspec = join(", ", @args);
	  $index = 0;
	  @passargs = map { $index++; "index$index" } @{$amax};
	  $passargs = join(", ", @passargs);
	} else {
	  $isarray = 0;
	  $arraydims = 0;
	  $arraysize_bits = 0;
	  $argspec = "";
	  $passargs = "";
	}

        # Determine if signed
	if ($basetype eq "U") {
	  $signed = 0; $signedstr = ", unsigned";
	} elsif ($basetype eq "I") {
	  $signed = 1; $signedstr = ", signed";
	} elsif ($basetype eq "F" || $basetype eq "D" || $basetype eq "LD") {
	  $signed = 1; $signstr = "";
	}

        # Get field type and accessor
	$javafield = $field;
	$javafield =~ s/\./_/g;
	($javatype, $java_access, $arrayspec) = &javabasetype($type, $bitlength, $arraydims);

	print "    /////////////////////////////////////////////////////////\n";
	print "    // Accessor methods for field: $field\n";
	if ($isarray) {
	  print "    //   Field type: $javatype$arrayspec$signedstr\n";
	  print "    //   Offset (bits): $offset\n";
	  print "    //   Size of each element (bits): $bitlength\n";
	} else {
	  print "    //   Field type: $javatype$signedstr\n";
	  print "    //   Offset (bits): $offset\n";
	  print "    //   Size (bits): $bitlength\n";
	}
	print "    /////////////////////////////////////////////////////////\n\n";
        ### isSigned
	if ($signed) { $strue = "true"; } else { $strue = "false"; }
	print "    /**\n";
	print "     * Return whether the field '$field' is signed ($strue).\n";
	print "     */\n";
	print "    public static boolean isSigned_$javafield() {\n";
	print "        return $strue;\n";
	print "    }\n\n";

        ### isArray
	if ($isarray) { $atrue = "true"; } else { $atrue = "false"; }
	print "    /**\n";
	print "     * Return whether the field '$field' is an array ($atrue).\n";
	print "     */\n";
	print "    public static boolean isArray_$javafield() {\n";
	print "        return $atrue;\n";
	print "    }\n\n";

        ### Offset
	print "    /**\n";
	print "     * Return the offset (in bytes) of the field '$field'\n";
	if ((int($offset) % 8) != 0) {
	  print "     * WARNING: This field is not byte-aligned (bit offset $offset).\n";
	}
	print "     */\n";

	print "    public static int offset_$javafield($argspec) {\n";
	if ($isarray) {
	    printoffset($base + $offset, $amax, $abitsize, $aoffset, 0);
	} else {
	    print "        return ($offset / 8);\n";
	}
	print "    }\n\n";

	print "    /**\n";
	print "     * Return the offset (in bits) of the field '$field'\n";
	print "     */\n";
	print "    public static int offsetBits_$javafield($argspec) {\n";
	if ($isarray) {
	  printoffset($base + $offset, $amax, $abitsize, $aoffset, 1);
	} else {
	  print "        return $offset;\n";
	}
	print "    }\n\n";


	if (!$isarray) {
	  ### For non-array fields

          ### Get
  	  print "    /**\n";
  	  print "     * Return the value (as a $javatype) of the field '$field'\n";
  	  print "     */\n";
  	  print "    public $javatype get_$javafield() {\n";
  	  print "        return ($javatype)get$java_access(offsetBits_$javafield(), $bitlength);\n";
  	  print "    }\n\n";

          ### Set
  	  print "    /**\n";
  	  print "     * Set the value of the field '$field'\n";
  	  print "     */\n";
  	  print "    public void set_$javafield($javatype value) {\n";
  	  print "        set$java_access(offsetBits_$javafield(), $bitlength, value);\n";
  	  print "    }\n\n";

          ### Size
  	  print "    /**\n";
	  print "     * Return the size, in bytes, of the field '$field'\n";
	  if ((int($bitlength) % 8) != 0) {
	    print "     * WARNING: This field is not an even-sized number of bytes ($bitlength bits).\n";
	  } 
	  print "     */\n";
	  print "    public static int size_$javafield() {\n";
	  if ((int($bitlength) % 8) != 0) {
  	    print "        return ($bitlength / 8) + 1;\n";
	  } else {
  	    print "        return ($bitlength / 8);\n";
          }
	  print "    }\n\n";

  	  print "    /**\n";
	  print "     * Return the size, in bits, of the field '$field'\n";
	  print "     */\n";
	  print "    public static int sizeBits_$javafield() {\n";
	  print "        return $bitlength;\n";
	  print "    }\n\n";

	} else {
          ### For array fields

          ### Get
  	  print "    /**\n";
  	  print "     * Return the entire array '$field' as a $javatype$arrayspec\n";
  	  print "     */\n";
  	  print "    public $javatype$arrayspec get_$javafield() {\n";
	  &printarrayget($javafield, $javatype, $arrayspec, $bitlength, $amax, $abitsize);
  	  print "    }\n\n";

          ### Set
  	  print "    /**\n";
  	  print "     * Set the contents of the array '$field' from the given $javatype$arrayspec\n";
  	  print "     */\n";
  	  print "    public void set_$javafield($javatype$arrayspec value) {\n";
	  &printarrayset($javafield, $javatype, $arrayspec, $bitlength, $amax, $abitsize);
  	  print "    }\n\n";

          ### GetElement
  	  print "    /**\n";
  	  print "     * Return an element (as a $javatype) of the array '$field'\n";
  	  print "     */\n";
  	  print "    public $javatype getElement_$javafield($argspec) {\n";
  	  print "        return ($javatype)get$java_access(offsetBits_$javafield($passargs), $bitlength);\n";
  	  print "    }\n\n";

          ### SetElement
  	  print "    /**\n";
  	  print "     * Set an element of the array '$field'\n";
  	  print "     */\n";
  	  print "    public void setElement_$javafield($argspec, $javatype value) {\n";
  	  print "        set$java_access(offsetBits_$javafield($passargs), $bitlength, value);\n";
  	  print "    }\n\n";

	  if ($arraysize_bits != 0) {
            ### Total size (when array size is known)
  	    print "    /**\n";
	    print "     * Return the total size, in bytes, of the array '$field'\n";
	    if ((int($arraysize_bits) % 8) != 0) {
  	      print "     * WARNING: This array is not an even-sized number of bytes ($arraysize_bits bits).\n";
	    } 
	    print "     */\n";
	    print "    public static int totalSize_$javafield() {\n";
	    print "        return ($arraysize_bits / 8);\n";
	    print "    }\n\n";

  	    print "    /**\n";
	    print "     * Return the total size, in bits, of the array '$field'\n";
	    print "     */\n";
	    print "    public static int totalSizeBits_$javafield() {\n";
	    print "        return $arraysize_bits;\n";
	    print "    }\n\n";
	  }

          ### Element size
	  print "    /**\n";
	  print "     * Return the size, in bytes, of each element of the array '$field'\n";
	  if ((int($bitlength) % 8) != 0) {
	    print "     * WARNING: This field is not an even-sized number of bytes ($bitlength bits).\n";
	  }
	  print "     */\n";
	  print "    public static int elementSize_$javafield() {\n";
	  print "        return ($bitlength / 8);\n";
	  print "    }\n\n";

	  print "    /**\n";
	  print "     * Return the size, in bits, of each element of the array '$field'\n";
	  print "     */\n";
	  print "    public static int elementSizeBits_$javafield() {\n";
	  print "        return $bitlength;\n";
	  print "    }\n\n";

          ### Number of dimensions
	  print "    /**\n";
	  print "     * Return the number of dimensions in the array '$field'\n";
	  print "     */\n";
	  print "    public static int numDimensions_$javafield() {\n";
	  print "        return $arraydims;\n";
	  print "    }\n\n";

          ### Number of elements
	  if ($arraydims == 1 && $$amax[0] != 0) {
            # For 1D arrays where the size of the array is known
  	    print "    /**\n";
	    print "     * Return the number of elements in the array '$field'\n";
	    print "     */\n";
	    print "    public static int numElements_$javafield() {\n";
	    print "        return $$amax[0];\n";
	    print "    }\n\n";
	  } 
	  print "    /**\n";
      	  print "     * Return the number of elements in the array '$field'\n";
	  print "     * for the given dimension.\n";
	  print "     */\n";
	  print "    public static int numElements_$javafield(int dimension) {\n";
	  print "      int array_dims[] = { ";
	  foreach $e (@$amax) { print "$e, "; }
	  print " };\n";
	  print "        if (dimension < 0 || dimension >= $arraydims) throw new ArrayIndexOutOfBoundsException();\n";
	  print "        if (array_dims[dimension] == 0) throw new IllegalArgumentException(\"Array dimension \"+dimension+\" has unknown size\");\n";
	  print "        return array_dims[dimension];\n";
	  print "    }\n\n";

          ### String conversions (for 1D arrays of 8-bit values)
	  if ($arraydims == 1 && $bitlength == 8) {
	      print "    /**\n";
	      print "     * Fill in the array '$field' with a String\n";
	      print "     */\n";
	      print "    public void setString_$javafield(String s) { \n";
	      if ($amax[0] != 0) {
                print "         int len = Math.min(s.length(), $$amax[0]-1);\n";
	      } else {
                print "         int len = s.length();\n";
	      }
	      print "         int i;\n";
	      print "         for (i = 0; i < len; i++) {\n";
	      print "             setElement_$javafield(i, ($javatype)s.charAt(i));\n";
              print "         }\n";
	      print "         setElement_$javafield(i, ($javatype)0); //null terminate\n";
	      print "    }\n\n";

  	      print "    /**\n";
 	      print "     * Read the array '$field' as a String\n";
	      print "     */\n";
	      print "    public String getString_$javafield() { \n";
	      if ($$amax[0] == 0) {
                print "         char carr[] = new char[net.tinyos.message.Message.MAX_CONVERTED_STRING_LENGTH];\n";
	      } else {
                print "         char carr[] = new char[Math.min(net.tinyos.message.Message.MAX_CONVERTED_STRING_LENGTH,$$amax[0])];\n";
              }
	      print "         int i;\n";
	      print "         for (i = 0; i < carr.length; i++) {\n";
	      print "             if ((char)getElement_$javafield(i) == (char)0) break;\n";
	      print "             carr[i] = (char)getElement_$javafield(i);\n";
              print "         }\n";
              print "         return new String(carr,0,i);\n";
	      print "    }\n\n";
	  }
	}
    }

    print "}\n";
}

sub javabasetype()
{
    my ($basetype, $bitlength, $arraydims) = @_;
    my $jtype, $acc;

    # Pick the java type whose range is closest to the corresponding C type
    if ($basetype eq "U") {
      $acc = "UIntElement";
      if ($bitlength < 8) { $jtype = "byte"; }
      elsif ($bitlength < 16) { $jtype = "short"; }
      elsif ($bitlength < 32) { $jtype = "int"; }
      else { $jtype = "long"; }
    }
    elsif ($basetype eq "I") {
      $acc = "SIntElement";
      if ($bitlength <= 8) { $jtype = "byte"; }
      elsif ($bitlength <= 16) { $jtype = "short"; }
      elsif ($bitlength <= 32) { $jtype = "int"; }
      else { $jtype = "long"; }
    }
    elsif ($basetype eq "F" || $basetype eq "D" || $basetype eq "LD") {
      $acc = "FloatElement";
      $jtype = "float";
    }

    if ($arraydims > 0) {
      # For array types
      $arrayspec = "";
      for ($i = 0; $i < $arraydims; $i++) {
	$arrayspec = "[]" . $arrayspec;
      }
    } 

    return ($jtype, $acc, $arrayspec);
}

sub printoffset()
{
    my ($offset, $max, $bitsize, $aoffset, $inbits) = @_;

    print "        int offset = $offset;\n";
    for ($i = 1; $i <= @$max; $i++) {
	# check index bounds. 0-sized arrays don't get an upper-bound check
	# (they represent variable size arrays. Normally they should only
	# occur as the first-dimension of the last element of the structure)
	if ($$max[$i - 1] != 0) {
	    print "        if (index$i < 0 || index$i >= $$max[$i - 1]) throw new ArrayIndexOutOfBoundsException();\n";
	}
	else {
	    print "        if (index$i < 0) throw new ArrayIndexOutOfBoundsException();\n";
	}
	print "        offset += $$aoffset[$i - 1] + index$i * $$bitsize[$i - 1];\n";
    }
    if ($inbits) {
      print "        return offset;\n";
    } else {
      print "        return (offset / 8);\n";
    }
}

sub printarrayget() {
  my ($javafield, $javatype, $arrayspec, $bitlength, $amax, $abitsize) = @_;

  # Check whether array has known size
  for ($i = 0; $i < @$amax; $i++) {
    if ($$amax[$i] == 0) {
      print "        throw new IllegalArgumentException(\"Cannot get field as array - unknown size\");\n";
      return;
    }
  }

  print "        $javatype$arrayspec tmp = new $javatype";
  for ($i = 0; $i < @$amax; $i++) {
    print "[$$amax[$i]]";
  }
  print ";\n";

  $indent = " ";
  for ($i = 0; $i < @$amax; $i++) {
    print "      $indent for (int index$i = 0; index$i < numElements_$javafield($i); index$i++) {\n";
    $indent = $indent . "  ";
  }
  $indent = $indent . "  ";
  print "      $indent tmp";
  for ($i = 0; $i < @$amax; $i++) {
    print "[index$i]";
  }
  print " = getElement_$javafield(";
  for ($i = 0; $i < @$amax; $i++) {
    print "index$i";
    if ($i != @$amax-1) { print ","; }
  }
  print ");\n";

  $indent = substr($indent, 0, length($indent)-2);
  for ($i = 0; $i < @$amax; $i++) {
    $indent = substr($indent, 0, length($indent)-2);
    print "      $indent }\n";
  }
  print "        return tmp;\n";
}

sub printarrayset() {
  my ($javafield, $javatype, $arrayspec, $bitlength, $amax, $abitsize) = @_;

  $indent = " ";
  $val = "";
  for ($i = 0; $i < @$amax; $i++) {
    print "      $indent for (int index$i = 0; index$i < value$val.length; index$i++) {\n";
    $val = $val . "[index$i]";
    $indent = $indent . "  ";
  }
  $indent = $indent . "  ";
  print "      $indent setElement_$javafield(";
  for ($i = 0; $i < @$amax; $i++) {
    print "index$i";
    if ($i != @$amax-1) { print ","; }
  }
  print ", value";
  for ($i = 0; $i < @$amax; $i++) {
    print "[index$i]";
  }
  print ");\n";

  $indent = substr($indent, 0, length($indent)-2);
  for ($i = 0; $i < @$amax; $i++) {
    $indent = substr($indent, 0, length($indent)-2);
    print "      $indent }\n";
  }
}






More information about the Tinyos mailing list