Contiki 3.x
chameleon-bitopt.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2007, Swedish Institute of Computer Science.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  */
31 
32 /**
33  * \file
34  * A Chameleon module that produces bit-optimized headers
35  * \author
36  * Adam Dunkels <adam@sics.se>
37  */
38 
39 #include "net/rime/chameleon.h"
40 
41 #include "net/rime/rime.h"
42 
43 #include <string.h>
44 
45 /* This option enables an optimization where the link addresses are
46  left to the MAC RDC and not encoded in the Chameleon header.
47  Note: this requires that the underlying MAC layer to add link
48  addresses and will not work together with for example nullrdc.
49  */
50 #ifdef CHAMELEON_CONF_WITH_MAC_LINK_ADDRESSES
51 #define CHAMELEON_WITH_MAC_LINK_ADDRESSES CHAMELEON_CONF_WITH_MAC_LINK_ADDRESSES
52 #else /* !CHAMELEON_CONF_WITH_MAC_LINK_ADDRESSES */
53 #define CHAMELEON_WITH_MAC_LINK_ADDRESSES 0
54 #endif /* !CHAMELEON_CONF_WITH_MAC_LINK_ADDRESSES */
55 
56 struct bitopt_hdr {
57  uint8_t channel[2];
58 };
59 
60 static const uint8_t bitmask[9] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0,
61  0xf8, 0xfc, 0xfe, 0xff };
62 
63 #define DEBUG 0
64 #if DEBUG
65 #include <stdio.h>
66 #define PRINTF(...) printf(__VA_ARGS__)
67 #else
68 #define PRINTF(...)
69 #endif
70 
71 /*---------------------------------------------------------------------------*/
72 uint8_t CC_INLINE
73 get_bits_in_byte(uint8_t *from, int bitpos, int vallen)
74 {
75  uint16_t shifted_val;
76 
77  shifted_val = (from[0] << 8) | from[1];
78 
79  /* PRINTF("get_bits_in_byte: from[0] 0x%02x from[1] 0x%02x shifted_val 0x%04x, return 0x%02x vallen %d\n",
80  from[0], from[1], shifted_val,
81  (((shifted_val << bitpos) >> 8) & bitmask[vallen]) >> (8 - vallen),
82  vallen
83  );*/
84 
85  return (((shifted_val << bitpos) >> 8) & bitmask[vallen]) >> (8 - vallen);
86 }
87 /*---------------------------------------------------------------------------*/
88 void
89 get_bits(uint8_t *to, uint8_t *from, int bitpos, int vallen)
90 {
91  int i, bits;
92 
93 
94  if(vallen < 8) {
95  *to = get_bits_in_byte(from, bitpos, vallen);
96  } else {
97  if(bitpos == 0) {
98  for(i = 0; i < vallen / 8; ++i) {
99  /* PRINTF("get_bits i %d val 0x%02x\n",
100  i, from[i]);*/
101  to[i] = from[i];
102  }
103  bits = vallen & 7;
104  if(bits) {
105  to[i] = get_bits_in_byte(&from[i], 0, bits);
106  }
107  } else {
108  for(i = 0; i < vallen / 8; ++i) {
109  /* PRINTF("get_bits i %d val 0x%02x bitpos %d\n",
110  i, from[i], bitpos);*/
111  to[i] = get_bits_in_byte(&from[i], bitpos, 8);
112  }
113  bits = vallen & 7;
114  if(bits) {
115  to[i] = get_bits_in_byte(&from[i], bitpos, bits);
116  }
117  }
118  }
119 }
120 /*---------------------------------------------------------------------------*/
121 static int
122 header_size(const struct packetbuf_attrlist *a)
123 {
124  int size, len;
125 
126  /* Compute the total size of the final header by summing the size of
127  all attributes that are used on this channel. */
128 
129  size = 0;
130  for(; a->type != PACKETBUF_ATTR_NONE; ++a) {
131 #if CHAMELEON_WITH_MAC_LINK_ADDRESSES
132  if(a->type == PACKETBUF_ADDR_SENDER ||
133  a->type == PACKETBUF_ADDR_RECEIVER) {
134  /* Let the link layer handle sender and receiver */
135  continue;
136  }
137 #endif /* CHAMELEON_WITH_MAC_LINK_ADDRESSES */
138  /* PRINTF("chameleon header_size: header type %d len %d\n",
139  a->type, a->len);*/
140  len = a->len;
141  /* if(len < 8) {
142  len = 8;
143  }*/
144  size += len;
145  }
146  return size;
147 }
148 /*---------------------------------------------------------------------------*/
149 void CC_INLINE
150 set_bits_in_byte(uint8_t *target, int bitpos, uint8_t val, int vallen)
151 {
152  unsigned short shifted_val;
153  shifted_val = val << (8 - bitpos + 8 - vallen);
154  /* printf("set_bits_in_byte before target[0] 0x%02x target[1] 0x%02x shifted_val 0x%04x val 0x%02x vallen %d\n",
155  target[0], target[1], shifted_val, val, vallen);*/
156  target[0] |= shifted_val >> 8;
157  target[1] |= shifted_val & 0xff;
158 }
159 /*---------------------------------------------------------------------------*/
160 void
161 set_bits(uint8_t *ptr, int bitpos, uint8_t *val, int vallen)
162 {
163  int i, bits;
164 
165  /* PRINTF("set_bits %p bitpos %d, val %p len %d\n",
166  ptr, bitpos, val, vallen);*/
167 
168  if(vallen < 8) {
169  set_bits_in_byte(ptr, bitpos, *val /*>> (8 - vallen)*/, vallen);
170  } else {
171  if(bitpos == 0) {
172  for(i = 0; i < vallen / 8; ++i) {
173  /* PRINTF("set_bits i %d val %d\n",
174  i, val[i]);*/
175  ptr[i] = val[i];
176  }
177  bits = vallen & 7;
178  if(bits) {
179  set_bits_in_byte(&ptr[i], 0, val[i] >> (8 - bits), bits);
180  }
181  } else {
182  for(i = 0; i < vallen / 8; ++i) {
183  /* PRINTF("set_bits i %d val %d\n",
184  i, val[i]);*/
185  set_bits_in_byte(&ptr[i], bitpos, val[i], 8);
186  }
187  bits = vallen & 7;
188  if(bits) {
189  set_bits_in_byte(&ptr[i], 0, val[i] >> (8 - bits + bitpos), bits);
190  }
191  }
192  }
193 }
194 /*---------------------------------------------------------------------------*/
195 #if 0
196 static void
197 printbin(int n, int digits)
198 {
199  int i;
200  char output[128];
201 
202  for(i = 0; i < digits; ++i) {
203  output[digits - i - 1] = (n & 1) + '0';
204  n >>= 1;
205  }
206  output[i] = 0;
207 
208  printf(output);
209 }
210 
211 static void
212 printhdr(uint8_t *hdr, int len)
213 {
214  int i, j;
215 
216  j = 0;
217  for(i = 0; i < len; ++i) {
218  printbin(hdr[i], 8);
219  printf(", ");
220  ++j;
221  if(j == 10) {
222  printf("\n");
223  j = 0;
224  }
225  }
226 
227  if(j != 0) {
228  printf("\n");
229  }
230 }
231 #endif
232 /*---------------------------------------------------------------------------*/
233 static int
234 pack_header(struct channel *c)
235 {
236  const struct packetbuf_attrlist *a;
237  int hdrbytesize;
238  int byteptr, bitptr, len;
239  uint8_t *hdrptr;
240  struct bitopt_hdr *hdr;
241 
242  /* Compute the total size of the final header by summing the size of
243  all attributes that are used on this channel. */
244 
245  hdrbytesize = c->hdrsize / 8 + ((c->hdrsize & 7) == 0? 0: 1);
246  if(packetbuf_hdralloc(hdrbytesize + sizeof(struct bitopt_hdr)) == 0) {
247  PRINTF("chameleon-bitopt: insufficient space for headers\n");
248  return 0;
249  }
250  hdr = (struct bitopt_hdr *)packetbuf_hdrptr();
251  hdr->channel[0] = c->channelno & 0xff;
252  hdr->channel[1] = (c->channelno >> 8) & 0xff;
253 
254  hdrptr = ((uint8_t *)packetbuf_hdrptr()) + sizeof(struct bitopt_hdr);
255  memset(hdrptr, 0, hdrbytesize);
256 
257  byteptr = bitptr = 0;
258 
259  for(a = c->attrlist; a->type != PACKETBUF_ATTR_NONE; ++a) {
260 #if CHAMELEON_WITH_MAC_LINK_ADDRESSES
261  if(a->type == PACKETBUF_ADDR_SENDER ||
262  a->type == PACKETBUF_ADDR_RECEIVER) {
263  /* Let the link layer handle sender and receiver */
264  PRINTF("%d.%d: pack_header leaving sender/receiver to link layer\n");
265  continue;
266  }
267 #endif /* CHAMELEON_WITH_MAC_LINK_ADDRESSES */
268  PRINTF("%d.%d: pack_header type %d, len %d, bitptr %d, ",
270  a->type, a->len, bitptr);
271  /* len = (a->len & 0xf8) + ((a->len & 7) ? 8: 0);*/
272  len = a->len;
273  byteptr = bitptr / 8;
274  if(PACKETBUF_IS_ADDR(a->type)) {
275  set_bits(&hdrptr[byteptr], bitptr & 7,
276  (uint8_t *)packetbuf_addr(a->type), len);
277  PRINTF("address %d.%d\n",
278  /* linkaddr_node_addr.u8[0], linkaddr_node_addr.u8[1],*/
279  ((uint8_t *)packetbuf_addr(a->type))[0],
280  ((uint8_t *)packetbuf_addr(a->type))[1]);
281  } else {
282  packetbuf_attr_t val;
283  val = packetbuf_attr(a->type);
284  set_bits(&hdrptr[byteptr], bitptr & 7,
285  (uint8_t *)&val, len);
286  PRINTF("value %d\n",
287  /*linkaddr_node_addr.u8[0], linkaddr_node_addr.u8[1],*/
288  val);
289  }
290  /* printhdr(hdrptr, hdrbytesize);*/
291  bitptr += len;
292  }
293  /* printhdr(hdrptr, hdrbytesize);*/
294 
295  return 1; /* Send out packet */
296 }
297 /*---------------------------------------------------------------------------*/
298 static struct channel *
299 unpack_header(void)
300 {
301  const struct packetbuf_attrlist *a;
302  int byteptr, bitptr, len;
303  int hdrbytesize;
304  uint8_t *hdrptr;
305  struct bitopt_hdr *hdr;
306  struct channel *c;
307 
308 
309  /* The packet has a header that tells us what channel the packet is
310  for. */
311  hdr = (struct bitopt_hdr *)packetbuf_dataptr();
312  if(packetbuf_hdrreduce(sizeof(struct bitopt_hdr)) == 0) {
313  PRINTF("chameleon-bitopt: too short packet\n");
314  return NULL;
315  }
316  c = channel_lookup((hdr->channel[1] << 8) + hdr->channel[0]);
317  if(c == NULL) {
318  PRINTF("chameleon-bitopt: input: channel %u not found\n",
319  (hdr->channel[1] << 8) + hdr->channel[0]);
320  return NULL;
321  }
322 
323  hdrptr = packetbuf_dataptr();
324  hdrbytesize = c->hdrsize / 8 + ((c->hdrsize & 7) == 0? 0: 1);
325  if(packetbuf_hdrreduce(hdrbytesize) == 0) {
326  PRINTF("chameleon-bitopt: too short packet\n");
327  return NULL;
328  }
329  byteptr = bitptr = 0;
330  for(a = c->attrlist; a->type != PACKETBUF_ATTR_NONE; ++a) {
331 #if CHAMELEON_WITH_MAC_LINK_ADDRESSES
332  if(a->type == PACKETBUF_ADDR_SENDER ||
333  a->type == PACKETBUF_ADDR_RECEIVER) {
334  /* Let the link layer handle sender and receiver */
335  continue;
336  }
337 #endif /* CHAMELEON_WITH_MAC_LINK_ADDRESSES */
338  PRINTF("%d.%d: unpack_header type %d, len %d, bitptr %d\n",
340  a->type, a->len, bitptr);
341  /* len = (a->len & 0xf8) + ((a->len & 7) ? 8: 0);*/
342  len = a->len;
343  byteptr = bitptr / 8;
344  if(PACKETBUF_IS_ADDR(a->type)) {
345  linkaddr_t addr;
346  get_bits((uint8_t *)&addr, &hdrptr[byteptr], bitptr & 7, len);
347  PRINTF("%d.%d: unpack_header type %d, addr %d.%d\n",
349  a->type, addr.u8[0], addr.u8[1]);
350  packetbuf_set_addr(a->type, &addr);
351  } else {
352  packetbuf_attr_t val = 0;
353  get_bits((uint8_t *)&val, &hdrptr[byteptr], bitptr & 7, len);
354 
355  packetbuf_set_attr(a->type, val);
356  PRINTF("%d.%d: unpack_header type %d, val %d\n",
358  a->type, val);
359  }
360  /* byteptr += len / 8;*/
361  bitptr += len;
362  }
363  return c;
364 }
365 /*---------------------------------------------------------------------------*/
366 CC_CONST_FUNCTION struct chameleon_module chameleon_bitopt = {
367  unpack_header,
368  pack_header,
369  header_size
370 };
371 /*---------------------------------------------------------------------------*/
int packetbuf_hdralloc(int size)
Extend the header of the packetbuf, for outbound packets.
Definition: packetbuf.c:172
linkaddr_t linkaddr_node_addr
The Rime address of the node.
Definition: linkaddr.c:48
Header file for Chameleon, Rime&#39;s header processing module
#define CC_CONST_FUNCTION
Configure if the C compiler have problems with const function pointers.
Definition: cc.h:86
#define NULL
The null pointer.
Header file for the Rime stack
void * packetbuf_hdrptr(void)
Get a pointer to the header in the packetbuf, for outbound packets.
Definition: packetbuf.c:213
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition: packetbuf.c:207
int packetbuf_hdrreduce(int size)
Reduce the header in the packetbuf, for incoming packets.
Definition: packetbuf.c:188