Docs

Documentation page

Doc General

General/overview

The RFXduino (“Radio For X:duino”) gateway is a dedicated embedded Linux (Raspberry Pi) server “hub” that connects multiple nRF24L01+ radio equipped X:duino (i.e., Arduino or Arduino-like) embedded devices to an ethernet LAN, and thereby the Internet, each with its own virtual serial connection.

One RFXduino gateway serves up 255 nRF24L01+ equipped Arduino/X:duino boards. So each Arduino/X:duino project can communicate via it’s own TCP/IP serial connection over LAN/Internet as simply as using the familiar “Serial” library commands “Serial.print()”, “Serial.read()” etc. Your Arduino/X:duino can serve webpages, send emails, send tweets, send SMS via web APIs, POST data to Xively, and so on, wirelessly via an economical nRF24L01+ module.

RFXduino is designed to be a cost-effective alternative to expensive WiFi shields, BT, Xbee radios etc. that are often used when wirelessly connecting Arduino/Arduino-like embedded devices to a network.

RFXduino uses Nordic’s nRF24L01+ radios because of their flexibility and cost-effectiveness. A low power nRF24L01+ radio can be added to a project for less than $3, and a high powered version for less than $10.

Natively, the nRF24L01+ is a packet device, designed to send up to 32 bytes of data at a time in short burst messages. Unlike BT or Xbees, there is no native hardware support for serial stream communication, BUT the RFX library fills that gap… full bi-directional serial stream data connections are implemented via nRF24L01+ radios!

The low powered versions of the nRF24L01+ radios are good for connecting to an RFX gateway/hub within a house, up to a few rooms away, whereas the higher powered versions with the LNA (low noise amp) and PA (power amp) options can connect to an RFX from much greater distances — over 100s of meters, depending on conditions. This makes them suitable for devices inside or outside the house, but beyond the range of the low powered versions.

If you have only one embedded project that you wish to connect wirelessly to your LAN or Internet, then a Wifi shield or similar may be more cost-effective. However, as soon as you are considering connecting more than one device wirelessly, the low incremental cost of each additional device after the initial cost of the gateway set-up makes RFX a compelling value proposition.

Finally, while affordability is a major driver, another important consideration is power, flexibility, and potential for customization. Need to communicate with a https server? A standalone Wifi shield or similar won’t handle that, you need a gateway to do the heavy lifting. Customization? This is a solution developed for the community of DIY makers and embedded hackers, after all, so the RFX library code that compiles into your Arduino or Arduino-like project is provided in source form, making it possible to extend and add custom capabilities if required.

A major design goal has been to also provide a comprehensive yet simple to use out-of-the-box solution to get your Arduino and Arduino-like embedded projects on-line as quickly and simply as possible!

The RFXduino library has been tested to run on the following dev boards:

  • Arduino Uno, Nano, Mega1280, Mega2560, Leonardo and Due.
  • Pro Micro, both 5V and 3.3V variants.
  • Iteadstudio IBoard
  • Leaflabs Maple5
  • PJRC Teensy 3.0/3.1 (for additional convenience, Embedded Coolness also offers a Teensy 3.x “carrier” dev board adding Arduino shield compatibility with built-in prototyping area and connection header for nRF24L01+ radios. Available in kit form from this store.)
  • Embedded Coolness’s own ATmega328p-based Uno-class board (a compact dev board with built-in prototyping area and connection header for nRF24L01+ radios), and
  • EmbeddedCoolness’ ATmega1284p-based “Skinny Bob” Bobuino derivative board (a larger, Mega-class dev board with built-in prototyping area and connection header for nRF24L01+ radios). Both boards available in kit form from this store.

Many additional custom and commercially produced AVR and ARM-based X:duino board variants should also be straightforward to make work with the RFXduino library code, as it has been written with portability in mind from its beginning.

Basic RFX port IO functionality

When an Arduino/X:duino is connected to an RFXduino gateway, it has LAN network connectivity via a dedicated port on the gateways IP address.

So, for example, if RFX embedded project 1 has been assigned port 11001, and the RFX gateway’s IP address is (say) 192.168.1.25, then the embedded project will be able to connect/be connected to via 192.168.1.25:11001.

So, if (say) an Arduino/X:duino was running a sketch that enabled it to be a web server, a web browser connecting to http://192.168.1.25:11001 will be served a web page from the Arduino/X:duino, just as in the examples from the standard Ethernet library that comes with the Arduino development environment.

A simple web server example using RFX is here. It has been directly adapted from a sketch written for the Arduino Ethernet library, so you can easily see where the small number of changes need to be made to convert an Ethernet library to ketch to run under RFX.

The Arduno/X:duino is not limited to html or http; the port is good for general purpose TCP/IP communications. So, a telnet terminal connection (via a telnet client such as PuTTY) connecting to 192.168.1.25:11001 could be used as a virtual serial connection to the Arduino/X:duino, as if you were connected via the USB serial connection.

Instead of

Serial.print("hello world!\n");

You would write

rfx.pr("hello world!\n");

and instead of

c = Serial.read();

To read a character, you would write

c = rfx.read();

A simple example of a sketch that reads a line of text from the virtual serial input and then echoes it back to the virtual serial output is here.

Advanced functionality: RFX Alert and Exec services

RFX Alert services

What if you want to your embedded project to PUT data to xively.com (formerly pachube/cosm), send an email, or POST an SMS to your phone via a web API?

While, in principle, you could do this by writing fairly complicated routines directly in your sketch to handle the various protocols, RFX simplifies all this greatly by abstracting these functions as “alert services”.

An RFX alert instructs the gateway to forward a text message to the nominated service (configuration and set-up on the gateway device) like so:

  ack = rfx.alert_start_request(ALERT_EMAIL,5000);

  if (ack) {
    rfx.prln("Your pool is out of chlorine.");
    rfx.prln("\n(Sent from your swimming pool.)\n");
  }
  ack = rfx.alert_stop_request(5000); // this says ready to receive normal stream

If you wanted to send the message via SMS instead, you would write:

  ack = rfx.alert_start_request(ALERT_SMS,5000);
  if (ack) {
    rfx.prln("Your pool is out of chlorine.");
    rfx.prln("\n(Sent from your swimming pool.)\n");
  }
  ack = rfx.alert_stop_request(5000); // this says ready to receive normal stream

How this works is that any text that is sent between the alert_start_request() and the alert_stop_request() is understood by the RFX gateway server to be a message that should be forwarded to the nominated service via the appropriate protocol. An email will get sent to a smtp server that is specified in the RFX email alerts configuration, and the SMS will be forwarded to the SMS sevice provider web gateway that is specified in the RFX SMS alerts configuration, and so on.

And if there are any new alert services that you wish to add, it is easy to follow the template, since this is all extensible and customizable.

Here’s an example of using RFX alerts to send an update to an xively.com data logging stream via a PUT:

ack = rfx.alert_start_request(ALERT_PUT,5000);

if (ack) { // don't proceed unless got start_request ack

  // anything written out by rfx.out goes in the alert until
  // an alert_stop_request() is sent

  rfx.fpln("--config ./cfg/diff_humidity_ctrl.cfg");
  rfx.fpf("out_temp,%s,%7.1f\n", datestr, dht_out.temperature);
  rfx.fpf("out_rh,%s,%7.2f\n", datestr, dht_out.humidity);
  rfx.fpf("out_dewp,%s,%7.1f\n", datestr, dewp_out);
  rfx.fpf("in_temp,%s,%7.1f\n", datestr, dht_in.temperature);
  rfx.fpf("in_rh,%s,%7.2f\n", datestr, dht_in.humidity);
  rfx.fpf("in_dewp,%s,%7.1f\n", datestr, dewp_in);
  rfx.fpf("fan_on_off,%s,%d\n", datestr, relayState);
}

rfx.alert_stop_request(5000); // this says ready to receive normal stream

You may notice the first line of the message actually indicates a configuration file where pertinent info such as the xively.com Url and ApiKey are stored. This info could be stored directly in the sketch programming, of course, but it makes things simpler and more manageable to keep such information in configuration files on the RFX gateway server. If xively.com changes its name (yet again!) or you want to direct your data to a different data logging stream, you don’t need to reprogram your embedded devices, simply update the relevant config file.

The second thing you may notice is that it appears RFX supports printf() style formatted output. This is indeed true, although we won’t discuss this in detail right now. (And we won’t show you what the above would look like if you were doing it in basic Serial.print() fashion, but as you could imagine, it would be a mess!)

RFX Exec services

The RFX alerts services are designed to be one-way communications – your device sends a message, but it doesn’t get any direct response of success or otherwise at the time of sending – messages using services like email or SMS are all forwarded on a “best effort” basis.

In many cases this is perfectly acceptable, but sometimes you want to be able to read and process a response, e.g., you send a query to a server, and it sends back a response.

For this, RFX provide the “exec” service, which is like a two-way version of the alerts service. Being two-way, it is slightly more complicated, since there is both a send and receive stage, but we will provide a simple example to show how that works.

You will notice the xively.com PUT example above sends the data with a timestamp string variable called datestr; this suggests the embedded Arduino/X:duino device has access to a time source such as a real time clock.

But what if you don’t have an RTC on your dev board? Well, if you are connected to RFX, you can ask for the time on the gateway server via the exec service!

Here’s a simple example of how to do that:

if (rfx.exec_start_request(5000)) { // don't proceed unless got start_request ack

 // anything written out by rfx.out goes into the exec cmd script
 // until an exec_recv_request() is sent, and then can read the
 // output of cmd script execution

 rfx.prln("date"); // just ask for the system date from gateway device using unix cmd "date"
 if (rfx.exec_recv_request(5000)) { // finished, switch to recv.
  // note, this will clear (flush) input buffer
  int n = rfx.read_until("\n", 5000, datestr, sizeof(datestr)); // read until newline or eof(), 5000 ms time limit
  if (rfx.matched()) {
   datestr[n-1] = 0; // delimit buf to make string, overwriting '\n'
  }
 }
}

rfx.exec_stop_request(5000); // this says ready to receive normal stream

This will capture into datestr a string returned from the RFX gateway after it executes a shell script with the single command “date”. Notice there is an extra step between exec_start_request() and exec_stop_request(), i.e., exec_recv_request(). This puts the requesting device into listening mode, and signals to the gateway server to execute commands/send results.

Notice also the read_until() method used to capture and parse the returned string. Again, this will be discussed in more detail in the documentation concerning advanced print functions.

In practice, much more complicated requests using a series of commands can be made, retrieving information from the Internet, local servers, or (as above) the gateway device itself. As long as the shell script specifies the output is to be directed to stdout, it will be returned by the exec service to the RFX connected requesting device.

RFX print functions: Overview

Basic print functions

The Rfx_printfns library streamlines and extends the Arduino Serial.print() functionality, so where you would previously write

Serial.print("Hello there!");

you would instead write

pr("Hello there!"); // pr() is short form of Serial.print()

This already makes reading and writing sketches quicker and easier, but that’s really just the beginning. If you wanted to use flash strings (or “prog_mem”) to store fixed strings for printing, instead of writing

Serial.print(F("hello there!"))

you would instead write

fp("hello there!"); // fp() (for "flash print") is short form of Serial.print(F())

prln()/fpln() correspond as you might expect to Serial.println()/Serial.println(F()).

pr()/fp()/prln()/fpln() are all overloaded to accept the same types and optional arguments as Serial.print()/Serial.println(). So, for example, pr(int_var,HEX) works as you would expect.

RFX printf() support

There is also an RFX implementation of printf() included that

  • is very light on ram footprint compared to standard library printf()
  • supports floating point (%f) formatted numbers
  • uses flash rather than ram for format strings by default
  • allows direct printing of flash strings, using an extension %P specifier
  • even prints C++/Arduino String types if required, using an extension %S specifier!

which means that instead of typing

float score = 6.0;
float max = 10.0;

Serial.print(f("I give Serial.print() ");
Serial.print(score);
Serial.print(" out of ");
Serial.print(max);
Serial.println("!");

you would type the much more civilized

float score = 9.5;
float max = 10.0;

fpf("I give printf() %f out of %f!\n", score, max); // fpf() for "flash printf()"

For completeness, there is also a prf() version that uses ram for format strings rather than flash (same as the standard library version, but it would be unusual you wouldn’t want to use the fpf() version instead.)

An example sketch that demos some of the advanced features of the RFX printf() implementation is here.

Portability

The pr()/fp(), prln()/fpln() and prf()/fpf() syntax of the Rfx_printfns library is portable across the X:duino platforms supported by RFX, so instead of writing

SerialUSB.print("hello there!");

for a Maple board, you can just write

pr("hello there!");

which aids portability of sketches. fp() is still supported and treated sensibly even on platforms that don’t support flash strings (e.g., ARM-based boards). If a platform doesn’t support flash strings, fp() is treated as if it were pr(), so there is no portability penalty in using the flash string variant syntax in the RFX print functions.

print functions for RFX wireless serial streams

Finally, the RFX print function syntax is completely and consistently extended to the RFX serial streams, so to write to a TCP/IP port from within your sketch, it is a simple as

rfx.fp("hello there!");

So the aim of introducing the pr()/fp()/prln()/fpln()/fpf()/prf() syntax for RFX print function was two-fold: Firstly, to streamline the syntax, making programs both easier to read and faster to write; and secondly, to provide a portable syntax across X:duino variant devices, and also across the uart and RFX wireless serial streams.

Rfx_printfns (longer)

1) Rfx_printfns.h

Rfx_printfns is a set of functions and macros that can be used standalone, i.e., it does not depend on any of the other RFX libs. It provides functionality for managing the allocation and printing of strings stored in program memory (i.e., “flash” strings) functions on AVR u-controllers. It uses the macros and.functions from the avr/pgmspace.h library. It has been designed to make source code faster to write, easier to read, and more portable across Arduino-like (i.e., “X:duino”) development environments by hiding the tedium of managing flash strings explicitly behind convenience macros. For example,

Serial.print("That was a lot of typing before you even get to what you want say");

becomes

pr("That was less so");

the Rfx_printfns functions and macros provide pr() and prln() as convenient shorthand substitutes for Serial.print() and Serial.println(), making a program more readable and quicker to type.

You can also replace Serial.print("That was less so") with

fp("That was less so");

which is basically a shorthand equivalent to

Serial.print(F("That was less so"));

i.e., it place the text string in program (or “flash”) memory, rather than taking up limited and therefore valuable ram.

Actually, writing fp("That was less so"); is even better than writing Serial.print(F("That was less so")); — and not just because it is quicker to type and easier to read. The nice thing about using the fp(s) and fpln(s) macros is that the string may be stored in either flash memory or ram, depending on how the program is configured in it’s configuration header file, Rfx_config.h (it goes in the same directory as the sketch program.) If the target board is an AVR u-controller, such as an Arduino Uno or equivalent, then an optional config parameter FLASH_STRINGS can be set true or false (1 or 0, actually), to control how the fp() macros manage their strings. If the target board is an ARM board, such as a Leaflabs Maple r5, an Arduino Due, or a PJRC Teensy3, and putting strings into flash is not an option due to the architectural constraints, then the fp() macros will place them ram, automatically.

The key thing here is the ease of portability; you can write

fp("hello worlds!");

in your program, and it will compile to on all the platforms mentioned, without having to do

Serial.print(F("hell worlds!"));

for Arduino Uno,

Serial.print("hell worlds!");

for Due,

SerialUSB.print("hell worlds!");

for Maple5,

and so on. The same sketch using the Rfx_printfns on all those platforms can be used without futzing with those tedious and annoying syntax differences. So not only does it save you typing, it saves _retyping_! And the errors that can introduce are also avoided, of course.

Finally, if improved convenience, readability and portability aren’t enough, there is a richly featured yet highly ram memory efficient implementation of printf() available to provide formatted printing functionality.

2) RFX printf()

Rfx_printf is an extension library of functions and macros that adds printf() formatted printing functionality on top of the basic Rfx_printfns library.

Experienced C programmers often sorely miss printf() when coming to a u-controller platform.

Instead of this:

printf("the temp is %f C and the rel. humidity is %f %%\n",temperature, humidity);

You end up having to write something that looks like:

Serial.print(F("the temp is "));
Serial.print(temperature);
Serial.print(F(" C and the rel. humidity is "));
Serial.print(humidity);
Serial.println(F(" %"));

which is tedious to write, and results in ugly and hard to read source code.

The root problem is that the standard printf() implementations are typically ram inefficient, and therefore often unsuitable for practical work on the target embedded platform.

The gcc printf() library functions bundled as part of the standard Arduino development distributions are no different – even in their severely limited form (no floating point support at all!), they are still ram hogs, and so are of limited use, at best.

The full floating point support features do make the standard printf() implementations big, so full implementations of printf() can be program memory hogs as well. That’s why the versions that come bundled as part of the standard Arduino packages are subsetted so as to not support floating point %f %E %g formatting at all.

However, in the Rfx_printfns implementation, basic support for floating point is implemented, all of %f and some of %g. The only thing missing is exponential formatting. Apart from that, it is a complete implementation of ANSI/K&R (pre-C99) printf().

So, if the Rfx_printfns library is being used, then as well as pr()/prln() and fp()/fpln(), we now also have prf(fmt,…) and fpf(fmt,…) available. The fpf(fmt,…) macro would be the natural choice for most situations, as it has the advantage of automatically storing the format string a flash/program memory string, if the FLASH_STRINGS setting is enabled, exactly analogous to how fp() and fpln() work. (If for some reason you need to use a ram string for a format string, the prf(fmt,…) variant is also available.)

fpf("this format string may be stored in flash memory…\n");

prf("but this format string definitely isn’t!\n");

Storing the printf() format string as a flash string is obviously a major benefit when ram is scarce. Actually, the library function printf_P() also does this, but a further advantage of the Rfx_printfns implementation is that it also has support for printing flash strings using a (non-standard) %P specifier. The standard gcc library printf functions provide no mechanism for doing this, which is potentially a major limitation. The standard %s format specifier will still print normal ram strings, if required.

fpf("rfx_printf works with %P strings and %s strings\n",PSTR("flash"),"normal");

Arduino/C++ Strings

Finally, for completeness, the RFX printf() function will also print out Arduino/C++ String() class strings, using another non-standard extension specifier, %S, so three types of string in all are supported for printing (which is two more than the standard lib implementations). It does this like so:

String cppstr = "Arduino/C++ String";

fpf("rfx_printf works with %S type strings as well.\n",&cppstr);

(Note that the Arduino/C++ String must be passed by reference using the & operator.)

I say this was included “for completeness” because, although (for many good reasons) it is generally recommended to avoid C++ style strings in embedded programming in favor of the older style “C-strings” whenever possible, I recognize there may be situations where support for C++ strings is wanted or needed.

One final note about Arduino/C++ Strings: pr(cppstr) and prln(cppstr) will work, but fp(cppstr) and fpln(cppstr) won’t work. This isn’t a bug — fp(cppstr) doesn’t really make sense for the fp() macro, since PSTR() can’t be applied to Strings (another reason to prefer C-strings).

What superficially may look like an inconsistency could potentially cause confusion though, particularly since fp(cppstr) will compile if FLASH_STRINGS is set to 0, but won’t compile if FLASH_STRINGS is set to 1. (That’s just because the fp() macro is equivalent to pr() when FLASH_STRINGS is 0, so the fact is works in this case is just a fluke, rather than by design.) So the rule is: Don’t mix fp()/fpln() and Arduino/C++ Strings.


RFX alerts

RFX Alerts: How to send an email

You can send an email from your Arduino in as little as three lines of code using the RFX alerts system :

if (rfx.start_alert_request(ALERT_EMAIL,5000)) 
  rfx.println("This is an email alert sent from your sketch!\n");
rfx.stop_alert_request();

After calling the start_alert_request() method, anything written to the rfx stream output will be captured by the RFX gateway as the body of an email message, until a stop_alert_request() method is called, which signals the end of the email message.

Once the email message text has been received by the gateway program, the gateway program passes it to a dedicated alert handler program, running as a background process. The alert handler program takes care of transaction details with the SMTP server. This delegation frees the main gateway program to return without delay to its primary real-time duties.

How does the email alert handler know to which address to send the email, etc? This is specified in advance in a configuration file for the email alert handler. This configuration file also includes the email title, the “from” address, and the connection and authentication details for the SMTP server.

So the delivered email might look like:

Subject: RFX Alert
To: youraddress@mailprovider.com
From: rfxalerts@mailprovider.com

This is an email alert sent from your sketch!

if so configured.

(Complete test sketch to send an email via RFXduino alert service below)

/*

email_test.ino

RFXduino test sketch for sending an email via alert service.

-Mark Pendrith, September 2013.

 */

#ifdef ARDUINO
#include <Arduino.h>
#endif

#include "Rfx_config.h"
#include <Rfx_r2.h>

#if HW_SPI
#include <SPI.h>
#endif

Rfx rfx;

void setup()
{
  Serial.begin(115200);

  SRC_DETAILS_C("Rfx_r2.h");

  rfx.begin_id(BOARD_ID,ID_STRING);
}

void loop()
{
  static bool done = false;

  if (rfx.joined() && !done) { // wait for join to gateway status confirmed

    if (rfx.alert_start_request(ALERT_EMAIL,5000)) { // don't proceed unless got start_request ack
      rfx.fpln("This is a test email alert sent from your sketch via the RFXduino gateway!");
      done = true; // only send email one time
    }
    else fp("rfx.alert_start_request() == false");

    rfx.alert_stop_request(5000); // this says ready to receive normal stream again
  }
}
RFX Alerts: How to send an SMS

You can send an SMS from your Arduino in as little as three lines of code using the RFX alerts system :

if (rfx.start_alert_request(ALERT_SMS,5000)) 
  rfx.println("This is an SMS alert sent from your sketch!");
rfx.stop_alert_request();

After calling the start_alert_request() method, anything written to the rfx stream output will be captured by the RFX gateway as the body of an SMS message, until a stop_alert_request() method is called, which signals the end of the SMS message.

Once the SMS message text has been received by the gateway program, the gateway program passes it to a dedicated alert handler program, running as a background process. The alert handler program takes care of transaction details with the SMS server API (typically a POST method to a URI is required, usually via an SSL connection). This delegation frees the main gateway program to return without delay to its primary real-time duties.

How does the SMS alert handler know to which phone number to send the SMS, etc? This is specified in advance in a configuration file for the SMS alert handler. This configuration file also includes the connection and authentication details for the SMS server.

So the delivered SMS might look like:

From: +12345678901

This is an SMS alert sent from your sketch!

if so configured.

(Complete test sketch to send an SMS text message via RFXduino alert service below)

/*

sms_test.ino

RFXduino test sketch for sending an SMS via alert service.

-Mark Pendrith, September 2013.

 */

#ifdef ARDUINO
#include <Arduino.h>
#endif

#include "Rfx_config.h"
#include <Rfx_r2.h>

#if HW_SPI
#include <SPI.h>
#endif

Rfx rfx;

void setup()
{
  Serial.begin(115200);

  SRC_DETAILS_C("Rfx_r2.h");

  rfx.begin_id(BOARD_ID,ID_STRING);
}

void loop()
{
  static bool done = false;

  if (rfx.joined() && !done) { // wait for join to gateway status confirmed

    if (rfx.alert_start_request(ALERT_SMS,5000)) { // don't proceed unless got start_request ack
      rfx.fpln("This is a test SMS alert sent from your sketch via the RFXduino gateway!");
      done = true; // only send SMS text message one time
    }
    else fp("rfx.alert_start_request() == false");

    rfx.alert_stop_request(5000); // this says ready to receive normal stream again
  }
}
RFX Alerts: How to send a Tweet

You can send a Tweet from your Arduino in as little as three lines of code using the RFX alerts system :

if (rfx.start_alert_request(ALERT_TWEET,5000)) 
  rfx.println("This is a Twitter alert sent from your sketch!");
rfx.stop_alert_request();

After calling the start_alert_request() method, anything written to the rfx stream output will be captured by the RFX gateway as the body of a Tweet, until a stop_alert_request() method is called, which signals the end of the Tweet text.

Once the Tweet text has been received by the gateway program, the gateway program passes it to a dedicated alert handler program, running as a background process. The alert handler program takes care of transaction details with the twitter.com server. This delegation frees the main gateway program to return without delay to its primary real-time duties.

How does the Tweet alert handler know to which Twitter account to send the Tweet, etc? This is specified in advance in a configuration file for the Tweet alert handler. This configuration file also includes the connection and authentication details for the twitter.com server.

So the displayed Tweet might look like:

This is a Twitter alert sent from your sketch!
if so configured.

(Complete test sketch to send a tweet via RFXduino alert service below)

/*

tweet_test.ino

RFXduino test sketch for sending a tweet via alert service.

-Mark Pendrith, September 2013.

 */

#ifdef ARDUINO
#include <Arduino.h>
#endif

#include "Rfx_config.h"
#include <Rfx_r2.h>

#if HW_SPI
#include <SPI.h>
#endif

Rfx rfx;

void setup()
{
  Serial.begin(115200);

  SRC_DETAILS_C("Rfx_r2.h");

  rfx.begin_id(BOARD_ID,ID_STRING);
}

void loop()
{
  static bool done = false;

  if (rfx.joined() && !done) { // wait for join to gateway status confirmed

    if (rfx.alert_start_request(ALERT_TWEET,5000)) { // don't proceed unless got start_request ack
      rfx.fpln("This is a test twitter alert sent from your sketch via the RFXduino gateway!");
      done = true; // only send tweet one time
    }
    else fp("rfx.alert_start_request() == false");

    rfx.alert_stop_request(5000); // this says ready to receive normal stream again
  }
}
RFX Alerts: Sending an Xively update using PUT

You can send an Xively update from your Arduino in as little as four lines of code using the RFX alerts system :

if (rfx.start_alert_request(ALERT_PUT,5000)) {
  rfx.fpln("--config ./cfg/diff_humidity_ctrl.cfg");
  rfx.fpf("humidity,%s,%7.1f\n", datestr, humidity);
}
rfx.stop_alert_request();

After calling the start_alert_request() method, anything written to the rfx stream output will be captured by the RFX gateway as the details of a PUT method update, until a stop_alert_request() method is called, which signals the end of the update data.

Once the PUT method details have been received by the gateway program, the gateway program passes them to a dedicated alert handler program, running as a background process. The alert handler program takes care of transaction details with the Xively.com server. This delegation frees the main gateway program to return without delay to its primary real-time duties.

How does the PUT alert handler know to which URL to send the PUT method update, etc? In the example above, this is specified in a configuration file for the PUT alert handler. This configuration file includes the Xively URL and Xively ApiKey:

--url https://api.xively.com/v2/feeds/841122328.csv
--header X-ApiKey:oOypte09aSplFaGzt8ANhg4j8R6mzYa9drrnKxf4qSbPemxN

and would have been named diff_humidity_ctrl.cfg, located in a directory cfg under the PUT alert handler working directory on the gateway server, as specified in the first line of the PUT alert text.

Instead of using a configuration file, this information could be hard-coded directly into sketch, as follows:

if (rfx.start_alert_request(ALERT_PUT,5000)) {
  rfx.fpln("--url https://api.xively.com/v2/feeds/841122328.csv");
  rfx.fpln("--header X-ApiKey:oOypte09aSplFaGzt8ANhg4j8R6mzYa9drrnKxf4qSbPemxN");
  rfx.fpf("humidity,%s,%7.1f\n", datestr, humidity);
}
rfx.stop_alert_request();

but creating a configuration file on the RFX gateway for each feed will generally make things easier to maintain, as may be required, and so the configuration file method is recommended.

Further, it is of course possible to update more than one Xively data stream in a single RFX PUT alert request, e.g.:

if (rfx.start_alert_request(ALERT_PUT,5000)) {
  rfx.fpln("--config ./cfg/diff_humidity_ctrl.cfg");
  rfx.fpf("humidity,%s,%7.1f\n", datestr, humidity);
  rfx.fpf("temperature,%s,%7.1f\n", datestr, temperature);
  rfx.fpf("control_state,%s,%7.1f\n", datestr, control_state);
}
rfx.stop_alert_request();

Finally, note that the RFX PUT alert method is quite general and not specific to Xively.com in any way, and can be used for sending PUT method requests to just about any server as required. The task of sending a data update to an Xively feed is used here simply as an example.


Example programs

echo_server_v1

/*--------------------------------------------------------------
  Program:      echo_server_v1

  Description:  Simple RFX demo server for Arduino or similar accepts 
                incoming TCP/IP port connections from a telnet/
                terminal program such as PuTTY, and will echo back
                each line of text input it receives after receiving a 
                newline char.

                This version is easiest to understand for those new to RFX, 
                as it sticks pretty much to standard Arduino library function 
                syntax, but it has room for some improvements, which will be 
                shown next in echo_server_v2
 
  Hardware:     Uno-class Arduino/X:duino (or better) with nRF24L01+ 
                module, and RFX gateway (Raspberry Pi with RFX 
                daughterboard and SD Card).
                  
  Software:     Developed using RFX r2 libs and Arduino 1.0.5 software
                (Should be compatible with Arduino 1.0 +)
  
  Date:         July 2013
 
  Author:       Mark Pendrith, demo sketch for Arduino using 
                RFX. http://embeddedcoolness.com (July, 2013)

--------------------------------------------------------------*/

#include <Arduino.h>

#define BOARD_ID 1 // choose a value between 1-255
#define ID_STRING "echo_server_v1" // choose a string to help identify
#define BOARD_TYPE_UNO // select board type for RFX
#define SPI_DEMI_SHIELD // select a SPI pin configuration fro RFX
#define HW_SPI 1 // select hardware SPI or software SPI (bit banging)

#include <Rfx_r2.h>
#include <SPI.h>

Rfx rfx; // create instance of Rfx object for wireless IO

String echo_str; // stores the echo string request
  
void setup()
{
  Serial.begin(115200); // for diagnostics to uart serial if connected

  rfx.begin_id(BOARD_ID,ID_STRING); // set up wireless link to RFX gateway 
}

void loop()
{
  if (rfx.port_connected()) { // check for new incoming port connection
    Serial.println("new connection!"); // diagnostic message to uart serial
    rfx.println("Hello world! I'm an RFX echo server. Type something...\n");
    while (rfx.port_connected()) { // serve this client while port connected
      if (rfx.available()) { // client data available to read
        char c = rfx.read(); // read 1 byte (character) from client
        echo_str += c;  // save the echo string 1 char at a time
        if (c == '\n') { // echo string to client only after newline received
          rfx.print("echo: ");
          rfx.println(echo_str); // print echo string to TCP/IP port connection
          echo_str = ""; // reset string
        }
      }
    }
    Serial.println("port connection closed"); // diagnostic message to uart serial
  }
}
echo_server_v2

/*--------------------------------------------------------------
  Program:      echo_server_v2

  Description:  Simple RFX demo server for Arduino or similar accepts 
                incoming TCP/IP port connections from a telnet/
                terminal program such as PuTTY, and will echo back
                each line of text input it receives after receiving a 
                newline char.

                This version should also be fairly easy to understand 
                for those new to RFX, as we've only made two changes 
                from echo_server_v1. The first is to move the RFX 
                related #define configuration settings to "Rfx_config.h", 
                which resides in the sketch directory/folder. This is 
                a nice way to keep from having to edit your sketch when 
                you want to recompile for a different target board or 
                hardware configuration, just edit the Rfx_config.h file 
                instead.

                The second change is to convert the constant character 
                array C-strings but to pgm_mem "flash strings", so we 
                aren't needlessly wasting valuable ram. 

                The standard Arduino program syntax is getting a bit 
                unwieldy as a result, however, so still has room for some 
                improvements, which will be shown next in our final version, 
                echo_server_v3.
 
  Hardware:     Uno-class Arduino/X:duino (or better) with nRF24L01+ 
                module, and RFX gateway (Raspberry Pi with RFX 
                daughterboard and SD Card).
                  
  Software:     Developed using RFX r2 libs and Arduino 1.0.5 software
                (Should be compatible with Arduino 1.0 +)
  
  Date:         July 2013
 
  Author:       Mark Pendrith, demo sketch for Arduino using 
                RFX. http://embeddedcoolness.com (July, 2013)

--------------------------------------------------------------*/

#include <Arduino.h>

#include "Rfx_config.h"
#include <Rfx_r2.h>
#include <SPI.h>

Rfx rfx; // create instance of Rfx object for wireless IO

String echo_str; // stores the echo string request
  
void setup()
{
  Serial.begin(115200); // for diagnostics to uart serial if connected

  rfx.begin_id(BOARD_ID,ID_STRING); // set up wireless link to RFX gateway 
}

void loop()
{
  if (rfx.port_connected()) { // check for new incoming port connection
    Serial.println(F("new connection!")); // diagnostic message to uart serial
    rfx.out.println(F("Hello world! I'm an RFX echo server. Type something...\n"));
    while (rfx.port_connected()) { // serve this client while port connected
      if (rfx.available()) { // client data available to read
        char c = rfx.read(); // read 1 byte (character) from client
        echo_str += c;  // save the echo string 1 char at a time
        if (c == '\n') { // echo string to client only after newline received
          rfx.print(F("echo: "));
          rfx.println(echo_str); // print echo string to TCP/IP port connection
          echo_str = ""; // reset string
        }
      }
    }
    Serial.println(F("port connection closed")); // diagnostic message to uart serial
  }
}
echo_server_v3

/*--------------------------------------------------------------
  Program:      echo_server_v3

  Description:  Simple RFX demo server for Arduino or similar accepts 
                incoming TCP/IP port connections from a telnet/
                terminal program such as PuTTY, and will echo back
                each line of text input it receives after receiving a 
                newline char.
 
                This version takes up from version 2, where we had introduced
                converting constant strings to ram-saving "flash strings" using
                the standard Arduino "F()" macros. The standard syntax makes 
                things a bit clunky and hard to read, so to improve 
                readability, we use the cleaner and much more succinct RFX 
                print lib syntax. 

                The changes from the previous version: 

                Serial.println(F("string")); becomes fpln("string");
                rfx.println(F("string")); becomes rfx.fpln("string");

                and we use the rfx ram-efficient implementation of printf() 
                so that

                rfx.print(F("echo: "));
                rfx.println(echo_str); // echo

                becomes

                rfx.fpf("echo: %S\n",&echo_str); // echo using RFX printf() fn

                To summarise the translation, the basic rule is print() is 
                shortened to pr(), and print(F()) -> fp() (for "flash print").
 
                Serial.print(...) -> pr(...)
                Serial.println(...) -> prln(...)
                Serial.print(F(...)) -> fp(...)
                Serial.println(F(...)) -> fpln(...)
                printf(...) -> prf(...)
                printf_P(...) -> fpf(...)

                Similarly, to send output to TCP/IP stream

                rfx.print(...) -> rfx.pr(...)
                rfx.println(...) -> rfx.prln(...)
                rfx.print(F(...)) -> rfx.fp(...)
                rfx.println(F(...)) -> rfx.fpln(...)
                rfx.printf(...) -> rfx.prf(...)
                rfx.printf_P(...) -> rfx.fpf(...)

  Hardware:     Uno-class Arduino/X:duino (or better) with nRF24L01+ 
                module, and RFX gateway (Raspberry Pi with RFX 
                daughterboard and SD Card).
                  
  Software:     Developed using RFX r2 libs and Arduino 1.0.5 software
                (Should be compatible with Arduino 1.0 +)
  
  Date:         July 2013
 
  Author:       Mark Pendrith, demo sketch for Arduino using 
                RFX. http://embeddedcoolness.com (July, 2013)

--------------------------------------------------------------*/

#include <Arduino.h>

#include "Rfx_config.h"
#include <Rfx_r2.h>
#include <SPI.h>

Rfx rfx; // create instance of Rfx object for wireless stream IO

String echo_str; // stores the echo string request
  
void setup()
{
  Serial.begin(115200); // for diagnostics to uart serial if connected

  rfx.begin_id(BOARD_ID,ID_STRING); // set up wireless link to RFX gateway 
}

void loop()
{
  if (rfx.port_connected()) { // check for new incoming port connection
    fpln("new connection!"); // diagnostic message to uart serial
    rfx.fpln("Hello world! I'm an RFX echo server. Type something...\n");
    while (rfx.port_connected()) { // serve this client while port connected
      if (rfx.available()) { // client data available to read
        char c = rfx.read(); // read 1 byte (character) from client
        echo_str += c;  // save the echo string 1 char at a time
        if (c == '\n') { // echo string to client only after newline received
          rfx.fpf("echo: %S\n",&echo_str); // echo using RFX printf() fn
          echo_str = ""; // reset string
        }
      }
    }
    fpln("port connection closed"); // diagnostic message to uart serial
  }
}
Blink radio

/*
  RFX Blink Radio

  Example program using RFX. If blink is the "hello world" of embedded 
  programming, then obviously RFX needs a radio blink demo!

  Turns on an LED on for one second, then off for one second, repeatedly. 
 
  It also prints "Blink On" and "Blink Off" alternatively via the wireless 
  connection to the default TCP/IP port allocated to this device.

  To see the blink messages, you could connect with a telnet terminal 
  program (like PuTTY) to that ip address:port no
 */

#ifdef ARDUINO
#include <Arduino.h>    // some X:duinos need this, others (e.g. Maple) not
#endif

#include "Rfx_config.h" // this is a config file for the sketch that tells the RFX 
                        // library the hardware characteristics of your device, as
                        // well as any other non-default settings you wish to specify 
                        // for this sketch, such as an ID_STRING and BOARD_ID number 
                        // you choose to identify which RFX enabled board is which. 

#include <Rfx_r1.h>     // this is the directive to include the RFX library

#if HW_SPI
#include <SPI.h>        // HW_SPI is one of the options that can be specified in
#endif                  // Rfx_config.h 

Rfx rfx;                // calls constructor Rfx::Rfx() creating object instance rfx

const int ledpin = 13;  // Pin 13 has an LED connected on many X:duino boards

void setup() 
{
  Serial.begin(115200);

  rfx.begin_id(BOARD_ID,ID_STRING);

  // initialize the digital pin as an output.

#if (!(defined(BOARD_TYPE_TEENSY3) && HW_SPI))
  pinMode(ledpin, OUTPUT); // Teensy 3.0 doesn't like this step
#endif
}

void loop()
{
  static bool blink_on = false;

  if (blink_on) {
    digitalWrite(ledpin, HIGH);   // set the LED on
    rfx.fpln("\nBlink on");   // and tell the world!
  }
  else {
    digitalWrite(ledpin, LOW);    // set the LED off
    rfx.fpln("\nBlink off");
  }

  blink_on = !blink_on;

  rfx_delay(1000); // wait for a second

  // ok, that takes care of blinking duties!

  rfx.sync();  // this should be called regularly, to run diags on nRF24L01+.
}

void rfx_bg() 
{
  /* rfx_bg() is a user-defined background loop that executes while the program is 
  in a waiting state when called by rfx_delay() instead of ordinary delay().

  you can put here anything that could be usefully performed while otherwise waiting 
  for a fixed delay period timeout. e.g. you could place a background diags routine
  like rfx.sync() in here.

  you can also choose to do nothing at all by leaving this fn empty. if you prefer  
  to disable the default_rfx_bg()  functionality, simply delete or comment out the 
  call to default_rf_bg() below. */

  default_rfx_bg();
}
AJAX web server

/*--------------------------------------------------------------
  Program:      rfx_websrv_AJAX_switch

  Description:  Arduino web server shows the state of a switch
				on a web page using AJAX via RFX. The state of the
				switch must be read by clicking a button on
				the web page - for demonstrating AJAX.
  
  Hardware:     Arduino Uno (or equivalent) and RFX. Should work 
				with other Arduinos/X:duinos, perhaps w/ minor 
				modifications.
				  
  Software:     Developed using RFX and Arduino 1.0.5 software
				Should be compatible with Arduino 1.0 +
  
  References:   - WebServer example by David A. Mellis and 
				  modified by Tom Igoe
				- Ethernet library documentation:
				  http://arduino.cc/en/Reference/Ethernet
				- Learning PHP, MySQL & JavaScript by
				  Robin Nixon, O'Reilly publishers

  Date:         15 January 2013
 
  Author:       W.A. Smith, http://startingelectronics.com

  Modified by:  Mark Pendrith, to demonstrate AJAX for Arduino via RFX.
				Original ethernet shield code commented out to show what
				needed to be changed to convert ethernet shield code to
				RFX. http://embeddedcoolness.com (July, 2013)

--------------------------------------------------------------*/

#ifdef ARDUINO
#if (ARDUINO >= 100)
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
#endif

#include "Rfx_config.h"
#include <Rfx_r1.h>
#include <SPI.h>
//#include <Ethernet.h>

// MAC address from Ethernet shield sticker under board
//byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
//IPAddress ip(10, 0, 0, 20); // IP address, may need to change depending on network
//EthernetServer server(80);  // create a server at port 80

Rfx rfx;

String HTTP_req;      // stores the HTTP request
  
#define LED 13        // LED for switching is attached to Arduino pin 13

static uint8_t  led_state = 0;

void setup()
{
  //Ethernet.begin(mac, ip);  // initialize Ethernet device
  //server.begin();           // start to listen for clients
  Serial.begin(115200);       // for diagnostics
  
  pinMode(LED, OUTPUT);
  digitalWrite(LED, LOW);

  rfx.begin_id(BOARD_ID,ID_STRING);  
}

void loop()
{
  //EthernetClient client = server.available();  // try to get client

  //if (client) {  // got client?
  if (rfx.joined()) { // joined to RFX gateway?
    boolean currentLineIsBlank = true;
    //while (client.connected()) {
    while (rfx.port_connected()) {
      //if (client.available()) {   // client data available to read
      if (rfx.available()) {   // client data available to read
        //char c = client.read(); // read 1 byte (character) from client
        char c = rfx.read(); // read 1 byte (character) from client
        HTTP_req += c;  // save the HTTP request 1 char at a time
        // last line of client request is blank and ends with \n
        // respond to client only after last line received
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          rfx.fpln("HTTP/1.1 200 OK");
          rfx.fpln("Content-Type: text/html");
          rfx.fpln("Connection: keep-alive");
          rfx.out.prln(); // need to print blank line after header
          // AJAX request for switch state
          if (HTTP_req.indexOf("ajax_switch") > -1) {
            // read switch state and send appropriate paragraph text
            GetSwitchState(&rfx);
          }
          else {  // HTTP request for web page
            // send web page - contains JavaScript with AJAX calls
            rfx.fpln("<!DOCTYPE html>");
            rfx.fpln("<html>");
            rfx.fpln("<head>");
            rfx.fpln("<title>RFX AJAX Demo</title>");
            rfx.fpln("<script>");
            rfx.fpln("function GetSwitchState() {");
            rfx.fpln("nocache = \"&nocache=\" + Math.random() * 1000000;");
            rfx.fpln("var request = new XMLHttpRequest();");
            rfx.fpln("request.onreadystatechange = function() {");
            rfx.fpln("if (this.readyState == 4) {");
            rfx.fpln("if (this.status == 200) {");
            rfx.fpln("if (this.responseText != null) {");
            rfx.fpln("document.getElementById(\"switch_txt\").innerHTML = this.responseText;");
            rfx.fpln("}}}}");
            rfx.fpln("request.open(\"GET\", \"ajax_switch\" + nocache, true);");
            //rfx.fpln("request.open(\"GET\", \"ajax_switch\", true);");
            rfx.fpln("request.send(null);");
            rfx.fpln("}");
            rfx.fpln("</script>");
            rfx.fpln("</head>");
            rfx.fpln("<body>");
            rfx.fpln("<h1>RFX Switch Status via AJAX</h1>");
            rfx.fpln("<p id=\"switch_txt\">Switch state: Not requested...</p>");
            rfx.fpln("<button type=\"button\" onclick=\"GetSwitchState()\">Get Switch State</button>");
            rfx.fpln("</body>");
            rfx.fpln("</html>");
          }
          delay(1); // give the web browser time to receive the data
          rfx.port_close();  // close the connection (better placed here rather than outside the loop)
          // display received HTTP request on serial port
          pr(HTTP_req);
          HTTP_req = "";            // finished with request, empty string
          break;
        }
        // every line of text received from the client ends with \r\n
        if (c == '\n') {
          // last character on line of received text
          // starting new line with next character read
          currentLineIsBlank = true;
        } 
        else if (c != '\r') {
          // a text character was received from client
          currentLineIsBlank = false;
        }
      } // end if (client.available())
    } // end while (client.connected())
    //delay(1);      // give the web browser time to receive the data
    //client.stop(); // close the connection
  } // end if (client)
}

// send the state of the switch to the web browser
void GetSwitchState(Rfx *r)
{
  static bool flipflop = false;
  //if (digitalRead(3)) {
  if ((flipflop = !flipflop)) {
    r->fpln("Switch state: ON");
    digitalWrite(LED,HIGH); // switch on the led
  }
  else {
    r->fpln("Switch state: OFF");
    digitalWrite(LED,LOW); // switch off the led
  }
}
RFX printf() demo


/*
Example program demoing some of the RFX printf() lib features in standalone 
mode. (All these features also available when using printf() method for 
TCP/IP port IO, of course.)

Mark Pendrith, July 2013
*/

#include <Arduino.h>

#include "Rfx_config.h"

#include <Rfx_printfns_r1.h>

void setup()
{
  char s1[] = "rfx printf()";
  double pi = 3.14159;

  Serial.begin(115200);

  fpf("\nThis is a basic demo of %s.\n\n",s1);

  for (int k = 0; k < 10; k++)
    fpf(" %s %d\n",s1,k);

  fpf("\nit prints floats like %f too!\n",pi);    
  fpf("all using very little ram (free_ram() = %d)\n",free_ram());
  fpln("all the fancy specifier/flag stuff is supported, (the only thing \n"
       "not supported is exponential format for floats).");

  fpln("\nHere's some of the fancy stuff, including two non-standard extensions useful \n"
         "for Arduino applications:\n");
 
  fpln("1) a %P specifiers to allow direct printing of AVR flash (i.e, \"PSTR()\") strings, and");
  fpln("2) a %S specifier to allow direct printing of Arduino Strings/C++ strings.\n");

  fpln("See some format specifier test examples below:\n");

  int i = -100;
  int8_t h = i; // a short int
  double f = (double)i;
  String cppstr = "This is an Arduino/C++ String";

  fpf("this is a test of fpf, i = %d, f = %9.2f, g = %.2g\n",i,f,f);

  fpf("\nthis may be a flash string...\n");
  prf("but this definitely isn't!\n\n");

  char test_str[] = "Here's a string to play around with for width and justificaton formatting...";

  fpf("%s\n", test_str);
  fpf(":%%s: = :%s:\n", test_str);
  fpf(":%%20s: = :%20s:\n", test_str);
  fpf(":%%.10s: = :%.10s:\n", test_str);
  fpf(":%%20.10s: = :%20.10s:\n", test_str);
  fpf(":%%-20.10s: = :%-20.10s:\n\n", test_str);

  const char *test_pstr = PSTR("And here's a PSTR (flash) string to play around with...");

  fpf("%P\n", test_pstr);
  fpf(":%%P: = :%P:\n", test_pstr);
  fpf(":%%20P: = :%20P:\n", test_pstr);
  fpf(":%%.10P: = :%.10P:\n", test_pstr);
  fpf(":%%20.10P: = :%20.10P:\n", test_pstr);
  fpf(":%%-20.10P: = :%-20.10P:\n\n", test_pstr);

  fpf("test of fpf, i = %i, u = %u, x = %x, o = %o, b = %b, f = %9.2f, g = %.2g\n",i,i,i,i,i,f,f);
  fpf("test of fpf, #i = %#i, #u = %#u, #x = %#x, #o = %#o, #b = %#b, #f = %#9.2f, #g = %#.2g\n",i,i,i,i,i,f,f);
  fpf("test of fpf, #hi = %#hi, #hu = %#hu, #hx = %#hx, #ho = %#ho, #hb = %#hb\n",h,h,h,h,h);

  int n;
  fpf("test of fpf, %%n,%n i = %i, u = %u, x = %x, o = %o, b = %b\n",&n,n,n,n,n,n);
  fpf("fpf, width trick %%*d = %*d\n",5,10);
  fpf("fpf, width and precision trick %%*.*f = %*.*f\n",7,3,3.14159);

  String* S = &cppstr; // prints out String types too!

  int len = S->length(); 
  char c = (*S)[0];
  fpf("fpf, C++ str: %%d = %d, %%c = %c\n",len,c);
  fpf("fpf, C++ str: %%S = %S\n",S);
}

void loop()
{
}
Xively update demo
/*
 
RFXduino tutorial sketch to show how to update two streams of an xively.com
feed via a PUT method every 60s using RFX alerts.
 
Also demonstrates how to use the RFX "get_udate()" service, in this case to return
a date string from the Linux gateway in the iso-8601 "Zulu" format, as
specified by Xively.
 
-Mark Pendrith, August 2013.
 
 */

#define XIVELY_FEED_ID "1202944042"
#define XIVELY_API_KEY "cQ62sK5YWOvIqKbRxX8BVkudf4eqq0VQkwyaCIWYa5OkW2N5"

// need to put in your own Xively feed id and ApiKey for this to actually work, of course.
 
#ifdef ARDUINO
#include <Arduino.h>
#endif
 
#include "Rfx_config.h"
#include <Rfx_r3.h>
 
#if HW_SPI
#include <SPI.h>
#endif
 
Rfx rfx;
 
// prototypes
 
void do_xively_update(double val1, double val2);
void send_xively_update_alert(uint8_t *datestring, double val1, double val2);
 
void setup()
{
  Serial.begin(115200);
 
  SRC_DETAILS_C("Rfx_r3.h");
 
  rfx.begin_id(BOARD_ID,ID_STRING);
}
 
void loop()
{
  static double val1 = 0.0;
  static double val2 = 100.0;
 
  static unsigned long last_ms = 0;
  unsigned long ms = millis();
 
  if ((ms - last_ms) > 60000) { // once every minute
    val1 += 10.0; // ascending sawtooth pattern
    val2 -= 10.0; // descending sawtooth pattern
    if (val1 > 105.0) {
      val1 = 0.0; // reset values
      val2 = 100.0; // to keep range in 0.0 - 100.0
    }
    do_xively_update(val1, val2); // update streams for an xively feed with these values
    last_ms = ms; // do again in 60s
  }
  rfx.sync(); // good idea to do this regularly to verify nRF24L01+ status
}
 
void do_xively_update(double val1, double val2)
{
  uint8_t datestring[UDATE_LEN]; // create a buffer to hold the date string
  bool date_ok = rfx.get_udate(datestring, sizeof(datestring), false); // get a UTC timestamp from gateway
  if (date_ok) send_xively_update_alert(datestring, val1, val2); // send update
}
 
void send_xively_update_alert(uint8_t *datestring, double val1, double val2)
{
  if (rfx.alert_start_request(ALERT_PUT,5000)) { // don't proceed unless got start_request ack
    // anything written out via rfx goes in the alert until an alert_stop_request() is sent
    rfx.fp("--url https://api.xively.com/v2/feeds/" XIVELY_FEED_ID ".csv\n");
    rfx.fp("--header X-ApiKey:" XIVELY_API_KEY "\n");

    // rfx.fpln("--config ./cfg/xively_demo_feed.cfg"); 
    // for greater convenience, we could setup a .cfg file on the gateway that provides the same 
    // info as the two lines above, and send this commented out line instead.

    rfx.fpf("stream1,%s,%7.1f\n", datestring, val1); // write the actual data in csv format
    rfx.fpf("stream2,%s,%7.1f\n", datestring, val2);
  }
  rfx.alert_stop_request(5000); // this says ready to receive normal stream again
}


Xively graphs of stream1 and stream2 as generated by above demo sketch

Xively graphs of stream1 and stream2


Sketch-level API documentation

Sketch-level API for class Rfx (Summary)

1) Initialization and status methods

Rfx Rfx();
void begin_id(uint8_t requested_port, const char* id_string);
bool sync();
bool sync(unsigned long refract);
bool joined();

2) Output stream methods

2.1) Output stream methods (configuration and status)

inline void set_output_devs(int i);
inline uint8_t get_output_devs();
inline int space();

2.2) Output stream write methods

inline bool write(uint8_t c);
inline int write(uint8_t *buf, int n);

2.3) Output stream print methods (strings)

inline int pr(“this string is stored in ram”);
inline int prln(“this string is stored in ram”);
inline int print(“this string is stored in ram”);
inline int println(“this string is stored in ram”);

inline int prln();
inline int println();

2.4) Output stream print methods (flash memory strings)

fp(“this string is stored in flash memory”)
fpln(“this string is stored in flash memory”)

2.5) Output stream print methods (numeric)

Template overloaded output stream method definitions for integer types:

inline int pr(TYPE_T i)
inline int print(TYPE_T i)
inline int prln(TYPE_T i)
inline int println(TYPE_T i)
inline int pr(INT_T i, int radix)
inline int print(INT_T i, int radix)
inline int prln(INT_T i, int radix)
inline int println(INT_T i, int radix)

Overloaded output stream methods for float types:

int pr(float|double f);
int prln(float|double f);
int pr(float|double f, int p);
int prln(float|double f, int p);

2.6) Output stream printf() methods

prf(“printf format string stored in ram memory %d etc\n”,…);
fpf(“printf format string stored in flash memory %d etc\n”,…);

3) Alerts methods

int alert_start_request(int alert);
int alert_start_request(int alert, int ms);
int alert_stop_request();
int alert_stop_request(int ms);

4) Exec methods

int exec_start_request();
int exec_start_request(int ms);
int exec_recv_request();
int exec_recv_request(int ms);
bool exec_recv_eof();
int exec_stop_request();
int exec_stop_request(int ms);

5) Input stream methods

inline int available();

inline int read();
inline int read(uint8_t *dest_buf, int max) ;

inline int read_until(const char* s);
inline int read_until(const char* s, long ms);
inline int read_until(const char* s, long ms, int max);
inline int read_until(const char* s, long ms, uint8_t *dest_buf, int max);
inline bool matched();

6) TCP/IP port connection methods

inline bool port_connected();
inline void port_close();
inline void port_close_final();
Sketch-level API for class Rfx (Detailed)

1) Initialization and status methods:


Rfx Rfx();
void begin_id(uint8_t requested_port, const char* id_string);
bool sync();
bool sync(unsigned long refract);
bool joined();

You set-up and initialise a RFXduino sketch with the following steps:

#include "Rfx_config.h" // a handy place to define various configuration settings
#include <Rfx_r3.h>     // the main library, installed under "libraries" folder
#include         // required if using the HW_SPI option

Rfx rfx; // instantiate an Rfx object to manage buffered TCP/IP streams via RPi hub

void setup()
{

 Serial.begin(115200);

 rfx.begin_id(BOARD_ID,ID_STRING); // usually defined as macros in Rfx_include.h

 /*
 anything else you need to intialize for your sketch…
 */

 while (!rfx.joined()); // in case you want to wait until your board has joined
                        // the RPi hub with the nRF24L01+ wireless link before
                        // proceeding
}

void loop()
{
 /*
 main loop logic in here…
 */
 rfx.sync(); // call this on a regular basis to keep the nRF24L01+ connection
             // in good shape
}

That’s the bare bones of a RFX enabled sketch. The joining of the nRF24L01+ link to the hub occurs in the background automatically, if a compatible hub is in range. If the wireless link drops out, attempts to rejoin will occur automatically.


2) Output stream methods

2.1) Output stream methods (configuration and status):


inline void set_output_devs(int i);
inline uint8_t get_output_devs();
inline int space();

By default, writing or printing to the rfx output stream sends characters to both the wireless RFX virtual TCP/IP link and to the serial COM port output. This can be controlled via the get/set_output_devs() methods:

rfx.set_output_devs(DEV_RADIO); // set output to just radio link

or

rfx.set_output_devs(DEV_SERIAL); // set output to just serial COM port

or

rfx.set_output_devs(DEV_RADIO|DEV_SERIAL); // set output to both (default)

or

rfx.set_output_devs(0); // set output to neither (bit-bucket)

To retrieve the current setting

uint8_t devs = rfx.get_output_devs();

so you can

rfx.set_output_devs(devs|DEV_RADIO); // enable output to radio link

etc., if so desired.

Before writing or printing characters to the Rfx output stream, it may be useful to determine how much space is currently available.

int sp = rfx.space();

returns the available space in the Rfx object output stream buffer.


2.2) Output stream write methods:


inline bool write(uint8_t c);
inline int write(uint8_t *buf, int n);

rfx.write(uint8_t c);

writes a single byte to the output stream buffer, returning true if successful.

rfx.write(uint8_t *buf, int n);

writes n bytes from buffer buf to the output stream buffer, returning no. of bytes written.


2.3) Output stream print methods (strings):


inline int pr("this string is stored in ram");
inline int prln("this string is stored in ram");
inline int print("this string is stored in ram");
inline int println("this string is stored in ram");

inline int prln();
inline int println();

Next, there are the various print methods; these are closely analogous to the Serial.print() methods in how they operate.

rfx.print("This is the long version");

sends a string to the rfx output stream buffer, but also

rfx.pr("This is the shorter version");

in case brevity is preferred. Exactly the same method, merely syntactic sugar.

As well as print()/pr(), there is println() /prln().

These operate as expected, automatically adding a CR LF at the end of the string, as in Serial.println(). However, the default behaviour can be modified by a Rfx_config.h setting.

Defining the macro

#define NEWLINE_STRING "\n"

will change the println() behaviour to add ing just a LF, rather than a CR LF, for example. NEWLINE_STRING can be set to any arbitrary string (note: it must be a string, double quotes, not a char, single quotes.). If not defined, the default CR LF setting will be respected.


2.4) Output stream print methods (flash memory strings):


fp("this string is stored in flash memory")
fpln("this string is stored in flash memory")

To save ram, there are also output stream flash/program memory print methods:

rfx.fp("this string is stored in flash memory");
rfx.fpln("this string is stored in flash memory");

Note that fp() and fpln() are implemented as macros that declare strings automatically as PSTR().


2.5) Output stream print methods (numeric):


template overloaded output stream method definitions for integer types:

inline int pr(TYPE_T i)
inline int print(TYPE_T i)
inline int prln(TYPE_T i)
inline int println(TYPE_T i)
inline int pr(INT_T i, int radix)
inline int print(INT_T i, int radix)
inline int prln(INT_T i, int radix)
inline int println(INT_T i, int radix)

Float types:

int pr(float f);
int prln(float f);
int pr(float f, int p);
int prln(float f, int p);

The print()/pr() and println()/prln() methods also operate as expected on numeric types.

For integers, the second optional parameter specifies the radix. If omitted, the default radix is DEC. Options are HEX, DEC, OCT, BIN.

For floating point types, the sec second optional parameter specifies the number of decimal places printed. If omitted, the default is two decimal places.

float pi = 3.14159;
rfx.pr(pi); // prints 3.14
rfx.pr(pi,4); // prints 3.1416
rfx.pr(pi,6); // prints 3.141590

2.6) Output stream printf() methods:


prf("printf format string stored in ram memory %d etc\n",…);
fpf("printf format string stored in flash memory %d etc\n",…);

For greater control of printing formatting, implementations of printf() are available as output stream print methods:

rfx.prf("printf format string stored in ram memory %d etc\n",…);

In general, the flash memory string printf methods would be preferred:

rfx.fpf("printf format string stored in flash memory %d etc\n",…);

The RFX implementations of printf() do not rely on the gcc lib printf() functions, as the gcc lib versions are not ram efficient. Also, the RFX implementations of printf() support floating point/flash strings/C++ Strings as printable data types.


2.7) Output stream print methods mirrored as standalone functions for serial COM port


For convenience, the RFX output stream print methods and macros are mirrored as standalone functions to do the equivalent serial IO on the serial COM port (i.e., providing more succinct syntax for the Serial.print() methods). Hence:

pr(…) -> Serial.print(…)
prln(…) -> Serial.println(…)
fp("this string is in flash") -> Serial.print(F("this string is in flash"))
fpln("this string is in flash") -> Serial.println(F("this string is in flash"))
prf(…) -> printf(…)
fpf(…) -> printf_P(…)

This results to greater consistency of syntax, and also makes the code more portable between supported X:duino platforms.


3) Alerts methods:


int alert_start_request(int alert);
int alert_start_request(int alert, int ms);
int alert_stop_request();
int alert_stop_request(int ms);

To initiate sending an alert message, an alert_start_request() method is called.

bool ack = rfx.alert_start_request(ALERT_EMAIL);

will return true if the request is successful, and

bool ack = rfx.alert_start_request(ALERT_EMAIL, 5000);

will do the same, but with a 5000 ms timeout, returning false if no ack is received with the timeout.

The timeout version is recommended, to prevent waiting indefinitely in case an ack is missed because a link drops out, etc.

After the start request has been acknowledged, writing to the output stream buffer will write the alert message, and anything written will not be part of the normal TCP/IP stream:

rfx.fpln("This is my email alert message.");
rfx.fpln("For an email it can be arbitrarily long.");

To signal completion in writing the alert message, issue an alert_stop_request():

bool ack = rfx.alert_stop_request();

will return true if the request is successful, and

bool ack = rfx.alert_stop_request(5000);

does the same thing with a timeout. Once an acknowledgement is received after a stop request, writing to the Rfx output stream buffer will return to sending to the usual TCP/IP port connection.


4) Exec methods:


int exec_start_request();
int exec_start_request(int ms);
int exec_recv_request();
int exec_recv_request(int ms);
bool exec_recv_eof();
int exec_stop_request();
int exec_stop_request(int ms);

An exec request is similar to an alert request, except there is also a “recv” step where the output from the executed Linux command or script is returned on the input stream.

To initiate sending an alert message, an alert_start_request() method is called.

bool ack = rfx.exec_start_request();

will return true if the request is successful, and

bool ack = rfx.exec_start_request(5000);

will do the same, but with a 5000 ms timeout, returning false if no ack is received with the timeout.

As with the alert service, the timeout version is recommended, to prevent waiting indefinitely in case an ack is missed because a link drops out, etc.

After the start request has been acknowledged, writing to the output stream buffer will write the exec command message, and anything written will not be part of the normal TCP/IP stream. E.g.:

rfx.fp("date \"+%Y-%m-%dT%H:%M:%SZ\"\n");

asks for the system date from the gateway device using unix cmd “date” specifying a iso-8601 format (suitable for xively, etc.)

To signal completion in writing the exec command, and to switch to listening for the resulting stdout directed output on the input stream, issue an exec_recv_request():

bool ack = rfx.exec_recv_request();

will return true if the request is successful, and

bool ack = rfx.exec_recv_request(5000);

will do the same, but with a 5000 ms timeout, returning false if no ack is received with the timeout.

The read_until() and matched() methods were developed to simplify parsing the exec output returned on the input stream. These methods are described in detail in the next section, “Input stream methods”, but it is natural to discuss them here.

In our exec command example above, we expect a date string returned in the format “2013-09-30T23:59:30Z” (21 chars including EOL delimiter, no quotation marks.)

We could use read_until() and matched() to parse this in two steps, first verifying the ‘T’ is where it should be, and secondly verifying the ‘Z’and EOL delimiter (LF) are where they should be at the end.

int n = rfx.read_until("T", 5000, tbuf, 11);

will read the input stream looking for a “T” for max 11 chars, or until a 5s timeout, placing the characters read into buffer tbuf.

The read_until() method will also return -1 if there is no more exec command output to be read (an eof is signalled).

The return value n is the number of characters read by this call to read_until().

If the substring “T” was found, then a subsequent call to method matched() will return true. So to verify that 11th char is indeed a ‘T’, we can test for the condition

(rfx.matched() && n == 11)

If true, we could then test for the “Z\n” substring:

n += rfx.read_until("Z\n", 5000, (tbuf+11), 10); //read for max 10 chars or eof(),
                                                 // 5s timeout
if (rfx.matched() && n == 21) { // verify that chars 20 and 21 are 'Z' and '\n'
  // looks like a good date string to me!
  . . .
}

Finally, we signal completion of receiving and processing the exec command output by issuing an exec_stop_request():

bool ack = rfx.exec_stop_request();

will return true if the request is successful, and

bool ack = rfx.exec_stop_request(5000);

does the same thing with a timeout. Once an acknowledgement is received after a stop request, writing to the Rfx output stream buffer will return to sending to the usual TCP/IP port connection.


5) Input stream methods:


inline int available();

inline int read();
inline int read(uint8_t *dest_buf, int max) ;

inline int read_until(const char* s);
inline int read_until(const char* s, long ms);
inline int read_until(const char* s, long ms, int max);
inline int read_until(const char* s, long ms, uint8_t *dest_buf, int max);
inline bool matched();

The available() method returns how many characters are currently available for reading in the input stream buffer:

int n = rfx.available(); // get number of characters waiting, if any

The read() method either reads the next charcter from the input stream buffer:

int c = rfx.read(); // read next available character

or will return -1 if the buffer is empty. If a buffer and a max parameter are used:

int n = rfx.read(tbuf, sizeof(tbuf));

then up to max characters will be read into the destination buffer, but fewer than max if rfx.available() < max. The return value is the number of characters actually read.

The read_until() method has four overloaded forms. All of them specify a character string of one or more characters that is used to match on a contiguous series of characters reading from the input stream.

The first form:

n = rfx.read_until("The");

will read characters from the input stream until the “The” substring is encountered, or a stream eof() condition is detected. The characters read are discarded, and the method returns the number of characters read.

The second form:

n = rfx.read_until("The", 5000);

also specifies a timeout value in milliseconds. It will return as per the first form, but also if the timeout is reached. (But note that if ms < 0, then the timeout value is ignored, and it will wait indefinitely, equivalent to the first form.) To determine whether the return condition was a string match, or a timeout or eof(), the matched() method can be used:

bool m = rfx.matched();

which returns true if the match was found and false otherwise.

The third form:

int n = read_until("The", 5000, 20);

adds a max number of characters to be read as a constraint and possible return condition
If max characters are read, the method will return whether or not a match has been found. (Note that if max < 0, the parameter is ignored, and the method will behave equivalently to the second form.)

The fourth form:

int n = read_until("The", 5000, tbuf, sizeof(tbuf));

does not discard the characters as they are read, but rather they are transferred to specified buffer dest_buf. It requires specifying a max value to prevent potential buffer overruns. (Note that if max < 0, the method will read indefinitely, but will not transfer characters to the specified buffer, i.e., the method will behave equivalently to the second form.)


6) TCP/IP port connection methods:


inline bool port_connected();
inline void port_close();
inline void port_close_final();

The TCP/IP port connections methods control and report the status of the incoming TCP/IP port connection associated with the data stream. If there is a current socket connection on the port,

bool s = rfx.port_connected();

returns true, otherwise false.

To close the current active socket connection on the incoming TCP/IP port (e.g., to signal the end of an html response)

rfx.port_close();

drops the port connection. After the socket is closed, it is reopened in a listening state, waiting for the next connection.

If the socket is to be closed permanently (i.e., close but do not reopen in listening state for a new connection), the method

rfx.port_close_final();

is used.

Addendum: Using RFX Virtual RTC methods

Addendum: Using RFX Virtual RTC (Real-time clock) methods

The virtual RTC methods are part of the Rfx class, and are enabled by defining the VIRT_RTC macro in the Rfx_config.h file:

#define VIRT_RTC 1

The virtual RTC methods extend the functionality of basic get_udate() (get Unix date) method, creating a system that simulates a hardware RTC clock.

When the RFX client/slave joins the network, the gateway provides the current Unix system time, which initializes the virtual RTC. Subsequently, the virtual RTC is updated using the millis() timer to keep an estimate of the current time. At midnight, the virtual RTC will call get_udate() to resync the virtual RTC with the Unix system time from the gateway.

By default, the RTC time is UTC (a.k.a. GMT). If you want the virtual RTC to keep a local time instead, the macro TZ_LOCALE can be define in Rfx_config.h. For example

#define TZ_LOCALE "Australia/Brisbane"

will keep time in Brisbane, Australia local time (UTC +10:00), and

#define TZ_LOCALE "America/Denver"

will keep time in Denver, Colorado. (UTC -7:00, UTC -6:00 if DST)

So the daylight saving offset will be applied automatically if it applies. (For other time zone locale strings, search for “list of tz database time zones” for linux systems.)

All date/time data is held in the following struct:

struct date {

  uint16_t year;

  uint8_t month, day, hours, mins, secs, dow;

  uint16_t ms;

  unsigned long last_update;

  int16_t tz_mins;

  bool tz_set;

  bool reset_required;
};

An instance of the date struct named virt_rtc holds the virtual RTC clock time. This date struct is automatically initialized from the Raspberry Pi clock when the slave joins the master. It is then updated and manipulated by various virtual RTC methods of the Rfx class.

Of the virtual RTC methods, the update_rtc()  and print_rtc()/println_rtc() are the most used at the application level.

update_rtc()

Calling update_rtc() periodically is all that is required to keep the virt_rtc time up to date. It could naturally be placed in the loop() function of the sketch, to keep the virt_rtc variables current. For example,

Rfx rfx;

void loop()

{

  :
  :

  rfx.update_rtc(); // keep virtual rtc updated

  rfx.sync(); // do this regularly to verify nRF24L01+ status
}

update_rtc() will also call refresh_rtc(), reset_rtc() and get_udate() as required to periodically resync with the gateway system time. After update_rtc() is called, the up-to-date virt_rtc variables can be accessed as so:

  int day = virt_rtc.day; // day of month (1..31)
  int dow = virt_rtc.dow; // day of week (0..6, Sun=0, Sat=6)
  int month = virt_rtc.month; // Jan=1, Dec=12
  :

etc.

update_rtc()  is the overloaded form of update_rtc(date *d). If the date struct pointer argument is omitted, &virt_rc is assumed. You would normally just use the update_rtc() form.

Note that if VIRT_RTC is defined, calling get_udate()  will return the virtual rtc time, rather than accessing the gateway directly each time. To manually force resynchronization with the gateway, you can set

virt_rtc.reset_required = true;

before calling get_udate().

Resynchronization with gateway time is automatically flagged at day rollover (i.e., midnight) each day.

print_rtc()/println_rtc()

The virt_rtc time and date variables can be directly accessed and used in date calculations and to produce time stamps, date strings, etc., in any way or format desired, but to provide a convenient way of printing out the virtual RTC date and time, the print_rtc() and println_rtc() methods can be used.

The class Rfx methods print_rtc(…) and println_rtc(…) have several overloaded forms.

void Rfx::print_rtc(date *d, int8_t output_devs);

with two arguments is the most general form. It prints to the output devices specified by output_devs the date and time held in date struct d, in the format hh:mm:ss Dow Mth dd yyyy, e.g.:

18:31:05 Sun Jan 18 2015

(Note: The three letter day of week strings “Sun” .. “Sat”, and the month strings “Jan”…”Dec” are defined in Rfx methods weekdays() and months() respectively, and can be edited for your language if not English.)

The specified output device(s) can be the serial output stream (DEV_SERIAL), the radio output stream (DEV_RADIO), or both (DEV_SERIAL|DEV_RADIO).

The current virtual real time clock is held in a date struct virt_rtc, so

rfx.print_rtc(&virt_rtc, DEV_SERIAL);

prints the current virtual rtc time to the serial port only

rfx.print_rtc(&virt_rtc, DEV_RADIO);

prints the current virtual rtc time to the radio only, and

rfx.print_rtc(&virt_rtc, (DEV_RADIO|DEV_SERIAL));

to both.

Note that if the date struct d argument is omitted, &virt_rtc is used in its place. And if the output_devs argument is omitted, the current output devices setting (set by method set_output_devs() is used. So, for example,

rfx.print_rtc(DEV_SERIAL);

is equivalent to

rfx.print_rtc(&virt_rtc, DEV_SERIAL);

and

rfx.print_rtc();

(without any arguments) prints out the current virtual rtc time to the currently set output devices (which would probably be the most commonly used form).

The println_rtc(…) methods are as above, but additionally add a newline at end of the output string as a convenience.

 

Addendum: Using RFX WDT (watchdog timer) functions

The three RFX watchdog timer (WDT) functions

void wdt_start()
void wdt_stop()
void wdt_pat()

provide generic wrappers around the chip specific WDT functions. The WDT functions are enabled by defining the WDT macro in the Rfx_config.h file:

#define RFX_WDT 1

If the RFX_WDT macro is not defined, or defined as 0, then the WDT functions are declared as empty so as to do nothing when called.

But if the RFX_WDT macro is defined as 1, then the three functions wdt_start(), wdt_stop(), and wdt_pat() provide wrappers for the corresponding architecture specific functions.

For example, if the sketch was being built for an Atmel AVR architecture chip, then the wrappers look like this:

#include <avr/wdt>;
inline void wdt_start() { wdt_enable(WDTO_8S); wdt_reset(); }
inline void wdt_stop() { wdt_disable(); }
inline void wdt_pat() { wdt_reset(); }

This enables a WDT with an 8 second timeout (the maximum for AVR) when wdt_start() is called (typically in setup()). The timeout is reset whenever wdt_pat() is called at various points in the sketch. (See example sketch at end to illustrate use.) The WDT is disabled when wdt_stop() is called.

Note that for ARM architecture devices, it is not possible to disable a watchdog timer once enabled. So for the ARM devices (e.g., TEENSY3, MAPLE5), wdt_stop() is defined as an empty function and will not do anything. This is not a great disadvantage, however; generally, once a WDT is enabled in a program it is normally expected it will remain activated until the next reset occurs.

For consistency, a standard 8s timeout is implemented for all supported architectures when using wdt_start(). (If you need more precise control than this, use the underlying architecture-specific function directly.)

If the timer is allowed to timeout, then the chip performs a hardware reset and the is restarted from setup(). This normally to guard against the program hanging, but it can also be useful to enable a software controlled reset for a deliberate restart, e.g.:

void reboot() {
  rfx.fp(“Rebooting in 8 seconds…”);
  rfx_delay(9000); // wait until WDT restarts device
}

(Of course, the above will only work if #define RFX_WDT 1 is defined. Otherwise, it will simply exit after 9 seconds.)

Arduino Due: Special considerations

Also note that the Arduino Due has some special compatibility issues, and the RFX WDT functions are not (yet) implemented to work for Due. The incompatibility may be addressed in an upcoming revision of the IDE, however – possibly 1.6.5.

(There are work arounds to get the WDT functions working for the Due, but it involves some manual modifications of the Arduino core files.)

RFX_WDT replaces older WDT macro

Finally, the RFX_WDT macro setting now replaces the older WDT macro in RFXduino sketches, to allow for future compatibility with Due. The older

#define WDT 1

form will still be supported in non-Due devices, but there will be a deprecation warning* at build time:

“#define WDT 1 is now deprecated. Replace with #define RFX_WDT 1 for compatibility with Due.”

So while

#define WDT 1

will continue to work, by changing this to

#define RFX_WDT 1

you will retain source code portability across all supported devices, including Due in the future.

(* If you don’t see this warning, you have an older version of the RFX libs, please contact support@embeddedcoolness.com for an update.)

Illustrative RFX WDT sketch

#include <Arduino.h>;
#include "Rfx_config.h"

#define RFX_WDT 1 // could put this in Rfx_config.h for convenience.
                  // (macro must be defined before Rfx_r3.h)
#include <Rfx_r3.h>;
#include <SPI.h>;

Rfx rfx;

int snacks = 5;

void setup() {
  Serial.begin(115200);
  rfx.begin_id(BOARD_ID, ID_STRING);
  rfx_delay(4000); // allow a few secs to establish serial connection
  wdt_start(); // init an 8s wd timer
  rfx.fpln("\r\nhmm, thats a mean looking dog!");
}

void loop() {
  if (snacks &gt; 0) {
    rfx.fpln("nice doggy, here's a snack");
    wdt_pat();
    --snacks;
  }
  else {
    rfx.fpln("uh oh, I've run out of snacks...");
  }
  rfx_delay(1000);
  rfx.sync();
}

If the WDT is active, you will see as output:

hmm, thats a mean looking dog!
nice doggy, here's a snack
nice doggy, here's a snack
nice doggy, here's a snack
nice doggy, here's a snack
nice doggy, here's a snack
uh oh, I've run out of snacks...
uh oh, I've run out of snacks...
uh oh, I've run out of snacks...
uh oh, I've run out of snacks...
uh oh, I've run out of snacks...
uh oh, I've run out of snacks...
uh oh, I've run out of snacks...
uh oh, I've run out of snacks...

before the device resets, and repeats the dialog.

If you see more than eight

“uh oh, I've run out of snacks...”

messages in a row, then the watchdog timer has failed for some reason. If the watchdog timer terminates the sketch, but it fails to restart properly, the most likely problem is that the bootloader on the Arduino device doesn’t support WDT restart.

Bootloader issues

If the WDT fails to restart the Arduino device properly, typically with the board getting into a tight restart loop with a rapidly flashing board LED, you may need to update the bootloader on your Arduino device. WDT support has been a bit patchy over the history of Arduino devices, and some early bootloaders diid not support WDT, the philosophy being WDT as being “too dangerous” for beginners.

Here’s a rundown of the support of WDT for various Arduino models and some derivatives, and the steps to take if your bootloader needs upgrading:

UNO: The latest “optiboot” bootloader for Uno supports WDT. If you have an older bootloader installed on a Uno (or similar 328p-based device), simply select Tools|board as “Uno” in the IDE and then reflash via Tools|Burn bootloader using a suitable ISP programming device (such as the USBasp.)

NANO: Some Nano clones ship with an older bootloader; these may not support WDT. The recommendation is to reflash with the optiboot bootloader for the Uno, which means that it will appear to be an Uno rather than a Nano when selecting the board type from the Tools|Board menu of the IDE, but it will now support WDT properly.

MEGA 2560: Some Mega2560 boards still ship with a bootloader that does not support WDT; however, the latest bootloader for the Mega2560 that is distributed with the Arduino IDE now supports WDT. So to update a Mega2560 or clone, reflash with the “burn bootloader” option in the IDE for a Mega2560.

MEGA (Mega AT1280): Unfortunately, for whatever reason, the standard bootloader distributed for the Mega1280 with the Arduino IDE still does not support WDT. Fortunately however, there is a version of the optiboot bootloader especially created for the Mega1280 that supports WDT.

To upgrade a Mega1280 is a two-step process. The first step is to burn the new bootloader for the device. The second step is to add a new boards.txt entry to support the upgraded Mega 1280.

To make this as simple as possible, a zip file with the various files and installation instructions is available (contact support@embeddedcoolness.com). When these files have been installed, a new board type entry called “Arduino Mega1280 Optiboot” will appear in the boards menu of the IDE. Use this entry to burn the bootloader and to program the board by the IDE after that.

DUE: Due doesn’t currently support WDT, but in this case, the issue is the IDE core files, not the bootloader. This *should* be rectified in IDE 1.6.5., after which WDT should “just work”.

LEONARDO: The Leonardo boootloader has limited support for WDT. The “Caterina” Leonardo bootloader firmware may not handle the virtual serial port over USB connection properly over the WDT restart, however. (Hint: Do not use while(!Serial); construct after Serial.begin() – may hang after restart as Serial never becomes “true”.) Also, if a serial connection is present, the WDT may become disabled after restart, and not fire at all. Overall, only reliable if a serial connection is not open over the WDT restart.

PJRC TEENSY 3.0/3.1/LC: The Teensy 3.x/LC boards have always supported WDT.

Leaflabs Maple r5/Maple Mini and clones: The Maple devices have always supported WDT.

Demo projects

Also, now under the Demos tab, is a documentation section set up for RFXduino demo projects, providing complete project documentation, including full sketch source code, schematics etc. for fully deployable real world RFX projects, to pick up where the short “example” programs above finish. The goal is to provide a resource so people can start with a fully working project that is similar to, but not exactly what they were intending to do for their own project, and adapt it accordingly.