⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 halstack.c

📁 zigbee 协议堆栈 stack(简化协议)
💻 C
字号:
/*
  V0.1 Initial Release   10/July/2006  RBR
  Port over Tmote        23/December/2006 RS
*/

#include "lrwpan_config.h"
#include "hal.h"
#include "halStack.h"
#include "clock_hal.h"
#include "console.h"
#include "debug.h"
#include "ieee_lrwpan_defs.h"
#include "memalloc.h"

#include <stdio.h>

static RADIO_FLAGS local_radio_flags;

static UINT16 radio_panid;
static SADDR radio_saddr;
static BYTE current_channel;  //channels 11 to 16

typedef enum _RADIO_STATE_ENUM {
  RADIO_STATE_OFF,
  RADIO_STATE_ON
}RADIO_STATE_ENUM;

RADIO_STATE_ENUM radio_state;

#ifdef LRWPAN_ASYNC_INTIO

static volatile BYTE serio_rxBuff[LRWPAN_ASYNC_RX_BUFSIZE];
static volatile BYTE serio_rxHead, serio_rxTail;

#endif

//halInit contains both processor specific initialization
void halInit(void){
    radio_state = RADIO_STATE_OFF;
	local_radio_flags.val = 0;
	halInitUart();		//set uart
	halInitMACTimer();	//set timer
}

//Uart init()...USART1 x USART0 for SPI
//we are going to initialize the console to single character
//input, and no echo to emulate the micro
void halInitUart(void) {
	
  /* RS232 */
  P3DIR &= ~0x80;			/* Select P37 for input (UART1RX) */
  P3DIR |= 0x40;			/* Select P36 for output (UART1TX) */
  P3SEL |= 0xC0;			/* Select P36,P37 for UART1{TX,RX} */

  UCTL1 = SWRST | CHAR;                 /* 8-bit character, UART mode */

/*   U1RCTL &= ~URXEIE;	/\* even erroneous characters trigger interrupts *\/ */

  UTCTL1 = SSEL1;	//SMCLK as source

  //halSetBaud(LRWPAN_DEFAULT_BAUDRATE);
  UBR01 = SMCLK_BAUD_57_6k_UBR0;
  UBR11 = SMCLK_BAUD_57_6k_UBR1;
  UMCTL1 = SMCLK_BAUD_57_6k_UMCTL;

  ME2 &= ~USPIE1;						/* USART1 SPI module disable */
  ME2 |= (UTXE1 | URXE1);               /* Enable USART1 TXD/RXD */

  UCTL1 &= ~SWRST;

  /* XXX Clear pending interrupts before enable!!! */

  IE2 |= URXIE1;                        /* Enable USART1 RX interrupt  */
  
#ifdef LRWPAN_ASYNC_INTIO
  serio_rxHead = 0;
  serio_rxTail = 0;
#endif

}

//TMote Sky: support just for ASYNC
#ifdef  LRWPAN_ASYNC_INTIO
//get a character from serial port, uses interrupt driven IO
char halGetch(void){
    while(serio_rxTail == serio_rxHead);
    serio_rxTail++;
   if (serio_rxTail == LRWPAN_ASYNC_RX_BUFSIZE) serio_rxTail = 0;
   return (serio_rxBuff[serio_rxTail]);
}

BOOL halGetchRdy(void){
 return(serio_rxTail != serio_rxHead);
 }

#endif

//write a character to serial port
//Uses UART initialized by halInitUart
void halPutch(char c){
  /* Loop until the transmission buffer is available. */
  while ((IFG2 & UTXIFG1) == 0);

  /* Transmit the data. */
  TXBUF1 = c;	
}

void halRawPut(char c){
  /* Loop until the transmission buffer is available. */
  while ((IFG2 & UTXIFG1) == 0);

  /* Transmit the data. */
  TXBUF1 = c;	
}

//MAC Init()
//defined such that timerA has a period of 1 symbol, or 16 us
//FOSC assumed to be some multiple of 4 MHZ
//Tmote Sky MCLK running at 4MHz
#define SYMBOL_FREQ  62500      //equals to symbols period of 16us

/*
 * Incremented after overflow of TimerA
 * TimerA...SMCLK/8...16us
 * interrupt after 2^16*16us=1s
 */
 
UINT16 halMacTimerOflow;

//TimerA used as MAC timer
//17012007...go for HW tick every 16us and check overflow for increment halMacTimerOflow
//This greatly release the uC
void halInitMACTimer(void) {
	/* DCO calibration */
	clock_hal_init();
	
	//For testing
	//RTC TimerB ... 0.5Hz...2s
	//Overflow...ACLK...Continous
	//TBCTL = TBSSEL_1 + MC_2 + TBIE;
	
	//Don't need this...I go with overflow
	/* Initialize ccr1 to create the X us interval. */
    /* CCR1 interrupt enabled, interrupt occurs when timer equals CCR1. */
	//TACCTL1 = CCIE;
	/* Interrupt after X us. */
	//TACCR1 = INTERVAL;
	
	//Older setting
	//TACTL = TBSSEL_2 + MC_2 + TAIE;
	
	/* start ticking */
	//Overflow...SMCLK/8=16us...Continous
	TACTL = TBSSEL_2 + ID_3 + MC_2 + TAIE;
	
	/* Keeping track of overflow */
	halMacTimerOflow=0;
}

void halShutdown(void){
//disable timer interrupts so that they don't wake us up
//Old approach
//	TACCR1 = 0;

	TACTL &= ~TAIE; 
    halDisableRadio();
}

void halWarmstart(void){
//enable timer interrupt
//Old approach
//  TACCTL1 = CCIE;
	TACTL |= TAIE;
}

//only works as long as SYMBOLS_PER_MAC_TICK is not less than 1
//TMote Sky...I use HW tick as indicator of 16us...SYMBOLS_PER_MAC_TICK=1
UINT32 halMacTicksToUs(UINT32 ticks){
   UINT32 rval; 
   rval =  (ticks/SYMBOLS_PER_MAC_TICK())* (1000000/LRWPAN_SYMBOLS_PER_SECOND);
   return(rval);
}

//read the macTimer, assumes interrupts, Timer0 are enabled!
//New: TMote Sky...I use HW tick in TAR as indicator of 16us
UINT32 halGetMACTimer(void)
{
   UINT8   iStatus;
   UINT32  rval;

   do {
   	 //Old
     //rval = halMacTimerOflow; //check if we're running
     
     //New 17012007
     rval = (UINT16) TAR;
     SAVE_AND_DISABLE_GLOBAL_INTERRUPT(iStatus);
     if (rval > 2) { //ok, trust that the Oflow byte is correctly incremented by ISR
       	break;
     }
   	 RESTORE_GLOBAL_INTERRUPT(iStatus) ;  //renable global interrupt, allow to tick some more
   }
   while(1);
    
   //at this point, global interrupts are disabled, read overflow value
   //Old
   //rval = halMacTimerOflow;
   
   //New 17012007
   rval  += ((UINT32) halMacTimerOflow) << 16;
   RESTORE_GLOBAL_INTERRUPT(iStatus);
   return (rval);
}

#ifdef LRWPAN_COMPILER_NO_RECURSION
UINT32 halISRGetMACTimer(void)
{
   UINT8   iStatus;
   UINT32  rval;

   do {
   	 //Old
     //rval = halMacTimerOflow; //check if we're running
     
     //New 17012007
     rval = (UINT16) TAR;
     SAVE_AND_DISABLE_GLOBAL_INTERRUPT(iStatus);
     if (rval > 2) { //ok, trust that the Oflow byte is correctly incremented by ISR
       	break;
     }
   	 RESTORE_GLOBAL_INTERRUPT(iStatus) ;  //renable global interrupt, allow to tick some more
   }
   while(1);
    
   //at this point, global interrupts are disabled, read overflow value
   //Old
   //rval = halMacTimerOflow;
   
   //New 17012007
   rval  += ((UINT32) halMacTimerOflow) << 16;
   RESTORE_GLOBAL_INTERRUPT(iStatus);
   return (rval);
}
#endif

UINT32 halMACTimerNowDelta(UINT32 x){
   UINT32 now;
   now = halGetMACTimer();
   now = (now - x);
   //TimerA is 16bit + I use UINT16 halMacTimerOflow = 32 bits
   //now = now & (UINT32) MACTIMER_MAX_VALUE;
   return(now);
}

void halUtilMemCopy(BYTE *dst, BYTE *src, BYTE len) {
	while (len) {
		*dst = *src;
		dst++;src++;
		len--;
	}
}

void halGetProcessorIEEEAddress(BYTE *buf) {

	buf[0] = aExtendedAddress_B0;
	buf[1] = aExtendedAddress_B1;
	buf[2] = aExtendedAddress_B2;
	buf[3] = aExtendedAddress_B3;
	buf[4] = aExtendedAddress_B4;
	buf[5] = aExtendedAddress_B5;
	buf[6] = aExtendedAddress_B6;
	buf[7] = aExtendedAddress_B7;
}

//ms precision
void halWaitMs(UINT32 msecs){	UINT16	i, j, cnt;
    cnt = msecs;	do {		i = 20;		do {
			j = TAR;
			while((TAR - j) <= 2);		} while(--i);	} while(--cnt);}

//us precision
void halWaitUs(UINT16 usecs) 
{ 
  UINT16 i;
  if (usecs < 500)
    for (i=2; i < usecs; i++) { 
      asm volatile("nop\n\t"
                   "nop\n\t"
                   "nop\n\t"
                   "nop\n\t"
                   ::);
    }
  else
    for (i=0; i < usecs; i++) { 
      asm volatile("nop\n\t"
                   "nop\n\t"
                   "nop\n\t"
                   "nop\n\t"
                   ::);
    }
}

//just for demo
void halIdle(void) {
  NOP();
  //TODO: it could go to sleep mode over here???
}

//sleeps for the duration of the of the watchdog timer timeout
//just for demo
void halSleep(UINT32 msecs) {
	//WDT_ADLY_1000;
	//WDT_ADLY_250;
	//WDT_ADLY_16;
	//WDT_ADLY_1_9;
	
  	WDTCTL = WDT_ADLY_1000;                   // WDT 1s, ACLK, interval timer
  	IE1 |= WDTIE;                             // Enable WDT interrupt
  	_BIS_SR(LPM1_bits + GIE);                 // Enter LPM1 w/interrupt
}

//ISR stuff
//UART receive
interrupt(UART1RX_VECTOR) uart1_intr(void) {
/* Check status register for receive errors. */
  if (URCTL1 & RXERR) {
    volatile unsigned dummy;
    dummy = RXBUF1;   /* Clear error flags by forcing a dummy read. */
  } else {
#ifdef  LRWPAN_ASYNC_INTIO
     serio_rxHead++;
     if (serio_rxHead == LRWPAN_ASYNC_RX_BUFSIZE ) serio_rxHead = 0;
     serio_rxBuff[serio_rxHead] = RXBUF1;
#endif
  }
}

// MAC Timer
// Timer_A3 Interrupt Vector Handler
interrupt(TIMERA1_VECTOR) timera1 (void) {
 
/*
 * 17012007
 * New approach...look for overflow 
 * 
 */
  
 switch(TAIV) {
   case 0x02: break;                          // CCR1 not used
   case 0x04: break;                          // CCR2 not used
   case 0x0A: { halMacTimerOflow++; break; }  // overflow
  }
  
  //Callback for receiving packets
  //Let's see if TMote can handle this...not sure about it
  //Trying to use interrupt priority...see PORT1_VECTOR below
  //evbRadioIntCallback();
 
/* not yet implemented  
#ifdef LRWPAN_ENABLE_SLOW_TIMER
     evbIntCallback();  // call evb 
     usrSlowTimerInt(); // call the usrInterrupt
#endif
*/
}

interrupt(PORT1_VECTOR) fifop (void) {
	//receiving packets
	//led_blue_toggle();
  	evbRadioIntCallback();
  	//TODO: it could go to sleep mode over here???
}

// Timer_B7 Interrupt Vector (TBIV) handler
interrupt(TIMERB1_VECTOR) timerb1 (void) {	
 switch( TBIV )
 {
   case  0x02: break;                          // CCR1 not used
   case  0x04: break;                          // CCR2 not used
   case  0x0E: {   	//conPrintUINT32(halMacTimerOflow);
					//conPrintROMString("\n");
					break;
    		    } 	// overflow
  }
}

// Watchdog Timer interrupt service routine
interrupt(WDT_VECTOR) watchdog_timer(void) {
//exit from sleep mode
  IE1 &= ~WDTIE;
  DISABLE_WDT();
  LPM1_EXIT;
  //led_red_toggle();
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -