Contiki 2.6

contiki-sensinode-main.c

00001 #include "contiki.h"
00002 #include "sys/clock.h"
00003 #include "sys/autostart.h"
00004 
00005 #include "dev/serial-line.h"
00006 #include "dev/slip.h"
00007 #include "dev/bus.h"
00008 #include "dev/leds.h"
00009 #include "dev/uart1.h"
00010 #include "dev/dma.h"
00011 #include "dev/models.h"
00012 #include "dev/cc2430_rf.h"
00013 #include "dev/watchdog.h"
00014 #include "dev/lpm.h"
00015 #include "net/rime.h"
00016 #include "net/netstack.h"
00017 #include "net/mac/frame802154.h"
00018 #include "debug.h"
00019 #include "dev/watchdog-cc2430.h"
00020 #include "dev/sensinode-sensors.h"
00021 #include "disco.h"
00022 #include "contiki-lib.h"
00023 #include "contiki-net.h"
00024 
00025 unsigned short node_id = 0;                     /* Manually sets MAC address when > 0 */
00026 
00027 #if VIZTOOL_CONF_ON
00028 PROCESS_NAME(viztool_process);
00029 #endif
00030 
00031 #if BATMON_CONF_ON
00032 PROCESS_NAME(batmon_process);
00033 #endif
00034 
00035 #if NETSTACK_CONF_SHORTCUTS
00036 static __data int len;
00037 #endif
00038 
00039 #ifdef STARTUP_CONF_VERBOSE
00040 #define STARTUP_VERBOSE STARTUP_CONF_VERBOSE
00041 #else
00042 #define STARTUP_VERBOSE 0
00043 #endif
00044 
00045 #if STARTUP_VERBOSE
00046 #define PUTSTRING(...) putstring(__VA_ARGS__)
00047 #define PUTHEX(...) puthex(__VA_ARGS__)
00048 #define PUTBIN(...) putbin(__VA_ARGS__)
00049 #define PUTCHAR(...) putchar(__VA_ARGS__)
00050 #else
00051 #define PUTSTRING(...) do {} while(0)
00052 #define PUTHEX(...) do {} while(0)
00053 #define PUTBIN(...) do {} while(0)
00054 #define PUTCHAR(...) do {} while(0)
00055 #endif
00056 
00057 #if CLOCK_CONF_STACK_FRIENDLY
00058 extern volatile __bit sleep_flag;
00059 #endif
00060 
00061 extern rimeaddr_t rimeaddr_node_addr;
00062 static __data int r;
00063 #if ENERGEST_CONF_ON
00064 static unsigned long irq_energest = 0;
00065 #define ENERGEST_IRQ_SAVE(a) do { \
00066     a = energest_type_time(ENERGEST_TYPE_IRQ); } while(0)
00067 #define ENERGEST_IRQ_RESTORE(a) do { \
00068     energest_type_set(ENERGEST_TYPE_IRQ, a); } while(0)
00069 #else
00070 #define ENERGEST_IRQ_SAVE(a) do {} while(0)
00071 #define ENERGEST_IRQ_RESTORE(a) do {} while(0)
00072 #endif
00073 /*---------------------------------------------------------------------------*/
00074 static void
00075 fade(int l) CC_NON_BANKED
00076 {
00077   volatile int i, a;
00078   int k, j;
00079   for(k = 0; k < 400; ++k) {
00080     j = k > 200? 400 - k: k;
00081 
00082     leds_on(l);
00083     for(i = 0; i < j; ++i) {
00084       a = i;
00085     }
00086     leds_off(l);
00087     for(i = 0; i < 200 - j; ++i) {
00088       a = i;
00089     }
00090   }
00091 }
00092 /*---------------------------------------------------------------------------*/
00093 static void
00094 set_rime_addr(void) CC_NON_BANKED
00095 {
00096   uint8_t *addr_long = NULL;
00097   uint16_t addr_short = 0;
00098   char i;
00099   __code unsigned char * macp;
00100 
00101   PUTSTRING("Rime is 0x");
00102   PUTHEX(sizeof(rimeaddr_t));
00103   PUTSTRING(" bytes long\n");
00104 
00105   if(node_id == 0) {
00106     PUTSTRING("Reading MAC from flash\n");
00107     /*
00108      * The MAC is always stored in 0x1FFF8 of our flash. This maps to address
00109      * 0xFFF8 of our CODE segment, when BANK3 is selected.
00110      * Switch to BANK3, read 8 bytes starting at 0xFFF8 and restore last BANK
00111      * Since we are called from main(), this MUST be BANK1 or something is very
00112      * wrong. This code can be used even without banking
00113      */
00114 
00115     /* Don't interrupt us to make sure no BANK switching happens while working */
00116     DISABLE_INTERRUPTS();
00117 
00118     /* Switch to BANK3, map CODE: 0x8000 - 0xFFFF to FLASH: 0x18000 - 0x1FFFF */
00119     FMAP = 3;
00120 
00121     /* Set our pointer to the correct address and fetch 8 bytes of MAC */
00122     macp = (__code unsigned char *) 0xFFF8;
00123 
00124     for(i = (RIMEADDR_SIZE - 1); i >= 0; --i) {
00125       rimeaddr_node_addr.u8[i] = *macp;
00126       macp++;
00127     }
00128 
00129     /* Remap 0x8000 - 0xFFFF to BANK1 */
00130     FMAP = 1;
00131     ENABLE_INTERRUPTS();
00132 
00133   } else {
00134     PUTSTRING("Setting manual address from node_id\n");
00135     rimeaddr_node_addr.u8[RIMEADDR_SIZE - 1] = node_id >> 8;
00136     rimeaddr_node_addr.u8[RIMEADDR_SIZE - 2] = node_id & 0xff;
00137   }
00138 
00139   /* Now the address is stored MSB first */
00140 #if STARTUP_VERBOSE
00141   PUTSTRING("Rime configured with address ");
00142   for(i = 0; i < RIMEADDR_SIZE - 1; i++) {
00143     PUTHEX(rimeaddr_node_addr.u8[i]);
00144     PUTCHAR(':');
00145   }
00146   PUTHEX(rimeaddr_node_addr.u8[i]);
00147   PUTCHAR('\n');
00148 #endif
00149 
00150   /* Set the cc2430 RF addresses */
00151 #if (RIMEADDR_SIZE==8)
00152   addr_short = (rimeaddr_node_addr.u8[6] * 256) + rimeaddr_node_addr.u8[7];
00153   addr_long = (uint8_t *) &rimeaddr_node_addr;
00154 #else
00155   addr_short = (rimeaddr_node_addr.u8[0] * 256) + rimeaddr_node_addr.u8[1];
00156 #endif
00157   cc2430_rf_set_addr(IEEE802154_PANID, addr_short, addr_long);
00158 }
00159 /*---------------------------------------------------------------------------*/
00160 int
00161 main(void)
00162 {
00163 
00164   /* Hardware initialization */
00165   bus_init();
00166   rtimer_init();
00167 
00168   /* model-specific h/w init. */
00169   model_init();
00170 
00171   /* Init LEDs here */
00172   leds_init();
00173   fade(LEDS_GREEN);
00174 
00175   /* initialize process manager. */
00176   process_init();
00177 
00178   /* Init UART1 */
00179   uart1_init();
00180 
00181 #if DMA_ON
00182   dma_init();
00183 #endif
00184 
00185 #if SLIP_ARCH_CONF_ENABLE
00186   /* On cc2430, the argument is not used */
00187   slip_arch_init(0);
00188 #else
00189   uart1_set_input(serial_line_input_byte);
00190   serial_line_init();
00191 #endif
00192 
00193   PUTSTRING("##########################################\n");
00194   putstring(CONTIKI_VERSION_STRING "\n");
00195   putstring(SENSINODE_MODEL " (CC24");
00196   puthex(((CHIPID >> 3) | 0x20));
00197   putstring("-" FLASH_SIZE ")\n");
00198 
00199 #if STARTUP_VERBOSE
00200 #ifdef HAVE_SDCC_BANKING
00201   PUTSTRING("  With Banking.\n");
00202 #endif /* HAVE_SDCC_BANKING */
00203 #ifdef SDCC_MODEL_LARGE
00204   PUTSTRING("  --model-large\n");
00205 #endif /* SDCC_MODEL_LARGE */
00206 #ifdef SDCC_MODEL_HUGE
00207   PUTSTRING("  --model-huge\n");
00208 #endif /* SDCC_MODEL_HUGE */
00209 #ifdef SDCC_STACK_AUTO
00210   PUTSTRING("  --stack-auto\n");
00211 #endif /* SDCC_STACK_AUTO */
00212 
00213   PUTCHAR('\n');
00214 
00215   PUTSTRING(" Net: ");
00216   PUTSTRING(NETSTACK_NETWORK.name);
00217   PUTCHAR('\n');
00218   PUTSTRING(" MAC: ");
00219   PUTSTRING(NETSTACK_MAC.name);
00220   PUTCHAR('\n');
00221   PUTSTRING(" RDC: ");
00222   PUTSTRING(NETSTACK_RDC.name);
00223   PUTCHAR('\n');
00224 
00225   PUTSTRING("##########################################\n");
00226 #endif
00227 
00228   watchdog_init();
00229 
00230   /* Initialise the cc2430 RNG engine. */
00231   random_init(0);
00232 
00233   /* start services */
00234   process_start(&etimer_process, NULL);
00235   ctimer_init();
00236 
00237   /* initialize the netstack */
00238   netstack_init();
00239   set_rime_addr();
00240 
00241 #if BUTTON_SENSOR_ON || ADC_SENSOR_ON
00242   process_start(&sensors_process, NULL);
00243   sensinode_sensors_activate();
00244 #endif
00245 
00246 #if UIP_CONF_IPV6
00247   memcpy(&uip_lladdr.addr, &rimeaddr_node_addr, sizeof(uip_lladdr.addr));
00248   queuebuf_init();
00249   process_start(&tcpip_process, NULL);
00250 
00251 #if DISCO_ENABLED
00252   process_start(&disco_process, NULL);
00253 #endif /* DISCO_ENABLED */
00254 
00255 #if VIZTOOL_CONF_ON
00256   process_start(&viztool_process, NULL);
00257 #endif
00258 
00259 #if (!UIP_CONF_IPV6_RPL)
00260   {
00261     uip_ipaddr_t ipaddr;
00262 
00263     uip_ip6addr(&ipaddr, 0x2001, 0x630, 0x301, 0x6453, 0, 0, 0, 0);
00264     uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);
00265     uip_ds6_addr_add(&ipaddr, 0, ADDR_TENTATIVE);
00266   }
00267 #endif /* UIP_CONF_IPV6_RPL */
00268 #endif /* UIP_CONF_IPV6 */
00269 
00270   /*
00271    * Acknowledge the UART1 RX interrupt
00272    * now that we're sure we are ready to process it
00273    */
00274   model_uart_intr_en();
00275 
00276   energest_init();
00277   ENERGEST_ON(ENERGEST_TYPE_CPU);
00278 
00279   fade(LEDS_RED);
00280 
00281 #if BATMON_CONF_ON
00282   process_start(&batmon_process, NULL);
00283 #endif
00284 
00285   autostart_start(autostart_processes);
00286 
00287   watchdog_start();
00288 
00289   while(1) {
00290     do {
00291       /* Reset watchdog and handle polls and events */
00292       watchdog_periodic();
00293 
00294 #if CLOCK_CONF_STACK_FRIENDLY
00295       if(sleep_flag) {
00296         if(etimer_pending() &&
00297             (etimer_next_expiration_time() - clock_time() - 1) > MAX_TICKS) {
00298           etimer_request_poll();
00299         }
00300         sleep_flag = 0;
00301       }
00302 #endif
00303       r = process_run();
00304     } while(r > 0);
00305 #if NETSTACK_CONF_SHORTCUTS
00306     len = NETSTACK_RADIO.pending_packet();
00307     if(len) {
00308       packetbuf_clear();
00309       len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE);
00310       if(len > 0) {
00311         packetbuf_set_datalen(len);
00312         NETSTACK_RDC.input();
00313       }
00314     }
00315 #endif
00316 
00317 #if LPM_MODE
00318 #if (LPM_MODE==LPM_MODE_PM2)
00319     SLEEP &= ~OSC_PD;            /* Make sure both HS OSCs are on */
00320     while(!(SLEEP & HFRC_STB));  /* Wait for RCOSC to be stable */
00321     CLKCON |= OSC;               /* Switch to the RCOSC */
00322     while(!(CLKCON & OSC));      /* Wait till it's happened */
00323     SLEEP |= OSC_PD;             /* Turn the other one off */
00324 #endif /* LPM_MODE==LPM_MODE_PM2 */
00325 
00326     /*
00327      * Set MCU IDLE or Drop to PM1. Any interrupt will take us out of LPM
00328      * Sleep Timer will wake us up in no more than 7.8ms (max idle interval)
00329      */
00330     SLEEP = (SLEEP & 0xFC) | (LPM_MODE - 1);
00331 
00332 #if (LPM_MODE==LPM_MODE_PM2)
00333     /*
00334      * Wait 3 NOPs. Either an interrupt occurred and SLEEP.MODE was cleared or
00335      * no interrupt occurred and we can safely power down
00336      */
00337     __asm
00338       nop
00339       nop
00340       nop
00341     __endasm;
00342 
00343     if (SLEEP & SLEEP_MODE0) {
00344 #endif /* LPM_MODE==LPM_MODE_PM2 */
00345 
00346       ENERGEST_OFF(ENERGEST_TYPE_CPU);
00347       ENERGEST_ON(ENERGEST_TYPE_LPM);
00348 
00349       /* We are only interested in IRQ energest while idle or in LPM */
00350       ENERGEST_IRQ_RESTORE(irq_energest);
00351 
00352       /* Go IDLE or Enter PM1 */
00353       PCON |= IDLE;
00354 
00355       /* First instruction upon exiting PM1 must be a NOP */
00356       __asm
00357         nop
00358       __endasm;
00359 
00360       /* Remember energest IRQ for next pass */
00361       ENERGEST_IRQ_SAVE(irq_energest);
00362 
00363       ENERGEST_ON(ENERGEST_TYPE_CPU);
00364       ENERGEST_OFF(ENERGEST_TYPE_LPM);
00365 
00366 #if (LPM_MODE==LPM_MODE_PM2)
00367       SLEEP &= ~OSC_PD;            /* Make sure both HS OSCs are on */
00368       while(!(SLEEP & XOSC_STB));  /* Wait for XOSC to be stable */
00369       CLKCON &= ~OSC;              /* Switch to the XOSC */
00370       /*
00371        * On occasion the XOSC is reported stable when in reality it's not.
00372        * We need to wait for a safeguard of 64us or more before selecting it
00373        */
00374       clock_delay_usec(65);
00375       while(CLKCON & OSC);         /* Wait till it's happened */
00376     }
00377 #endif /* LPM_MODE==LPM_MODE_PM2 */
00378 #endif /* LPM_MODE */
00379   }
00380 }
00381 /*---------------------------------------------------------------------------*/