Contiki 2.6

chameleon-bitopt.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2007, Swedish Institute of Computer Science.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the Institute nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * This file is part of the Contiki operating system.
00030  */
00031 
00032 /**
00033  * \file
00034  *         A Chameleon module that produces bit-optimized headers
00035  * \author
00036  *         Adam Dunkels <adam@sics.se>
00037  */
00038 
00039 #include "net/rime/chameleon.h"
00040 
00041 #include "net/rime.h"
00042 
00043 #include <string.h>
00044 
00045 /* This option enables an optimization where the link addresses are
00046    left to the MAC RDC and not encoded in the Chameleon header.
00047    Note: this requires that the underlying MAC layer to add link
00048    addresses and will not work together with for example nullrdc.
00049  */
00050 #ifdef CHAMELEON_CONF_WITH_MAC_LINK_ADDRESSES
00051 #define CHAMELEON_WITH_MAC_LINK_ADDRESSES CHAMELEON_CONF_WITH_MAC_LINK_ADDRESSES
00052 #else /* !CHAMELEON_CONF_WITH_MAC_LINK_ADDRESSES */
00053 #define CHAMELEON_WITH_MAC_LINK_ADDRESSES 0
00054 #endif /* !CHAMELEON_CONF_WITH_MAC_LINK_ADDRESSES */
00055 
00056 struct bitopt_hdr {
00057   uint8_t channel[2];
00058 };
00059 
00060 static const uint8_t bitmask[9] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0,
00061                                  0xf8, 0xfc, 0xfe, 0xff };
00062 
00063 #define DEBUG 0
00064 #if DEBUG
00065 #include <stdio.h>
00066 #define PRINTF(...) printf(__VA_ARGS__)
00067 #else
00068 #define PRINTF(...)
00069 #endif
00070 
00071 /*---------------------------------------------------------------------------*/
00072 uint8_t CC_INLINE
00073 get_bits_in_byte(uint8_t *from, int bitpos, int vallen)
00074 {
00075   uint16_t shifted_val;
00076 
00077   shifted_val = (from[0] << 8) | from[1];
00078 
00079   /*  PRINTF("get_bits_in_byte: from[0] 0x%02x from[1] 0x%02x shifted_val 0x%04x, return 0x%02x vallen %d\n",
00080         from[0], from[1], shifted_val,
00081         (((shifted_val << bitpos) >> 8) & bitmask[vallen]) >> (8 - vallen),
00082         vallen
00083         );*/
00084   
00085   return (((shifted_val << bitpos) >> 8) & bitmask[vallen]) >> (8 - vallen);
00086 }
00087 /*---------------------------------------------------------------------------*/
00088 void
00089 get_bits(uint8_t *to, uint8_t *from, int bitpos, int vallen)
00090 {
00091   int i, bits;
00092   
00093   
00094   if(vallen < 8) {
00095     *to = get_bits_in_byte(from, bitpos, vallen);
00096   } else {
00097     if(bitpos == 0) {
00098       for(i = 0; i < vallen / 8; ++i) {
00099         /*      PRINTF("get_bits i %d val 0x%02x\n",
00100                 i, from[i]);*/
00101         to[i] = from[i];
00102       }
00103       bits = vallen & 7;
00104       if(bits) {
00105         to[i] = get_bits_in_byte(&from[i], 0, bits);
00106       }
00107     } else {
00108       for(i = 0; i < vallen / 8; ++i) {
00109         /*      PRINTF("get_bits i %d val 0x%02x bitpos %d\n",
00110                 i, from[i], bitpos);*/
00111         to[i] = get_bits_in_byte(&from[i], bitpos, 8);
00112       }
00113       bits = vallen & 7;
00114       if(bits) {
00115         to[i] = get_bits_in_byte(&from[i], bitpos, bits);
00116       }
00117     }
00118   }
00119 }
00120 /*---------------------------------------------------------------------------*/
00121 static int
00122 header_size(const struct packetbuf_attrlist *a)
00123 {
00124   int size, len;
00125   
00126   /* Compute the total size of the final header by summing the size of
00127      all attributes that are used on this channel. */
00128   
00129   size = 0;
00130   for(; a->type != PACKETBUF_ATTR_NONE; ++a) {
00131 #if CHAMELEON_WITH_MAC_LINK_ADDRESSES
00132     if(a->type == PACKETBUF_ADDR_SENDER ||
00133        a->type == PACKETBUF_ADDR_RECEIVER) {
00134       /* Let the link layer handle sender and receiver */
00135       continue;
00136     }
00137 #endif /* CHAMELEON_WITH_MAC_LINK_ADDRESSES */
00138     /*    PRINTF("chameleon header_size: header type %d len %d\n",
00139            a->type, a->len);*/
00140     len = a->len;
00141     /*    if(len < 8) {
00142       len = 8;
00143       }*/
00144     size += len;
00145   }
00146   return size;
00147 }
00148 /*---------------------------------------------------------------------------*/
00149 void CC_INLINE
00150 set_bits_in_byte(uint8_t *target, int bitpos, uint8_t val, int vallen)
00151 {
00152   unsigned short shifted_val;
00153   shifted_val = val << (8 - bitpos + 8 - vallen);
00154   /*  printf("set_bits_in_byte before target[0] 0x%02x target[1] 0x%02x shifted_val 0x%04x val 0x%02x vallen %d\n",
00155       target[0], target[1], shifted_val, val, vallen);*/
00156   target[0] |= shifted_val >> 8;
00157   target[1] |= shifted_val & 0xff;
00158 }
00159 /*---------------------------------------------------------------------------*/
00160 void
00161 set_bits(uint8_t *ptr, int bitpos, uint8_t *val, int vallen)
00162 {
00163   int i, bits;
00164 
00165   /*  PRINTF("set_bits %p bitpos %d, val %p len %d\n",
00166       ptr, bitpos, val, vallen);*/
00167 
00168   if(vallen < 8) {
00169     set_bits_in_byte(ptr, bitpos, *val /*>> (8 - vallen)*/, vallen);
00170   } else {
00171     if(bitpos == 0) {
00172       for(i = 0; i < vallen / 8; ++i) {
00173         /*      PRINTF("set_bits i %d val %d\n",
00174                 i, val[i]);*/
00175         ptr[i] = val[i];
00176       }
00177       bits = vallen & 7;
00178       if(bits) {
00179         set_bits_in_byte(&ptr[i], 0, val[i] >> (8 - bits), bits);
00180       }
00181     } else {
00182       for(i = 0; i < vallen / 8; ++i) {
00183         /*      PRINTF("set_bits i %d val %d\n",
00184                 i, val[i]);*/
00185         set_bits_in_byte(&ptr[i], bitpos, val[i], 8);
00186       }
00187       bits = vallen & 7;
00188       if(bits) {
00189         set_bits_in_byte(&ptr[i], 0, val[i] >> (8 - bits + bitpos), bits);
00190       }
00191     }
00192   }
00193 }
00194 /*---------------------------------------------------------------------------*/
00195 #if 0
00196 static void
00197 printbin(int n, int digits)
00198 {
00199   int i;
00200   char output[128];
00201   
00202   for(i = 0; i < digits; ++i) {
00203     output[digits - i - 1] = (n & 1) + '0';
00204     n >>= 1;
00205   }
00206   output[i] = 0;
00207   
00208   printf(output);
00209 }
00210 
00211 static void
00212 printhdr(uint8_t *hdr, int len)
00213 {
00214   int i, j;
00215 
00216   j = 0;
00217   for(i = 0; i < len; ++i) {
00218     printbin(hdr[i], 8);
00219     printf(", ");
00220     ++j;
00221     if(j == 10) {
00222       printf("\n");
00223       j = 0;
00224     }
00225   }
00226 
00227   if(j != 0) {
00228     printf("\n");
00229   }
00230 }
00231 #endif
00232 /*---------------------------------------------------------------------------*/
00233 static int
00234 pack_header(struct channel *c)
00235 {
00236   const struct packetbuf_attrlist *a;
00237   int hdrbytesize;
00238   int byteptr, bitptr, len;
00239   uint8_t *hdrptr;
00240   struct bitopt_hdr *hdr;
00241   
00242   /* Compute the total size of the final header by summing the size of
00243      all attributes that are used on this channel. */
00244 
00245   hdrbytesize = c->hdrsize / 8 + ((c->hdrsize & 7) == 0? 0: 1);
00246   if(packetbuf_hdralloc(hdrbytesize + sizeof(struct bitopt_hdr)) == 0) {
00247     PRINTF("chameleon-bitopt: insufficient space for headers\n");
00248     return 0;
00249   }
00250   hdr = (struct bitopt_hdr *)packetbuf_hdrptr();
00251   hdr->channel[0] = c->channelno & 0xff;
00252   hdr->channel[1] = (c->channelno >> 8) & 0xff;
00253 
00254   hdrptr = ((uint8_t *)packetbuf_hdrptr()) + sizeof(struct bitopt_hdr);
00255   memset(hdrptr, 0, hdrbytesize);
00256   
00257   byteptr = bitptr = 0;
00258   
00259   for(a = c->attrlist; a->type != PACKETBUF_ATTR_NONE; ++a) {
00260 #if CHAMELEON_WITH_MAC_LINK_ADDRESSES
00261     if(a->type == PACKETBUF_ADDR_SENDER ||
00262        a->type == PACKETBUF_ADDR_RECEIVER) {
00263       /* Let the link layer handle sender and receiver */
00264       PRINTF("%d.%d: pack_header leaving sender/receiver to link layer\n");
00265       continue;
00266     }
00267 #endif /* CHAMELEON_WITH_MAC_LINK_ADDRESSES */
00268     PRINTF("%d.%d: pack_header type %d, len %d, bitptr %d, ",
00269            rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00270            a->type, a->len, bitptr);
00271     /*    len = (a->len & 0xf8) + ((a->len & 7) ? 8: 0);*/
00272     len = a->len;
00273     byteptr = bitptr / 8;
00274     if(PACKETBUF_IS_ADDR(a->type)) {
00275       set_bits(&hdrptr[byteptr], bitptr & 7,
00276                (uint8_t *)packetbuf_addr(a->type), len);
00277       PRINTF("address %d.%d\n",
00278             /*      rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],*/
00279             ((uint8_t *)packetbuf_addr(a->type))[0],
00280             ((uint8_t *)packetbuf_addr(a->type))[1]);
00281     } else {
00282       packetbuf_attr_t val;
00283       val = packetbuf_attr(a->type);
00284       set_bits(&hdrptr[byteptr], bitptr & 7,
00285                (uint8_t *)&val, len);
00286       PRINTF("value %d\n",
00287             /*rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],*/
00288             val);
00289     }
00290     /*    printhdr(hdrptr, hdrbytesize);*/
00291     bitptr += len;
00292   }
00293   /*  printhdr(hdrptr, hdrbytesize);*/
00294 
00295   return 1; /* Send out packet */
00296 }
00297 /*---------------------------------------------------------------------------*/
00298 static struct channel *
00299 unpack_header(void)
00300 {
00301   const struct packetbuf_attrlist *a;
00302   int byteptr, bitptr, len;
00303   int hdrbytesize;
00304   uint8_t *hdrptr;
00305   struct bitopt_hdr *hdr;
00306   struct channel *c;
00307   
00308 
00309   /* The packet has a header that tells us what channel the packet is
00310      for. */
00311   hdr = (struct bitopt_hdr *)packetbuf_dataptr();
00312   if(packetbuf_hdrreduce(sizeof(struct bitopt_hdr)) == 0) {
00313     PRINTF("chameleon-bitopt: too short packet\n");
00314     return NULL;
00315   }
00316   c = channel_lookup((hdr->channel[1] << 8) + hdr->channel[0]);
00317   if(c == NULL) {
00318     PRINTF("chameleon-bitopt: input: channel %u not found\n",
00319            (hdr->channel[1] << 8) + hdr->channel[0]);
00320     return NULL;
00321   }
00322 
00323   hdrptr = packetbuf_dataptr();
00324   hdrbytesize = c->hdrsize / 8 + ((c->hdrsize & 7) == 0? 0: 1);
00325   if(packetbuf_hdrreduce(hdrbytesize) == 0) {
00326     PRINTF("chameleon-bitopt: too short packet\n");
00327     return NULL;
00328   }
00329   byteptr = bitptr = 0;
00330   for(a = c->attrlist; a->type != PACKETBUF_ATTR_NONE; ++a) {
00331 #if CHAMELEON_WITH_MAC_LINK_ADDRESSES
00332     if(a->type == PACKETBUF_ADDR_SENDER ||
00333        a->type == PACKETBUF_ADDR_RECEIVER) {
00334       /* Let the link layer handle sender and receiver */
00335       continue;
00336     }
00337 #endif /* CHAMELEON_WITH_MAC_LINK_ADDRESSES */
00338     PRINTF("%d.%d: unpack_header type %d, len %d, bitptr %d\n",
00339            rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00340            a->type, a->len, bitptr);
00341     /*    len = (a->len & 0xf8) + ((a->len & 7) ? 8: 0);*/
00342     len = a->len;
00343     byteptr = bitptr / 8;
00344     if(PACKETBUF_IS_ADDR(a->type)) {
00345       rimeaddr_t addr;
00346       get_bits((uint8_t *)&addr, &hdrptr[byteptr], bitptr & 7, len);
00347       PRINTF("%d.%d: unpack_header type %d, addr %d.%d\n",
00348              rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00349              a->type, addr.u8[0], addr.u8[1]);
00350       packetbuf_set_addr(a->type, &addr);
00351     } else {
00352       packetbuf_attr_t val = 0;
00353       get_bits((uint8_t *)&val, &hdrptr[byteptr], bitptr & 7, len);
00354 
00355       packetbuf_set_attr(a->type, val);
00356       PRINTF("%d.%d: unpack_header type %d, val %d\n",
00357              rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00358              a->type, val);
00359     }
00360     /*    byteptr += len / 8;*/
00361     bitptr += len;
00362   }
00363   return c;
00364 }
00365 /*---------------------------------------------------------------------------*/
00366 CC_CONST_FUNCTION struct chameleon_module chameleon_bitopt = {
00367   unpack_header,
00368   pack_header,
00369   header_size
00370 };
00371 /*---------------------------------------------------------------------------*/