📄 halstack.c
字号:
/*
V0.1 Initial Release 10/July/2006
*/
#include "hal.h"
#include "halStack.h"
#include "console.h"
#include "debug.h"
#include "ieee_lrwpan_defs.h"
#include "memalloc.h"
#include "phy.h"
#include "mac.h"
/*
V0.2.2.
8/2/2006 Fixed problem with checking of CRC byte.
*/
RADIO_FLAGS local_radio_flags;
#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){
//Set clock source
local_radio_flags.val = 0;
SET_MAIN_CLOCK_SOURCE(CRYSTAL);
halInitUart();
halSetBaud(LRWPAN_DEFAULT_BAUDRATE);
halInitMACTimer();
}
//initialize UART to be used by
void halInitUart(void) {
// Setup for UART0
IO_PER_LOC_UART0_AT_PORT0_PIN2345();
UTX0IF = 1;
#ifdef LRWPAN_ASYNC_INTIO
serio_rxHead = 0;
serio_rxTail = 0;
INT_ENABLE_URX0(INT_ON);
#endif
}
#ifdef LRWPAN_ASYNC_INTIO
//get a character from serial port, uses interrupt driven IO
char halGetch(void){
char x;
do {
x = serio_rxHead; //use tmp because of volt decl
} while(serio_rxTail == x);
serio_rxTail++;
if (serio_rxTail == LRWPAN_ASYNC_RX_BUFSIZE) serio_rxTail = 0;
return (serio_rxBuff[serio_rxTail]);
}
BOOL halGetchRdy(void){
char x;
x = serio_rxHead;
return(serio_rxTail != x);
}
#else
//get a character from serial port
char halGetch(void){
char c;
while (!URX0IF);
c = U0DBUF;
URX0IF = FALSE;
return c;
}
BOOL halGetchRdy(void){
if (URX0IF) return (1);
else return(0);
}
#endif
void halUtilMemCopy(BYTE *dst, BYTE *src, BYTE len) {
while (len) {
*dst = *src;
dst++;src++;
len--;
}
}
// assuming 16us period, have 1/16us = 62500 tics per seocnd
#define T2CMPVAL (62500/SLOWTICKS_PER_SECOND)
//use timer2, will set it up for one tick per symbol
//assuming 2.4GHZ and a 32 MHZ clock.
// this is a 20 bit counter, will overflow in ~16 seconds
//should be long enough for MAC timeout cases
void halInitMACTimer(void) {
T2CNF = 0x00; //ensure timer is idle
T2CAPHPH = 0x02; // setting for 16 u-second periods
T2CAPLPL = 0x00; // (0x0200) / 32 = 16 u-seconds
//set the interrupt compare to its maximum value
#ifdef LRWPAN_ENABLE_SLOW_TIMER
T2PEROF0 = 0xFF & (T2CMPVAL);
T2PEROF1 = (BYTE) (T2CMPVAL>>8);
//enable overflow count compare interrupt
T2PEROF2 = ((BYTE) (T2CMPVAL>>16)) | 0x20;
#endif
//turn on timer
//configure timer
T2CNF = 0x03; //start timer
INT_SETFLAG_T2(INT_CLR); //clear processor interrupt flag
//enable T2 processor interrupt
#ifdef LRWPAN_ENABLE_SLOW_TIMER
INT_ENABLE_T2(INT_ON);
#endif
}
UINT32 halGetMACTimer(void){
UINT32 t;
BOOL gie_status;
SAVE_AND_DISABLE_GLOBAL_INTERRUPT(gie_status);
t = 0x0FF & T2OF0;
t += (((UINT16)T2OF1)<<8);
t += (((UINT32) T2OF2 & 0x0F)<<16);
RESTORE_GLOBAL_INTERRUPT(gie_status);
return (t);
}
#ifdef LRWPAN_COMPILER_NO_RECURSION
UINT32 halISRGetMACTimer(void){
UINT32 t;
BOOL gie_status;
SAVE_AND_DISABLE_GLOBAL_INTERRUPT(gie_status);
t = 0x0FF & T2OF0;
t += (((UINT16)T2OF1)<<8);
t += (((UINT32) T2OF2 & 0x0F)<<16);
RESTORE_GLOBAL_INTERRUPT(gie_status);
return (t);
}
#endif
//only works as long as SYMBOLS_PER_MAC_TICK is not less than 1
UINT32 halMacTicksToUs(UINT32 ticks){
UINT32 rval;
rval = (ticks/SYMBOLS_PER_MAC_TICK())* (1000000/LRWPAN_SYMBOLS_PER_SECOND);
return(rval);
}
//assumes that Timer2 has been initialized and is running
UINT8 halGetRandomByte(void) {
return(T2OF0);
}
//write a character to serial port
// Uses UART initialized by halInitUart
void halPutch(char c){
while (!UTX0IF);
UTX0IF = 0;
U0DBUF = c;
}
void halRawPut(char c){
while (!UTX0IF);
UTX0IF = 0;
U0DBUF = c;
}
//set the radio frequency
LRWPAN_STATUS_ENUM halSetRadioIEEEFrequency(PHY_FREQ_ENUM frequency, BYTE channel)
{
UINT16 afreq;
if (frequency != PHY_FREQ_2405M) return(LRWPAN_STATUS_PHY_FAILED);
if ((channel < 11) || (channel > 26)) return(LRWPAN_STATUS_PHY_FAILED);
afreq = 357 + 5*(channel - 11);
FSCTRLL = (BYTE) afreq;
FSCTRLH = ((FSCTRLH & ~0x03) | (BYTE)((afreq >> 8) & 0x03));
return(LRWPAN_STATUS_SUCCESS);
}
//this assumes 2.4GHz frequency
LRWPAN_STATUS_ENUM halSetChannel(BYTE channel){
return(halSetRadioIEEEFrequency(PHY_FREQ_2405M, channel));
}
#if defined(IAR8051)
//this uses the IEEE address stored in program memory.
//ensure that the flash programmer is configured to retain
//the IEEE address
void halGetProcessorIEEEAddress(BYTE *buf) {
#if (CC2430_FLASH_SIZE == 128)
unsigned char bank;
bank = MEMCTR;
//switch to bank 3
MEMCTR |= 0x30;
#endif
//note that the flash programmer stores these in BIG ENDIAN order for some reason!!!
buf[7] = *(ROMCHAR *)(IEEE_ADDRESS_ARRAY+0);
buf[6] = *(ROMCHAR *)(IEEE_ADDRESS_ARRAY+1);
buf[5] = *(ROMCHAR *)(IEEE_ADDRESS_ARRAY+2);
buf[4] = *(ROMCHAR *)(IEEE_ADDRESS_ARRAY+3);
buf[3] = *(ROMCHAR *)(IEEE_ADDRESS_ARRAY+4);
buf[2] = *(ROMCHAR *)(IEEE_ADDRESS_ARRAY+5);
buf[1] = *(ROMCHAR *)(IEEE_ADDRESS_ARRAY+6);
buf[0] = *(ROMCHAR *)(IEEE_ADDRESS_ARRAY+7);
#if (CC2430_FLASH_SIZE == 128)
//resore old bank settings
MEMCTR = bank;
#endif
}
#endif
#if defined(HI_TECH_C)
//cannot figure out how to get the Hi-Tech C51 compiler to support
//banking, so can't access the IEEE address stored in memory
//use this if you don't want to use the IEEE Address stored in program memory
//by the flash memory
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;
}
#endif
void halSetRadioIEEEAddress(void) {
BYTE buf[8];
halGetProcessorIEEEAddress(buf);
IEEE_ADDR0 = buf[0];
IEEE_ADDR1 = buf[1];
IEEE_ADDR2 = buf[2];
IEEE_ADDR3 = buf[3];
IEEE_ADDR4 = buf[4];
IEEE_ADDR5 = buf[5];
IEEE_ADDR6 = buf[6];
IEEE_ADDR7 = buf[7];
}
void halSetRadioPANID(UINT16 panid){
PANIDL = (BYTE) (panid);
PANIDH = (BYTE) (panid>>8);
}
void halSetRadioShortAddr(SADDR saddr){
SHORTADDRL = (BYTE) (saddr);
SHORTADDRH = (BYTE) (saddr>>8);
}
//return value of non-zero indicates failure
//Turn on Radio, initialize for RF mode
//assumes that auto-ack is enabled
//this function based on sppInit example from ChipCon
//also sets the IEEE address
//if listen_flag is true, then radio is configured for
//listen only (no auto-ack, no address recognition)
/*
Eventually, change this so that auto-ack can be configured as
on or off. When Coordinator is trying to start a network,
auto-ack, addr decoding will be off as Coordinator will be doing an energy
scan and detecting PAN collisions, and thus will not be doing
any acking of packets. After the network is started, then
will enable auto-acking.
Routers and End devices will always auto-ack
i
*/
LRWPAN_STATUS_ENUM halInitRadio(PHY_FREQ_ENUM frequency, BYTE channel, RADIO_FLAGS radio_flags)
{
LRWPAN_STATUS_ENUM status;
// Setting the frequency
status = halSetRadioIEEEFrequency(frequency, channel);
if (status != LRWPAN_STATUS_SUCCESS) return(status);
//turning on power to analog part of radio and waiting for voltage regulator.
RFPWR = 0x04;
while((RFPWR & 0x10)){}
//radio_flags.listen_mode=1; //debug
if (radio_flags.bits.listen_mode) {
//corresponds to promiscuous modes
//radio accepts all packets, the HUSSY!
MDMCTRL0H &= ~ADR_DECODE; //no address decode
MDMCTRL0L &= ~AUTO_ACK; //no auto ack
} else {
// Turning on Address Decoding
MDMCTRL0H |= ADR_DECODE;
//enable auto_ack
MDMCTRL0L |= AUTO_ACK;
}
local_radio_flags = radio_flags; //save this for later
// Setting for AUTO CRC
MDMCTRL0L |= AUTO_CRC;
//pan
if (radio_flags.bits.pan_coordinator) {
MDMCTRL0H |= PAN_COORDINATOR; //accepts frames with only source addressing modes
} else {
MDMCTRL0H &= ~PAN_COORDINATOR; //rejects frames with only source addressing modes
}
// Turning on AUTO_TX2RX
FSMTC1 = ((FSMTC1 & (~AUTO_TX2RX_OFF & ~RX2RX_TIME_OFF)) | ACCEPT_ACKPKT);
// Turning off abortRxOnSrxon.
FSMTC1 &= ~0x20;
//now configure the RX, TX systems.
// Setting the number of bytes to assert the FIFOP flag
IOCFG0 = 127; //set to max value as the FIFOP flag goes high when complete packet received
// Flushing both Tx and Rx FiFo. The flush-Rx is issued twice to reset the SFD.
// Calibrating the radio and turning on Rx to evaluate the CCA.
SRXON;
SFLUSHTX;
SFLUSHRX;
SFLUSHRX;
STXCALN;
ISSTART;
//this controls the frame pending bit in ACK frames.
//because of auto-ack, we will not have time to determine if data
//is actually pending or not.
#if defined(LWRPAN_RFD)
SACK; //RFDs never have data pending for FFDs
#else
SACKPEND; //routers/
#endif
halSetRadioIEEEAddress();
//Radio can interrupt when
//RX configuration
//clear flags/mask in radio
RFIF = 0;
RFIM = 0; //all interrupts are masked.
//enable RX interrupt on processor
INT_SETFLAG_RF(INT_CLR);
INT_ENABLE_RF(INT_ON);
//enable RX RFERR interrupt on processor
INT_SETFLAG_RFERR(INT_CLR);
INT_ENABLE_RFERR(INT_ON);
//do not use DMA at this point
//enable the RX receive interrupt here.
RFIM |= IRQ_FIFOP;
return(LRWPAN_STATUS_SUCCESS);
}
#define PIN_CCA CCA //CCA is defined in hal.h
//regardless of what happens here, we will try TXONCCA after this returns.
void doIEEE_backoff(void) {
BYTE be, nb, tmp, rannum;
UINT32 delay, start_tick;
be = aMinBE;
nb = 0;
do {
if (be) {
//do random delay
tmp = be;
//compute new delay
delay = 1;
while (tmp) {
delay = delay << 1; //delay = 2**be;
tmp--;
}
rannum = halGetRandomByte() & (delay-1); //rannum will be between 0 and delay-1
delay = 0;
while (rannum) {
delay += SYMBOLS_TO_MACTICKS(aUnitBackoffPeriod);
rannum--;
}//delay = aUnitBackoff * rannum
//now do backoff
start_tick = halGetMACTimer();
while (halMACTimerNowDelta(start_tick) < delay);
}
//check CCA
if (PIN_CCA) break;
nb++;
be++;
if (be > aMaxBE) be =aMaxBE;
}while (nb <= macMaxCSMABackoffs);
return;
}
//transmit packet
//hdrlen - header lenth
//hdr - pointer to header data
//plen - payload length
//pload - pointer to payload
LRWPAN_STATUS_ENUM halSendPacket(BYTE flen, BYTE *frm)
{
BYTE len;
LRWPAN_STATUS_ENUM res;
//if you print out the packet, this can cause timeouts on waits
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -