There has been alot of interest in Wake-On-Radio. But very little useful code to implement it.
Here is a working example / template for a wake on radio project.
You can download the complete project here: http://mtaylor.ca/home/e107_files/public/1273603830_2_FT0_wor.example.zip
The code supplied for the Access Point has a complete GUI menu.
Program one device with the AP code and open up Hyperterminal / Putty.
Press 'M' to bring up the GUI menu.
This is what you will see:
What would you like to do?
(0) Wake Up Device
(1) Toggle LEDs
(2) Turn Device Off
Pressing '0' will send the wake up command which is a stream of packets containing the code 65.
The green LED will be on while its sending the packets. Packets should be sent for 2x the WOR interval.
The ED will now be on and you will see that both of its LEDs are on. Press '1' to toggle the LEDs.
Pressing '2' will turn the LEDs off and place the ED back into sleep mode.
The End Device has a very simple function. Program it and connect it to the battery pack.
The ED will wake up every 1884 ms. To adjust this time, change the values of WOREVT1 and WOREVT0.
To determine what values to use, simply plug the desired delay into the Excel calculator.
When the ED wakes up it checks to make sure the packet recieved contains code 65. To ensure it is the wakeup command.
The LED is then turned on. Further packets containing the message 'TEST' will cause the LED to change state.
When the 'STOP' packet is recieved, WOR mode is re-enabled.
Note: both devices need to be set to the same channel to allow communication. Changing channels allows you to use multiple devices at the same time.
End Device Code:
//-------End
Device Code--------- //---------Matt Taylor----------- #include "msp430x22x4.h" #include "radios/family1/mrfi_spi.h" #include "mrfi.h" //Global Variables int i; int WOR_Enabled=1; //Controls whether WakeOnRadio is ON (1) or OFF (0) //Function Prototypes void MCU_Init(void); void packetHandling(mrfiPacket_t packet); //Determines appropriate action for recieved packet //WOR Code from Thomas Watteyne's Tutorial void wor_init(); void wor_start(); void wor_stop(); //-------------------------MAIN------------------------------------------------- void main(void) { WDTCTL = WDTPW + WDTHOLD; //Stop WDT MCU_Init(); //---------------------Start Wakeup Protocol---------- //--------------------Code from Chat program---------- BSP_Init(); MRFI_Init(); int channel=20; //Channels from 0 to 200 MRFI_WakeUp(); MRFI_RxIdle(); mrfiSpiWriteReg(CHANNR,channel); MRFI_RxOn(); P1DIR |= 0x03; //---------------------Start Wakeup Protocol---------- if (WOR_Enabled==1) { wor_init(); wor_start(); char output[] = {"\r\nDevice set to channel: 20 \r\nEntering Sleep Mode"}; TXString(output, (sizeof output)-1); } if (WOR_Enabled==0) { char output[] = {"\r\nDevice Ready"}; TXString(output, (sizeof output)-1); } __bis_SR_register(GIE+LPM4_bits); //---------------------------------------------------- }//end main //-------------------------MCU INITIATE----------------------------------------- void MCU_Init() { BCSCTL1 = CALBC1_8MHZ; //Set DCO DCOCTL = CALDCO_8MHZ; BCSCTL3 |= LFXT1S_2; //LFXT1 = VLO TACCTL0 = CCIE; //TACCR0 interrupt enabled TACCR0 = 12000; //~1 second TACTL = TASSEL_1 + MC_1; //ACLK, upmode P3SEL |= 0x30; //P3.4,5 = USCI_A0 TXD/RXD UCA0CTL1 = UCSSEL_2; //SMCLK UCA0BR0 = 0x41; //9600 from 8Mhz UCA0BR1 = 0x3; UCA0MCTL = UCBRS_2; UCA0CTL1 &= ~UCSWRST; //**Initialize USCI state machine** IE2 |= UCA0RXIE; //Enable USCI_A0 RX interrupt __enable_interrupt(); } //--------------------------PACKET RECEIVING------------------------------------ void MRFI_RxCompleteISR() { mrfiPacket_t packet; if (WOR_Enabled==1) wor_stop(); MRFI_Receive(&packet); char received[] = {"\r\nWakeUP received"}; //If the device is currently sleeping, check if the incoming packet contains the wakeup code (65) if (WOR_Enabled==1) { if ((MRFI_P_PAYLOAD(&packet))[2]==65) { TXString(received, (sizeof received)-1); WOR_Enabled=0; main(); //Restart main program with WOR disabled } else { MRFI_WakeUp(); MRFI_RxOn(); } } else //Wake on radio has been disabled { packetHandling(packet); //Determine action } } //------------------DETERMINE ACTION BASED ON COMMAND PACKET-------------------- void packetHandling(mrfiPacket_t packet) { for (int i=9;i<29;i++) //Cycle through the Packet { if (packet.frame[i-3]=='T' && packet.frame[i-2]=='E' && packet.frame[i-1]=='S' && packet.frame[i]=='T') P1OUT ^= 0x03; if (packet.frame[i-3]=='S' && packet.frame[i-2]=='T' && packet.frame[i-1]=='O' && packet.frame[i]=='P') { P1OUT&=~0x03; //LED OFF WOR_Enabled=1; MCU_Init(); wor_init(); wor_start(); //Restart program with WOR enabled } } //end for } //--------------------------WAKE ON RADIO FUNCTIONS----------------------------- void wor_init() { uint8_t reg; //Change the values of WOREVT1 and WOREVT0 to adjust the WOR interval //FFFA = 1884ms mrfiSpiWriteReg(WOREVT1, 0xFF); mrfiSpiWriteReg(WOREVT0, 0xFA); /* choose EVENT1[WORCTRL.6-4] == 7=0b111 */ reg = mrfiSpiReadReg(WORCTRL); reg |= 0x70; mrfiSpiWriteReg(WORCTRL, reg); /* enable frequence calibration RC_CAL[WORCTRL.3] == 1 */ reg = mrfiSpiReadReg(WORCTRL); reg |= 0x80; mrfiSpiWriteReg(WORCTRL, reg); /* choose WOR_RES[WORCTRL.1-0] == 00 */ reg = mrfiSpiReadReg(WORCTRL); reg &= ~0x03; mrfiSpiWriteReg(WORCTRL, reg); /* choose when to calibrate FS_AUTOCAL[MCSM0.5-4] == 01 */ reg = mrfiSpiReadReg(MCSM0); reg &= ~0x20; reg |= 0x10; mrfiSpiWriteReg(MCSM0, reg); /* initial filter by rssi RX_TIME_RSSI[MCSM2.4] == 0 */ reg = mrfiSpiReadReg(MCSM2); reg &= ~0x10; mrfiSpiWriteReg(MCSM2, reg); /* stay in Rx after preamble RX_TIME_QUAL[MCSM2.3] == 0 */ reg = mrfiSpiReadReg(MCSM2); reg &= ~0x08; mrfiSpiWriteReg(MCSM2, reg); /* enable RC oscilator RC_PD[WORCTRL.7] == 0 */ reg = mrfiSpiReadReg(WORCTRL); reg &= ~0x80; mrfiSpiWriteReg(WORCTRL, reg); /* assert GDO2 at SYNC GDO2_CFG[IOCFG2.5-0] == 0x06 */ mrfiSpiWriteReg(IOCFG2, 0x06); //P14=SYNC } void wor_start() { /* choose RX_TIME[MCSM2.2-0] == 2=0b010 */ uint8_t reg = mrfiSpiReadReg(MCSM2); reg &= ~0x05; reg |= 0x02; //mrfiSpiWriteReg(MCSM2, reg);//test mrfiSpiWriteReg(MCSM2, 2);//test /* from IDLE state, enter WOR */ MRFI_RxIdle(); MRFI_RxWor(); } void wor_stop() { /* choose RX_TIME[MCSM2.2-0] == 7=0b111 */ uint8_t reg = mrfiSpiReadReg(MCSM2); reg |= 0x07; //mrfiSpiWriteReg(MCSM2,reg); mrfiSpiWriteReg(MCSM2,7);//test /* turn radio to IDLE, quitting WOR*/ MRFI_RxIdle(); } |
Access Point Code:
//----Access Point Code---- //---------Matt Taylor----------- #include "msp430x22x4.h" #include "radios/family1/mrfi_spi.h" #include "mrfi.h" //Packets mrfiPacket_t wake_packet; mrfiPacket_t stop_packet; mrfiPacket_t packet; //Function Prototypes void GuiMenu(); void handleKeyboard(char); //Function to determine commands based on keystroke void wakeOnRadio(); //Function to wakeup the radio //-------------------------------MAIN------------------------------------------- int main(void) { BSP_Init(); MRFI_Init(); P3SEL |= 0x30; //P3.4,5 = USCI_A0 TXD/RXD UCA0CTL1 = UCSSEL_2; //SMCLK UCA0BR0 = 0x41; //9600 from 8Mhz UCA0BR1 = 0x3; UCA0MCTL = UCBRS_2; UCA0CTL1 &= ~UCSWRST; //Initialize USCI state machine IE2 |= UCA0RXIE; //Enable USCI_A0 RX interrupt int channel=20; //Channels from 0 to 200 MRFI_WakeUp(); MRFI_RxIdle(); mrfiSpiWriteReg(CHANNR,channel); MRFI_RxOn(); P1DIR |= 0x03; //LED outputs //--Clear Screen-- for (int i=0; i<15; i++) { TXString("\r\n",2); } GuiMenu(); __bis_SR_register(GIE+LPM4_bits); } //--------------------KEYBOARD INTERUPTS---------------------------------------- #pragma vector=USCIAB0RX_VECTOR __interrupt void USCI0RX_ISR(void) { char keystroke = UCA0RXBUF; //Capture keystroke handleKeyboard(keystroke); //GUI option } //--------------------------PACKET RECEIVING------------------------------------ void MRFI_RxCompleteISR() { uint8_t i; MRFI_Receive(&packet); char output[] = {" "}; for (i=9;i<29;i++) { output[i-9]=packet.frame[i]; } TXString(output, (sizeof output)); } void GuiMenu() { P1OUT &= ~0x03; //LEDs off //--Output GUI options-- TXString( "\r\nWhat would you like to do?", 30 ); TXString( "\r\n (0) Wake Up Device", 22 ); TXString( "\r\n (1) Toggle LEDs", 20 ); TXString( "\r\n (2) Turn Device Off", 22 ); TXString( "\r\n", 3 ); } //-----------------CONVERT KEYSTROKE TO COMMAND--------------------------------- void handleKeyboard(char keystroke) { int i=0; //----------------------Setup Packets---------------------- wake_packet.frame[0]=28; stop_packet.frame[0]=28; for(i=9;i<29;i++) { wake_packet.frame[i]=' '; stop_packet.frame[i]=' '; } wake_packet.frame[9]='T'; wake_packet.frame[10]='E'; wake_packet.frame[11]='S'; wake_packet.frame[12]='T'; stop_packet.frame[9]='S'; stop_packet.frame[10]='T'; stop_packet.frame[11]='O'; stop_packet.frame[12]='P'; //------------------------------------------------------- if (keystroke=='m' || keystroke=='M') { GuiMenu(); } if (keystroke=='0') { wakeOnRadio(); for (i=0;i<5000;i++) { __no_operation(); } //Delay for a bit MRFI_Transmit(&wake_packet, MRFI_TX_TYPE_FORCED); //Check if its ready } if (keystroke=='1') { MRFI_Transmit(&wake_packet, MRFI_TX_TYPE_FORCED); P1OUT ^= 0x01; for (i=0;i<3000;i++) { __no_operation(); } P1OUT ^= 0x01; } if (keystroke=='2') { P1OUT |= 0x01; for (i=0;i<30;i++){ //transmit stop packet a few times MRFI_Transmit(&stop_packet, MRFI_TX_TYPE_FORCED); } P1OUT&=~0x01; } } //------------------SEND WAKEUP COMMAND---------------------------------------- void wakeOnRadio() //Sends a mass amount of packets to wakeup ED { P1IFG &= ~0x04; int counter; mrfiPacket_t packetToSend; MRFI_SET_PAYLOAD_LEN((&packetToSend),20); P1OUT ^= 0x02; for (counter=1000;counter>=1;counter--) { (MRFI_P_PAYLOAD(&packetToSend))[2] = 65; MRFI_Transmit(&packetToSend, MRFI_TX_TYPE_FORCED); } P1OUT ^= 0x02; } |