diff --git a/Examples/IOShield/IOShield.ino b/Examples/IOShield/IOShield.ino
new file mode 100644
index 0000000..4580752
--- /dev/null
+++ b/Examples/IOShield/IOShield.ino
@@ -0,0 +1,345 @@
+// **********************************************************************************
+// IOShield sample sketch works with Moteinos equipped with RFM69W/RFM69HW
+// Can be adapted to use Moteinos/Arduinos using other RFM69 variants (RFM69CW, RFM69HCW) or even RFM12b
+// http://moteino.com
+// http://www.LowPowerLab.com/IOShield
+// 2015-03-13 (C) Felix Rusu of Low Power Lab LLC
+// **********************************************************************************
+// It works with IOShield(s) that have 2 shift registers (74HC595)
+// You can daisy chain up to 16 IOShields for a total of 256 outputs/stations/zones
+// If you chain more than 2 IOShields be sure to adjust the REGISTERCOUNT setting below in the define section
+// Also you must adjust the radio settings: frequency/ HW setting, encryption key etc below in the define section
+// It listens for tokens like:
+// - 'ON:N' where N={1..16} - turns ON one output dictated by position N
+// - 'ALL' - turns ON all outputs
+// - 'OFF' turns off all outputs
+// - 'PRG A:n ... Z:m' - runs a program in sequence, first token is station/zone/output number, second is the number of seconds to turn it ON for
+// WARNING: there is no delay between switching zones, so beware of the frequency you switch the valves on/off
+// **********************************************************************************
+// License
+// **********************************************************************************
+// This program is free software; you can redistribute it
+// and/or modify it under the terms of the GNU General
+// Public License as published by the Free Software
+// Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will
+// be useful, but WITHOUT ANY WARRANTY; without even the
+// implied warranty of MERCHANTABILITY or FITNESS FOR A
+// PARTICULAR PURPOSE. See the GNU General Public
+// License for more details.
+//
+// You should have received a copy of the GNU General
+// Public License along with this program.
+// If not, see .
+//
+// Licence can be viewed at
+// http://www.gnu.org/licenses/gpl-3.0.txt
+//
+// Please maintain this license information along with authorship
+// and copyright notices in any redistribution of this code
+// **********************************************************************************
+#include //get it here: http://github.com/lowpowerlab/rfm69
+#include //get it here: http://github.com/lowpowerlab/spiflash
+#include //get it here: https://github.com/LowPowerLab/WirelessProgramming
+#include //comes with Arduino IDE (www.arduino.cc)
+//*****************************************************************************************************************************
+// ADJUST THE SETTINGS BELOW DEPENDING ON YOUR HARDWARE/SITUATION!
+//*****************************************************************************************************************************
+#define GATEWAYID 1
+#define NODEID 121
+#define NETWORKID 250
+#define FREQUENCY RF69_915MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ)
+#define ENCRYPTKEY "sampleEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less!
+//#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!
+
+#define LATCHPIN 5
+#define CLOCKPIN 6
+#define DATAPIN 7
+#define REGISTERCOUNT 2 //Moteino IOShield has 2 daisy chained registers, if you have more adjust this number
+//*****************************************************************************************************************************
+#define LED 9 //pin connected to onboard LED
+#define SERIAL_BAUD 115200
+#define SERIAL_EN //comment out if you don't want any serial output
+
+#ifdef SERIAL_EN
+ #define DEBUG(input) Serial.print(input)
+ #define DEBUGln(input) Serial.println(input)
+#else
+ #define DEBUG(input)
+ #define DEBUGln(input)
+#endif
+
+RFM69 radio;
+/////////////////////////////////////////////////////////////////////////////
+// flash(SPI_CS, MANUFACTURER_ID)
+// SPI_CS - CS pin attached to SPI flash chip (8 in case of Moteino)
+// MANUFACTURER_ID - OPTIONAL, 0xEF30 for windbond 4mbit flash (Moteino OEM)
+/////////////////////////////////////////////////////////////////////////////
+SPIFlash flash(8, 0xEF30); //regular Moteinos have FLASH MEM on D8, MEGA has it on D4
+char buff[20]; //max radio DATA length = 61
+String str;
+String substr;
+
+void setup(void)
+{
+ Serial.begin(SERIAL_BAUD);
+ pinMode(LATCHPIN, OUTPUT);
+ pinMode(DATAPIN, OUTPUT);
+ pinMode(CLOCKPIN, OUTPUT);
+ pinMode(LED, OUTPUT);
+
+ radio.initialize(FREQUENCY,NODEID,NETWORKID);
+#ifdef IS_RFM69HW
+ radio.setHighPower(); //uncomment only for RFM69HW!
+#endif
+ radio.encrypt(ENCRYPTKEY);
+
+ //sprintf(buff, "IOShield : %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
+ //DEBUGln(buff);
+ DEBUGln(F("START"));
+
+ if (flash.initialize())
+ DEBUGln(F("SPI Flash Init OK"));
+ else
+ DEBUGln(F("SPI Flash Init FAIL! (is chip present?)"));
+
+ radio.sendWithRetry(GATEWAYID, "START", 5);
+ zonesOFF();
+ Blink(LED, 100);
+ Blink(LED, 100);
+ Blink(LED, 100);
+ DEBUG("Free RAM:");DEBUGln(checkFreeRAM());
+}
+
+byte LEDSTATE=LOW;
+uint32_t LEDCYCLETIMER=0;
+byte programZone[32]; //used to store program data
+unsigned int programSeconds[32]; //used to store program data
+byte programLength=0; //how many zones in this program
+byte programPointer=0; //keeps track of active zone (when >=0)
+unsigned int seconds=0;
+byte whichZone;
+int index;
+
+void loop()
+{
+ if (radio.receiveDone())
+ {
+ DEBUG(F("["));DEBUG(radio.SENDERID);DEBUG(F("] "));
+ DEBUG((char *)radio.DATA);
+ DEBUG(F(" [RX_RSSI:"));DEBUG(radio.RSSI);DEBUGln("]");
+
+ // wireless programming token check
+ // DO NOT REMOVE, or this node will not be wirelessly programmable any more!
+ CheckForWirelessHEX(radio, flash, true);
+
+ whichZone=0;
+ str = String((char *)radio.DATA);
+ str.trim();
+ if (str.equals(F("OFF"))) zonesOFF();
+ else if (str.equals(F("ALL"))) zonesAllON(); //for testing registers only, you should never turn ON all zones in a sprinkler system
+ else if (str.length() >= 4 && str.startsWith("ON:")) //ON:zoneNumber
+ {
+ str = str.substring(3); //trim "ON:"
+ whichZone = str.toInt(); //extract zone id
+ if (whichZone > 0) {
+ stopAndResetProgram();//this command forces any programs to stop and only set the requested zone/output ON
+ zoneON(whichZone);
+ }
+ else DEBUG("Invalid ON");
+ }
+ else if (str.length() >= 7 && str.startsWith("PRG ")) //PRG 1:5 2:5 3:10 4:5 .... zoneN:seconds
+ {
+ str = str.substring(4); //trim "PRG "
+ while (str.length()>=3 && programPointer < 255)
+ {
+ whichZone = str.toInt(); //extract zone id
+ index = str.indexOf(':');
+ if (index > 0 && str.length() > index) //make sure there's something after the colon
+ {
+ str = str.substring(index+1); //trim "zoneId:"
+ seconds = str.toInt(); //extract seconds
+ if (seconds > 0)
+ {
+ programZone[programLength] = whichZone;
+ programSeconds[programLength] = seconds;
+ programLength++;
+
+ DEBUG("Extracted ZONE");
+ DEBUG(whichZone);
+ DEBUG(":");
+ DEBUG(seconds);
+ DEBUGln("s");
+ }
+ else
+ {
+ programLength = 0;
+ DEBUG("INVALID PRG");
+ break;
+ }
+ }
+ else
+ {
+ programLength = 0;
+ DEBUG("INVALID PRG");
+ break;
+ }
+
+ //trim current token and move to next one
+ index = str.indexOf(' ');
+ if (index > 0 && str.length() > index+3) //X X:X
+ {
+ str = str.substring(index+1);
+ }
+ else //EOS?
+ {
+ DEBUG( programLength>0 ? "DONE" : "INVALID PRG");
+ break;
+ }
+ }
+ DEBUG(F("Found programs:"));DEBUGln(programLength);
+ }
+
+ //respond to any other ACKs
+ if (radio.ACKRequested()) radio.sendACK();
+ DEBUGln();
+ DEBUG("Free RAM:");DEBUGln(checkFreeRAM());
+ }
+
+ handleProgram();
+
+ if (millis() - LEDCYCLETIMER > 2000) //flip onboard LED state every so often to indicate activity
+ {
+ LEDCYCLETIMER = millis();
+ LEDSTATE = !LEDSTATE;
+ digitalWrite(LED, LEDSTATE);
+ }
+}
+
+unsigned long programZoneStart=0;
+void handleProgram()
+{
+ if (programLength > 0)
+ {
+ if (programZoneStart == 0)
+ {
+ programZoneStart = millis(); //mark start time of a zone
+ zoneON(programZone[programPointer]);
+ DEBUG("Running zone ");
+ DEBUG(programZone[programPointer]);
+ DEBUG(" for ");
+ DEBUG((((unsigned long)programSeconds[programPointer])*1000));
+ DEBUGln("ms...");
+ }
+ else if (millis() - programZoneStart > (((unsigned long)programSeconds[programPointer])*1000)) //check if zone time expired, jump to next zone
+ {
+ programZoneStart=0;
+ programLength--;
+ if (programLength == 0) //finished
+ zonesOFF();
+ else programPointer++; //skip to next zone in program
+ }
+ }
+}
+
+void stopAndResetProgram()
+{
+ programLength=0;
+ programPointer=0;
+ programZoneStart=0;
+}
+
+//turns ON one zone only, all others off
+void zoneON(byte which)
+{
+ //stopAndResetProgram(); //stop any running programs
+ if (radio.ACKRequested()) radio.sendACK();
+ registersWriteBit(which-1);
+ sprintf(buff, "ZONE:%d", which);
+ if (radio.sendWithRetry(GATEWAYID, buff, strlen(buff)))
+ {DEBUGln(F("..OK"));}
+ else {DEBUGln(F("..NOK"));}
+}
+
+//all zones OFF
+void zonesOFF()
+{
+ stopAndResetProgram(); //stop any running programs
+ if (radio.ACKRequested()) radio.sendACK();
+ registersClear();
+ if (radio.sendWithRetry(GATEWAYID, "ZONES:OFF", 9))
+ {DEBUGln(F("..OK"));}
+ else {DEBUGln(F("..NOK"));}
+}
+
+//all zones ON - for testing purposes only
+void zonesAllON()
+{
+ stopAndResetProgram(); //stop any running programs
+ registersAllOn();
+}
+
+void registersClear() {
+ digitalWrite(LATCHPIN, LOW);
+ for(byte i=0;i