Part 1: Using External Types
============================

External types are an extension to nesC for platform-independent type
representation: you can define your packet layout using syntax very similar
to existing C type declarations, and just accesses it like a regular C
type. The compiler ensures that this type has the same representation on
all platforms and generates any necessary conversion code. Additionally,
these types have no alignment restrictions. This makes them particularly
suitable for defining and accessing network packets in a
platform-independent way.

For instance, the SurgeCmdMsg from the Surge application can be defined and
accessed as follows using external types:

  typedef nx_struct {
    nx_uint8_t type;
    nx_union {
      nx_uint32_t newrate;
      nx_uint16_t focusaddr;
    } args;
  } SurgeCmdMsg;
  ...

  SurgeCmdMsg *pCmdMsg = (SurgeCmdMsg *)payload;
  if (pCmdMsg->type == SURGE_TYPE_SETRATE) {
    timer_rate = pCmdMsg->args.newrate;
  ...

More formally, nesC includes three kinds of external types. 

  o External base types are similar to the fixed size in8_t, uint16_t, etc
    types. They include 8, 16, 32 and 64-bit signed and unsigned integers
    denoted by the types nx_[u]int[8/16/32/64]_t.  

  o External array types are any array built from an external type, using 
    the usual C syntax, e.g, nx_int16_t x[10]. 

  o External structures are declared like C structures and unions, but 
    using the nx_struct and nx_union keywords (as in the SurgeCmdMsg 
    example above). An external structure can only contain external types
    as elements. 

External types have no alignment restrictions, external structures contain
no padding, and the external base types use a 2's complement, big-endian
representation (there are also little-endian versions of the base types
available, using the nxle_ prefix, but their use is discouraged for
networking purposes). Bit-fields in external structures are maximally
packed. A 0-width bit-field moves allocation on to the next byte. Thus the
representation of external types is platform-independent, and any arbitrary
section of memory can be accessed via an external type.

All these external types can be used exactly like regular C types, with a
few restrictions: 
  o Bit-fields can only be created from big-endian external base types
    (i.e., `nx_struct { nxle_uint8_t f1 : 2; }' is not allowed).
    Having  big- and little-endian bit-fields adjacent in a type would 
    be problematic...
  o Bit-fields of external types cannot be used inside non-external
    structures (i.e., `struct { nx_uint8_t f1 : 2; }' is not allowed).
  o External type variables cannot have initialisers.

Part 2: Implementation
======================

In the generated C code for nesC programs using external types, we simply
define a C type for each external base type, translate nx_struct and
nx_union to struct and union and leave array types unchanged. The external
base types are replaced by structures containing char arrays. 

Reads and writes of external base types are replaced by calls to inline
functions like NTOH32 in the example below.  For instance, the example
from Surge becomes:

  typedef struct { char data[4]; } nx_uint32_t;
  static inline unsigned short NTOUH32(void *target) {
    unsigned char *base = target;
    return (unsigned long)base[3] << 24 |
           (unsigned long)base[2] << 16 |
           base[1] << 8 | base[0];
  }
  ...
  typedef struct {
    nx_uint8_t type;
    union {
      nx_uint32_t newrate;
      nx_uint16_t focusaddr;
    } args;
  } SurgeCmdMsg;
  ...
  SurgeCmdMsg *pCmdMsg = (SurgeCmdMsg *)payload;
  if (NTOUH8(&pCmdMsg->type) == SURGE_TYPE_SETRATE) {
      timer_rate = NTOUH32(&pCmdMsg->args.newrate);
  ...

For this translation to be correct, a structure containing only characters
(such as nx_uint32_t) should have no alignment restrictions, and the same
must hold for structures containing such structures (e.g.,
SurgeCmdMsg). This is true on many, but not all platforms: on ARM
processors, all structures are aligned to 4-byte boundaries, and on
Motorola 68K processors they are aligned to 2-byte boundaries. We currently
work around this problem by using gcc's non-standard packed attribute.

Bit-fields are a little more complex: space used by bit-fields inside
external structures are replaced by "filler" fields. Accesses to external
bit-fields is done by taking the address of the enclosing external
structure, treating it as an array of bytes and accessing the appropriate
offsets.
