osd-contiki/platform/sensinode/contiki-sensinode-main.c
2012-03-23 14:41:07 +00:00

403 lines
9.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "contiki.h"
#include "sys/clock.h"
#include "sys/autostart.h"
#include "dev/serial-line.h"
#include "dev/slip.h"
#include "dev/bus.h"
#include "dev/leds.h"
#include "dev/uart1.h"
#include "dev/dma.h"
#include "dev/models.h"
#include "dev/cc2430_rf.h"
#include "dev/watchdog.h"
#include "dev/lpm.h"
#include "net/rime.h"
#include "net/netstack.h"
#include "net/mac/frame802154.h"
#include "sensinode-debug.h"
#include "dev/watchdog-cc2430.h"
#include "dev/sensinode-sensors.h"
#include "disco.h"
#include "contiki-lib.h"
#include "contiki-net.h"
unsigned short node_id = 0; /* Manually sets MAC address when > 0 */
#if VIZTOOL_CONF_ON
PROCESS_NAME(viztool_process);
#endif
#if BATMON_CONF_ON
PROCESS_NAME(batmon_process);
#endif
#if SHORTCUTS_CONF_NETSTACK
static __data int len;
#endif
#ifdef STARTUP_CONF_VERBOSE
#define STARTUP_VERBOSE STARTUP_CONF_VERBOSE
#else
#define STARTUP_VERBOSE 0
#endif
#if STARTUP_VERBOSE
#define PUTSTRING(...) putstring(__VA_ARGS__)
#define PUTHEX(...) puthex(__VA_ARGS__)
#define PUTBIN(...) putbin(__VA_ARGS__)
#define PUTCHAR(...) putchar(__VA_ARGS__)
#else
#define PUTSTRING(...) do {} while(0)
#define PUTHEX(...) do {} while(0)
#define PUTBIN(...) do {} while(0)
#define PUTCHAR(...) do {} while(0)
#endif
#if !CLOCK_CONF_ACCURATE
extern volatile __data clock_time_t count;
/* accurate clock is stack hungry */
extern volatile __bit sleep_flag;
#endif
extern rimeaddr_t rimeaddr_node_addr;
static __data int r;
#if ENERGEST_CONF_ON
static unsigned long irq_energest = 0;
#define ENERGEST_IRQ_SAVE(a) do { \
a = energest_type_time(ENERGEST_TYPE_IRQ); } while(0)
#define ENERGEST_IRQ_RESTORE(a) do { \
energest_type_set(ENERGEST_TYPE_IRQ, a); } while(0)
#else
#define ENERGEST_IRQ_SAVE(a) do {} while(0)
#define ENERGEST_IRQ_RESTORE(a) do {} while(0)
#endif
/*---------------------------------------------------------------------------*/
static void
fade(int l)
{
volatile int i, a;
int k, j;
for(k = 0; k < 400; ++k) {
j = k > 200? 400 - k: k;
leds_on(l);
for(i = 0; i < j; ++i) {
a = i;
}
leds_off(l);
for(i = 0; i < 200 - j; ++i) {
a = i;
}
}
}
/*---------------------------------------------------------------------------*/
static void
set_rime_addr(void)
{
uint8_t *addr_long = NULL;
uint16_t addr_short = 0;
char i;
#if SHORTCUTS_CONF_FLASH_READ
__code unsigned char * macp;
#else
static uint8_t ft_buffer[8];
#endif
PUTSTRING("Rime is 0x");
PUTHEX(sizeof(rimeaddr_t));
PUTSTRING(" bytes long\n");
if(node_id == 0) {
PUTSTRING("Reading MAC from flash\n");
#if SHORTCUTS_CONF_FLASH_READ
/*
* The MAC is always stored in 0x1FFF8 of our flash. This maps to address
* 0xFFF8 of our CODE segment, when BANK3 is selected.
* Switch to BANK3, read 8 bytes starting at 0xFFF8 and restore last BANK
* Since we are called from main(), this MUST be BANK1 or something is very
* wrong. This code can be used even without banking
*/
/* Don't interrupt us to make sure no BANK switching happens while working */
DISABLE_INTERRUPTS();
/* Switch to BANK3, map CODE: 0x8000 0xFFFF to FLASH: 0x18000 0x1FFFF */
FMAP = 3;
/* Set our pointer to the correct address and fetch 8 bytes of MAC */
macp = (__code unsigned char *) 0xFFF8;
for(i = (RIMEADDR_SIZE - 1); i >= 0; --i) {
rimeaddr_node_addr.u8[i] = *macp;
macp++;
}
/* Remap 0x8000 0xFFFF to BANK1 */
FMAP = 1;
ENABLE_INTERRUPTS();
#else
/*
* Or use the more generic flash_read() routine which can read from any
* address of our flash
*/
flash_read(ft_buffer, 0x1FFF8, 8);
/* Flip the byte order and store MSB first */
for(i = (RIMEADDR_SIZE - 1); i >= 0; --i) {
rimeaddr_node_addr.u8[RIMEADDR_SIZE - 1 - i] = ft_buffer[i];
}
#endif
} else {
PUTSTRING("Setting manual address from node_id\n");
rimeaddr_node_addr.u8[RIMEADDR_SIZE - 1] = node_id >> 8;
rimeaddr_node_addr.u8[RIMEADDR_SIZE - 2] = node_id & 0xff;
}
/* Now the address is stored MSB first */
#if STARTUP_VERBOSE
PUTSTRING("Rime configured with address ");
for(i = 0; i < RIMEADDR_SIZE - 1; i++) {
PUTHEX(rimeaddr_node_addr.u8[i]);
PUTCHAR(':');
}
PUTHEX(rimeaddr_node_addr.u8[i]);
PUTCHAR('\n');
#endif
/* Set the cc2430 RF addresses */
#if (RIMEADDR_SIZE==8)
addr_short = (rimeaddr_node_addr.u8[6] * 256) + rimeaddr_node_addr.u8[7];
addr_long = (uint8_t *) &rimeaddr_node_addr;
#else
addr_short = (rimeaddr_node_addr.u8[0] * 256) + rimeaddr_node_addr.u8[1];
#endif
cc2430_rf_set_addr(IEEE802154_PANID, addr_short, addr_long);
}
/*---------------------------------------------------------------------------*/
int
main(void)
{
/* Hardware initialization */
bus_init();
rtimer_init();
/* model-specific h/w init. */
model_init();
/* Init LEDs here */
leds_init();
fade(LEDS_GREEN);
/* initialize process manager. */
process_init();
/* Init UART1 */
uart1_init();
#if DMA_ON
dma_init();
#endif
#if SLIP_ARCH_CONF_ENABLE
/* On cc2430, the argument is not used */
slip_arch_init(0);
#else
uart1_set_input(serial_line_input_byte);
serial_line_init();
#endif
PUTSTRING("##########################################\n");
putstring(CONTIKI_VERSION_STRING "\n");
putstring(SENSINODE_MODEL " (CC24");
puthex(((CHIPID >> 3) | 0x20));
putstring("-" FLASH_SIZE ")\n");
#if STARTUP_VERBOSE
#ifdef HAVE_SDCC_BANKING
PUTSTRING(" With Banking.\n");
#endif /* HAVE_SDCC_BANKING */
#ifdef SDCC_MODEL_LARGE
PUTSTRING(" --model-large\n");
#endif /* SDCC_MODEL_LARGE */
#ifdef SDCC_MODEL_HUGE
PUTSTRING(" --model-huge\n");
#endif /* SDCC_MODEL_HUGE */
#ifdef SDCC_STACK_AUTO
PUTSTRING(" --stack-auto\n");
#endif /* SDCC_STACK_AUTO */
PUTCHAR('\n');
PUTSTRING(" Net: ");
PUTSTRING(NETSTACK_NETWORK.name);
PUTCHAR('\n');
PUTSTRING(" MAC: ");
PUTSTRING(NETSTACK_MAC.name);
PUTCHAR('\n');
PUTSTRING(" RDC: ");
PUTSTRING(NETSTACK_RDC.name);
PUTCHAR('\n');
PUTSTRING("##########################################\n");
#endif
watchdog_init();
/* Initialise the cc2430 RNG engine. */
random_init(0);
/* start services */
process_start(&etimer_process, NULL);
ctimer_init();
/* initialize the netstack */
netstack_init();
set_rime_addr();
#if BUTTON_SENSOR_ON || ADC_SENSOR_ON
process_start(&sensors_process, NULL);
sensinode_sensors_activate();
#endif
#if UIP_CONF_IPV6
memcpy(&uip_lladdr.addr, &rimeaddr_node_addr, sizeof(uip_lladdr.addr));
queuebuf_init();
process_start(&tcpip_process, NULL);
#if DISCO_ENABLED
process_start(&disco_process, NULL);
#endif /* DISCO_ENABLED */
#if VIZTOOL_CONF_ON
process_start(&viztool_process, NULL);
#endif
#if (!UIP_CONF_IPV6_RPL)
{
uip_ipaddr_t ipaddr;
uip_ip6addr(&ipaddr, 0x2001, 0x630, 0x301, 0x6453, 0, 0, 0, 0);
uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);
uip_ds6_addr_add(&ipaddr, 0, ADDR_TENTATIVE);
}
#endif /* UIP_CONF_IPV6_RPL */
#endif /* UIP_CONF_IPV6 */
/*
* Acknowledge the UART1 RX interrupt
* now that we're sure we are ready to process it
*/
model_uart_intr_en();
energest_init();
ENERGEST_ON(ENERGEST_TYPE_CPU);
fade(LEDS_RED);
#if BATMON_CONF_ON
process_start(&batmon_process, NULL);
#endif
autostart_start(autostart_processes);
watchdog_start();
while(1) {
do {
/* Reset watchdog and handle polls and events */
watchdog_periodic();
/**/
#if !CLOCK_CONF_ACCURATE
if(sleep_flag) {
if(etimer_pending() &&
(etimer_next_expiration_time() - count - 1) > MAX_TICKS) { /*core/sys/etimer.c*/
etimer_request_poll();
}
sleep_flag = 0;
}
#endif
r = process_run();
} while(r > 0);
#if SHORTCUTS_CONF_NETSTACK
len = NETSTACK_RADIO.pending_packet();
if(len) {
packetbuf_clear();
len = NETSTACK_RADIO.read(packetbuf_dataptr(), PACKETBUF_SIZE);
if(len > 0) {
packetbuf_set_datalen(len);
NETSTACK_RDC.input();
}
}
#endif
#if LPM_MODE
#if (LPM_MODE==LPM_MODE_PM2)
SLEEP &= ~OSC_PD; /* Make sure both HS OSCs are on */
while(!(SLEEP & HFRC_STB)); /* Wait for RCOSC to be stable */
CLKCON |= OSC; /* Switch to the RCOSC */
while(!(CLKCON & OSC)); /* Wait till it's happened */
SLEEP |= OSC_PD; /* Turn the other one off */
#endif /* LPM_MODE==LPM_MODE_PM2 */
/*
* Set MCU IDLE or Drop to PM1. Any interrupt will take us out of LPM
* Sleep Timer will wake us up in no more than 7.8ms (max idle interval)
*/
SLEEP = (SLEEP & 0xFC) | (LPM_MODE - 1);
#if (LPM_MODE==LPM_MODE_PM2)
/*
* Wait 3 NOPs. Either an interrupt occurred and SLEEP.MODE was cleared or
* no interrupt occurred and we can safely power down
*/
__asm
nop
nop
nop
__endasm;
if (SLEEP & SLEEP_MODE0) {
#endif /* LPM_MODE==LPM_MODE_PM2 */
ENERGEST_OFF(ENERGEST_TYPE_CPU);
ENERGEST_ON(ENERGEST_TYPE_LPM);
/* We are only interested in IRQ energest while idle or in LPM */
ENERGEST_IRQ_RESTORE(irq_energest);
/* Go IDLE or Enter PM1 */
PCON |= IDLE;
/* First instruction upon exiting PM1 must be a NOP */
__asm
nop
__endasm;
/* Remember energest IRQ for next pass */
ENERGEST_IRQ_SAVE(irq_energest);
ENERGEST_ON(ENERGEST_TYPE_CPU);
ENERGEST_OFF(ENERGEST_TYPE_LPM);
#if (LPM_MODE==LPM_MODE_PM2)
SLEEP &= ~OSC_PD; /* Make sure both HS OSCs are on */
while(!(SLEEP & XOSC_STB)); /* Wait for XOSC to be stable */
CLKCON &= ~OSC; /* Switch to the XOSC */
/*
* On occasion the XOSC is reported stable when in reality it's not.
* We need to wait for a safeguard of 64us or more before selecting it
*/
clock_delay(10);
while(CLKCON & OSC); /* Wait till it's happened */
}
#endif /* LPM_MODE==LPM_MODE_PM2 */
#endif /* LPM_MODE */
}
}
/*---------------------------------------------------------------------------*/