Move default pins over to Getting Started defaults
[RF24-C.git] / examples / pingpair_sleepy / pingpair_sleepy.pde
blob809679e5445bfad8f07b9cc81588b6e349839bc3
1 /*
2  Copyright (C) 2011 James Coliz, Jr. <maniacbug@ymail.com>
4  This program is free software; you can redistribute it and/or
5  modify it under the terms of the GNU General Public License
6  version 2 as published by the Free Software Foundation.
7  */
9 /**
10  * Example RF Radio Ping Pair which Sleeps between Sends
11  *
12  * This is an example of how to use the RF24 class to create a battery-
13  * efficient system.  It is just like the pingpair.pde example, but the
14  * ping node powers down the radio and sleeps the MCU after every
15  * ping/pong cycle.
16  *
17  * As with the pingpair.pde example, write this sketch to two different nodes,
18  * connect the role_pin to ground on one.  The ping node sends the current
19  * time to the pong node, which responds by sending the value back.  The ping
20  * node can then see how long the whole cycle took.
21  */
23 #include <SPI.h>
24 #include <avr/sleep.h>
25 #include <avr/power.h>
26 #include "nRF24L01.h"
27 #include "RF24.h"
28 #include "printf.h"
31 // Hardware configuration
34 // Set up nRF24L01 radio on SPI bus plus pins 8 & 9
36 RF24 radio(9,10);
38 // sets the role of this unit in hardware.  Connect to GND to be the 'pong' receiver
39 // Leave open to be the 'ping' transmitter
40 const int role_pin = 7;
43 // Topology
46 // Radio pipe addresses for the 2 nodes to communicate.
47 const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
50 // Role management
52 // Set up role.  This sketch uses the same software for all the nodes
53 // in this system.  Doing so greatly simplifies testing.  The hardware itself specifies
54 // which node it is.
56 // This is done through the role_pin
59 // The various roles supported by this sketch
60 typedef enum { role_ping_out = 1, role_pong_back } role_e;
62 // The debug-friendly names of those roles
63 const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"};
65 // The role of the current running sketch
66 role_e role;
69 // Sleep declarations
72 typedef enum { wdt_16ms = 0, wdt_32ms, wdt_64ms, wdt_128ms, wdt_250ms, wdt_500ms, wdt_1s, wdt_2s, wdt_4s, wdt_8s } wdt_prescalar_e;
74 void setup_watchdog(uint8_t prescalar);
75 void do_sleep(void);
77 const short sleep_cycles_per_transmission = 4;
78 volatile short sleep_cycles_remaining = sleep_cycles_per_transmission;
81 // Normal operation
84 void setup(void)
86   //
87   // Role
88   //
90   // set up the role pin
91   pinMode(role_pin, INPUT);
92   digitalWrite(role_pin,HIGH);
93   delay(20); // Just to get a solid reading on the role pin
95   // read the address pin, establish our role
96   if ( digitalRead(role_pin) )
97     role = role_ping_out;
98   else
99     role = role_pong_back;
101   //
102   // Print preamble
103   //
105   Serial.begin(57600);
106   printf_begin();
107   printf("\n\rRF24/examples/pingpair_sleepy/\n\r");
108   printf("ROLE: %s\n\r",role_friendly_name[role]);
110   //
111   // Prepare sleep parameters
112   //
114   // Only the ping out role sleeps.  Wake up every 4s to send a ping
115   if ( role == role_ping_out )
116     setup_watchdog(wdt_1s);
118   //
119   // Setup and configure rf radio
120   //
122   radio.begin();
124   //
125   // Open pipes to other nodes for communication
126   //
128   // This simple sketch opens two pipes for these two nodes to communicate
129   // back and forth.
130   // Open 'our' pipe for writing
131   // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading)
133   if ( role == role_ping_out )
134   {
135     radio.openWritingPipe(pipes[0]);
136     radio.openReadingPipe(1,pipes[1]);
137   }
138   else
139   {
140     radio.openWritingPipe(pipes[1]);
141     radio.openReadingPipe(1,pipes[0]);
142   }
144   //
145   // Start listening
146   //
148   radio.startListening();
150   //
151   // Dump the configuration of the rf unit for debugging
152   //
154   radio.printDetails();
157 void loop(void)
159   //
160   // Ping out role.  Repeatedly send the current time
161   //
163   if (role == role_ping_out)
164   {
165     // First, stop listening so we can talk.
166     radio.stopListening();
168     // Take the time, and send it.  This will block until complete
169     unsigned long time = millis();
170     printf("Now sending %lu...",time);
171     radio.write( &time, sizeof(unsigned long) );
173     // Now, continue listening
174     radio.startListening();
176     // Wait here until we get a response, or timeout (250ms)
177     unsigned long started_waiting_at = millis();
178     bool timeout = false;
179     while ( ! radio.available() && ! timeout )
180       if (millis() - started_waiting_at > 250 )
181         timeout = true;
183     // Describe the results
184     if ( timeout )
185     {
186       printf("Failed, response timed out.\n\r");
187     }
188     else
189     {
190       // Grab the response, compare, and send to debugging spew
191       unsigned long got_time;
192       radio.read( &got_time, sizeof(unsigned long) );
194       // Spew it
195       printf("Got response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time);
196     }
198     //
199     // Shut down the system
200     //
202     // Experiment with some delay here to see if it has an effect
203     delay(500);
205     // Power down the radio.  Note that the radio will get powered back up
206     // on the next write() call.
207     radio.powerDown();
209     // Sleep the MCU.  The watchdog timer will awaken in a short while, and
210     // continue execution here.
211     while( sleep_cycles_remaining )
212       do_sleep();
214     sleep_cycles_remaining = sleep_cycles_per_transmission;
215   }
217   //
218   // Pong back role.  Receive each packet, dump it out, and send it back
219   //
220   // This is untouched from the pingpair example.
221   //
223   if ( role == role_pong_back )
224   {
225     // if there is data ready
226     if ( radio.available() )
227     {
228       // Dump the payloads until we've gotten everything
229       unsigned long got_time;
230       bool done = false;
231       while (!done)
232       {
233         // Fetch the payload, and see if this was the last one.
234         done = radio.read( &got_time, sizeof(unsigned long) );
236         // Spew it.  Include our time, because the ping_out millis counter is unreliable
237         // due to it sleeping
238         printf("Got payload %lu @ %lu...",got_time,millis());
239       }
241       // First, stop listening so we can talk
242       radio.stopListening();
244       // Send the final one back.
245       radio.write( &got_time, sizeof(unsigned long) );
246       printf("Sent response.\n\r");
248       // Now, resume listening so we catch the next packets.
249       radio.startListening();
250     }
251   }
255 // Sleep helpers
258 // 0=16ms, 1=32ms,2=64ms,3=125ms,4=250ms,5=500ms
259 // 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
261 void setup_watchdog(uint8_t prescalar)
263   prescalar = min(9,prescalar);
264   uint8_t wdtcsr = prescalar & 7;
265   if ( prescalar & 8 )
266     wdtcsr |= _BV(WDP3);
268   MCUSR &= ~_BV(WDRF);
269   WDTCSR = _BV(WDCE) | _BV(WDE);
270   WDTCSR = _BV(WDCE) | wdtcsr | _BV(WDIE);
273 ISR(WDT_vect)
275   --sleep_cycles_remaining;
278 void do_sleep(void)
280   set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
281   sleep_enable();
283   sleep_mode();                        // System sleeps here
285   sleep_disable();                     // System continues execution here when watchdog timed out
288 // vim:ai:cin:sts=2 sw=2 ft=cpp