Fork to see if I can get working

Dependencies:   BufferedSerial OneWire WinbondSPIFlash libxDot-dev-mbed5-deprecated

Fork of xDotBridge_update_test20180823 by Matt Briggs

Files at this revision

API Documentation at this revision

Comitter:
Matt Briggs
Date:
Mon Jan 30 17:25:08 2017 -0700
Parent:
40:2ec4be320961
Child:
42:f4bce957ecab
Commit message:
Fisrt cut at implementing protocol refactor

Changed in this revision

xDotBridge/config.h Show annotated file Show diff for this revision Revisions of this file
xDotBridge/inc/CommProtocolPeerBrute.h Show annotated file Show diff for this revision Revisions of this file
xDotBridge/src/BaseboardIO.cpp Show annotated file Show diff for this revision Revisions of this file
xDotBridge/src/CommProtocolPeerBrute.cpp Show annotated file Show diff for this revision Revisions of this file
xDotBridge/src/main.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/xDotBridge/config.h	Thu Jan 26 17:36:59 2017 -0700
+++ b/xDotBridge/config.h	Mon Jan 30 17:25:08 2017 -0700
@@ -7,11 +7,10 @@
 
 // These define which wireless bridge you are generating code for
 #define BRIDGE_TX_BRUTE 0
-#define BRIDGE_RX_BRUTE 0
 
 #define LED_FEEDBACK 1  // If 1 then LED is shown and 0 LED is not shown to conserve power
 
-// Make eclipse happy by adding in macros which are typically added at compile time
+// Make eclipse IDE happy by adding in macros which are typically added at compile time
 #ifndef TARGET_XDOT_L151CC
 #define TARGET_XDOT_L151CC
 // Note these seem to need to be added to eclipse indexer to make everyone happy
@@ -24,7 +23,8 @@
 enum CmdResult {
     cmdSuccess=0,
     cmdCrcError=1,
-    cmdError=2
+    cmdTimeout=2,
+    cmdError=3
 };
 
 #endif
--- a/xDotBridge/inc/CommProtocolPeerBrute.h	Thu Jan 26 17:36:59 2017 -0700
+++ b/xDotBridge/inc/CommProtocolPeerBrute.h	Mon Jan 30 17:25:08 2017 -0700
@@ -2,55 +2,167 @@
  * Library for LoRa Peer to Peer Brute Force Protocol
 */
 
-#ifndef PEERBRUTECOMMPROTOCOL_H_
-#define PEERBRUTECOMMPROTOCOL_H_
+#ifndef COMMPROTOCOLPEERBRUTE_H_
+#define COMMPROTOCOLPEERBRUTE_H_
 
+#include <inttypes.h>
+#include <vector>
 #include "../config.h"
+#include "mDot.h"
 
 // TODO make base class to allow different protocols to be used with easy
+// TODO define how multiple RX would pair with a single TX
+// TODO wrap radio commands for error checking
+
+// TODO change to const
 static uint8_t pair_network_address[] = { 0x01, 0x02, 0x03, 0x04 };
 static uint8_t pair_network_session_key[] = { 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04 };
 static uint8_t pair_data_session_key[] =    { 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04 };
 
 /**
  *  @class PeerBruteCommProtocol
- *  @brief This class implements a peer brute force protocol.  The protocol
- *  consists of at a minimum one transmitter (TX) and one receiver (RX) which
- *  communicate via the 900MHz LoRa modulation.  The concept is that the RX is
- *  cycling on and off thus only listening for a small period of time.  Since
- *  we are not relying on a common time-base or other synchronization mechanism
- *  the TX simply transmits for a duration long enough guarantee that the RX will
- *  have at least one receive window during that time period.  Hence the name
- *  brute since the TX is just transmitting plenty for the RX to hear it.
+ *  @brief This class implements a peer-to-peer (P2P) brute force protocol.
+ *
+ *  @details The protocol consists of at a minimum one transmitter (TX) and one
+ *  receiver (RX) which communicate via the 900MHz LoRa modulation.  The concept
+ *  is that the RX is cycling on and off thus only listening for a small period
+ *  of time.  Since we are not relying on a common time-base or other
+ *  synchronization mechanism the TX simply transmits for a duration long enough
+ *  guarantee that the RX will have at least one receive window during that time
+ *  period.  Hence the name brute since the TX is just transmitting plenty for
+ *  the RX to hear it.
+ *
+ *  The following should be implemented outside of the class:
+ *  - Power settings?
+ *  - What to do with the msgs which are received
+ *  - When to send messages
+ *  - When to sleep
+ *
  */
-class PeerBruteCommProtocol
+
+class CommProtocolPeerBrute
 {
 public:
-    PeerBruteCommProtocol(bool isTx);
-    void init();
+    /**
+    * @brief CommProtocolPeerBrute constructor
+    *
+    * @details Just initialized internal variables does not configure devices.
+    * Should call init before other functions are called.
+    *
+    * @param isTx If true configures class as a transmitter otherwise receiver
+    *
+    * On Entry:
+    *
+    * On Exit:
+    * Internal variables are set to a known state but futher initialziation is required
+    *
+    * @return
+    */
+    CommProtocolPeerBrute(bool isTx);
 
+    /**
+     * @brief Initialize radio for chosen mode of operation (i.e. RX or TX)
+     *
+     * @return Returns the result of all the commands
+     */
+    CmdResult init();
+
+    /**
+     * @brief Returns weather this object is configured as a TX or RX
+     * @return Returns true if TX
+     */
     bool isTx();
+
+    /**
+     * @brief Returns weather this object is configured as a TX or RX
+     * @return Returns true if RX
+     */
     bool isRx() {return !isTx();}
 
-    uint32_t getDLC();
-    uint32_t getULC();
-
+    /**
+     * @brief This will clear the security pairs and channel info for pair
+     *
+     * @details This will clear both the value in RAM as well as the value stored in EEPROM for security and
+     * clarity purposes.  If RX this command will automatically trigger the generation of new security keys and
+     * pair specific parameters.
+     *
+     * @return Returns status of all commands completed
+     */
     CmdResult clearPair();
 
     // TX focused
+    /**
+     * @brief Transmit the msg attached
+     *
+     * @details TODO figure out what information is wrapped by the LoRaWAN stuff implemented by
+     * Multitech Systems
+     *
+     * @param msg A STL vector of uint8_t
+     * @return Returns status of all commands completed
+     */
     CmdResult send (const std::vector<uint8_t> &msg);
+
+    /**
+     * @brief This function sends a request to pair with a RX.  If successful a pair accept message is received.
+     *
+     * @return Returns status of all commands completed
+     */
     CmdResult sendPairReq();
 
     // RX focused
+    /**
+     * @brief This function enables the RX hardware of a radio.  Note the listen time is defined internally by the protocol
+     *
+     * @param msgPending This boolean is return by reference.  If true then during the listen window a msg was received.
+     * @return Returns status of all commands completed
+     */
     CmdResult listen (bool &msgPending);
+
+    /**
+     * @brief Returns the last message received via listening
+     *
+     * @param msg This STL vector of uint8_t is returned by reference with msg contents.
+     * @return Returns status of all commands completed
+     */
     CmdResult recv (std::vector<uint8_t> &msg);
+
+    /**
+     * @brief This fucntion enables the radio to listen for pair requests.
+     * @param waitTime The maximum time which radio waits for pair requests
+     *
+     * TODO determine if it is important to know who is paired
+     *
+     * @return If pair message received then cmdSucess is returned otherwise timeout is returned.
+     */
     CmdResult waitForPairing(float waitTime);
 
+    /**
+     * @brief Send a pair accept message.  This message contains all the information for TX to properly send
+     * msgs to RX in P2P mode.
+     * @return Returns status of all commands completed
+     */
+    CmdResult sendPairAccepted();
+
+    // xDot Peer to Peer Specific
+    /**
+     * Convenience function to get the internal downlink count from radio
+     * @return Number of downlink msgs
+     */
+    uint32_t getDLC();
+
+    /**
+     * Convenience function to get the internal uplink count from radio
+     * @return Number of uplink msgs
+     */
+    uint32_t getULC();
+
 private:
+    mDot *dot;
     uint8_t mNetworkAddr[4];
-    uint8_t pair_network_session_key[16];
-    uint8_t pair_data_session_key[16];
+    uint8_t mNetwork_session_key[16];
+    uint8_t mData_session_key[16];
     bool mIsTx;
+    unsigned int mWakeMode;
 
     /**
     * @brief Reads baseboard information from non-volatile memory (NVM)
@@ -84,8 +196,16 @@
     */
     CmdResult writeInfoToNVM();
 
+    /**
+     * Resets both uplink and downlink counters to zero.  Useful for when pairing.
+     * @return
+     */
     CmdResult resetCounters();
 
+    /**
+     * Generates new encryption keys for radio
+     * @return
+     */
     CmdResult genEncypKeys();
 };
 
--- a/xDotBridge/src/BaseboardIO.cpp	Thu Jan 26 17:36:59 2017 -0700
+++ b/xDotBridge/src/BaseboardIO.cpp	Mon Jan 30 17:25:08 2017 -0700
@@ -6,7 +6,7 @@
  */
 
 #include "BaseboardIO.h"
-#include "dot_util.h" // FIXME split out logging
+#include "MTSLog.h"
 
 BaseboardIO::BaseboardIO()
 {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xDotBridge/src/CommProtocolPeerBrute.cpp	Mon Jan 30 17:25:08 2017 -0700
@@ -0,0 +1,197 @@
+/*
+ * CommProtocolPeerBrute.cpp
+ *
+ *  Created on: Jan 30, 2017
+ *      Author: mbriggs
+ */
+
+#include "CommProtocolPeerBrute.h"
+#include "MTSLog.h"
+#include "dot_util.h"
+
+// wireless bridge protocol
+const uint8_t TX_PWR = 20; // 20 dBm
+const float RX_SLEEP_TIME = 2000; // ms (one second resolution, min 2 seconds)
+const uint8_t TX_TIME = 30; // in ms
+const unsigned int nTimesToTx = ceil(RX_SLEEP_TIME / ((float)TX_TIME));
+//const uint8_t maxPayloadSize = 10; // Number of bytes (used for toa calcultion)
+
+CommProtocolPeerBrute::CommProtocolPeerBrute(bool isTx)
+{
+    logInfo("RX_SLEEP_TIME %f, timeOnAir %lu, nTimesToTx %lu", RX_SLEEP_TIME, TX_TIME, nTimesToTx);
+
+    mIsTx = isTx;
+    if (mIsTx) {
+        mWakeMode = mDot::INTERRUPT;
+    }
+    else {
+        mWakeMode = mDot::RTC_ALARM_OR_INTERRUPT;
+    }
+    dot = mDot::getInstance();
+}
+
+CmdResult CommProtocolPeerBrute::init()
+{
+    // Common Configuration
+    dot->setAesEncryption(true);  // Enable encryption
+    dot->setTxWait(false);
+    dot->setAck(0);  // Disable Ack
+    dot->setClass("C"); // Set class C
+    dot->setTxPower(TX_PWR);
+
+    // TODO break out in a utility function
+    // update configuration if necessary
+    logInfo("Setting up peer to peer configuration");
+    if (dot->getJoinMode() != mDot::PEER_TO_PEER) {
+        logInfo("changing network join mode to PEER_TO_PEER");
+        if (dot->setJoinMode(mDot::PEER_TO_PEER) != mDot::MDOT_OK) {
+            logError("failed to set network join mode to PEER_TO_PEER");
+        }
+    }
+    uint8_t tx_power;
+    uint8_t tx_datarate;
+    uint32_t tx_frequency;
+    uint8_t frequency_band = dot->getFrequencyBand();
+    switch (frequency_band) {
+        case mDot::FB_EU868:
+            // 250kHz channels achieve higher throughput
+            // DR6 : SF7 @ 250kHz
+            // DR0 - DR5 (125kHz channels) available but much slower
+            tx_frequency = 869850000;
+            tx_datarate = mDot::DR6;
+            // the 869850000 frequency is 100% duty cycle if the total power is under 7 dBm - tx power 4 + antenna gain 3 = 7
+            tx_power = 4;
+            break;
+        case mDot::FB_US915:
+        case mDot::FB_AU915:
+        default:
+            // 500kHz channels achieve highest throughput
+            // DR8 : SF12 @ 500kHz
+            // DR9 : SF11 @ 500kHz
+            // DR10 : SF10 @ 500kHz
+            // DR11 : SF9 @ 500kHz
+            // DR12 : SF8 @ 500kHz
+            // DR13 : SF7 @ 500kHz
+            // DR0 - DR3 (125kHz channels) available but much slower
+            tx_frequency = 915500000;
+            tx_datarate = mDot::DR13;
+            // 915 bands have no duty cycle restrictions, set tx power to max
+            tx_power = 20;
+            break;
+    }
+    // in PEER_TO_PEER mode there is no join request/response transaction
+    // as long as both Dots are configured correctly, they should be able to communicate
+
+    // FIXME just using pairing keys for now
+    update_peer_to_peer_config(pair_network_address, pair_network_session_key, pair_data_session_key, tx_frequency, tx_datarate, tx_power);
+    return cmdSuccess;
+}
+
+bool CommProtocolPeerBrute::isTx()
+{
+    return mIsTx;
+}
+CmdResult CommProtocolPeerBrute::clearPair()
+{
+    logError("Not implemented yet!!!");
+    return cmdError;
+}
+
+// TX focused
+CmdResult CommProtocolPeerBrute::send (const std::vector<uint8_t> &msg)
+{
+    if (!dot->getNetworkJoinStatus()) {
+        join_network();
+    }
+    logInfo("Starting TX.  Time: %lu", us_ticker_read());
+    for(uint i=0;i<nTimesToTx;++i) {
+        dot->send(msg);
+    }
+    logInfo("Finished TX.  Time: %lu", us_ticker_read());
+    return cmdError;
+}
+
+CmdResult CommProtocolPeerBrute::sendPairReq()
+{
+    if (!dot->getNetworkJoinStatus()) {
+        join_network();
+    }
+    logError("Not implemented yet!!!");
+    return cmdError;
+}
+
+// RX focused
+CmdResult CommProtocolPeerBrute::listen (bool &msgPending)
+{
+    if (!dot->getNetworkJoinStatus()) {
+        join_network();
+    }
+
+    uint32_t cDwnLink = dot->getDownLinkCounter();
+
+    wait(TX_TIME/1000.0); // Wait TX_TIME
+
+    if (cDwnLink < dot->getDownLinkCounter()) {
+        msgPending = true;
+    }
+    else {
+        msgPending = false;
+    }
+    return cmdSuccess;  // Maybe add timeout as a possible return value
+}
+
+CmdResult CommProtocolPeerBrute::recv (std::vector<uint8_t> &msg)
+{
+    dot->recv(msg);
+    return cmdSuccess;
+}
+
+CmdResult CommProtocolPeerBrute::waitForPairing(float waitTime)
+{
+    logError("Not implemented yet!!!");
+    return cmdError;
+}
+
+CmdResult CommProtocolPeerBrute::sendPairAccepted()
+{
+    logError("Not implemented yet!!!");
+    return cmdError;
+}
+
+// xDot Peer to Peer Specific
+uint32_t CommProtocolPeerBrute::getDLC()
+{
+    return dot->getDownLinkCounter();
+}
+
+uint32_t CommProtocolPeerBrute::getULC()
+{
+    return dot->getUpLinkCounter();
+}
+
+// private:
+
+CmdResult CommProtocolPeerBrute::readInfoFromNVM()
+{
+    logError("Not implemented yet!!!");
+    return cmdError;
+}
+
+CmdResult CommProtocolPeerBrute::writeInfoToNVM()
+{
+    logError("Not implemented yet!!!");
+    return cmdError;
+}
+
+CmdResult CommProtocolPeerBrute::resetCounters()
+{
+    dot->setDownLinkCounter(0);
+    dot->setUpLinkCounter(0);
+    return cmdSuccess;
+}
+
+CmdResult CommProtocolPeerBrute::genEncypKeys()
+{
+    logError("Not implemented yet!!!");
+    return cmdError;
+}
--- a/xDotBridge/src/main.cpp	Thu Jan 26 17:36:59 2017 -0700
+++ b/xDotBridge/src/main.cpp	Mon Jan 30 17:25:08 2017 -0700
@@ -3,48 +3,24 @@
 #include "xdot_flash.h"
 #include "dot_util.h"
 #include "RadioEvent.h"
-#include <OneWire.h>
-
-/////////////////////////////////////////////////////////////////////////////
-// -------------------- DOT LIBRARY REQUIRED ------------------------------//
-// * Because these example programs can be used for both mDot and xDot     //
-//     devices, the LoRa stack is not included. The libmDot library should //
-//     be imported if building for mDot devices. The libxDot library       //
-//     should be imported if building for xDot devices.                    //
-// * https://developer.mbed.org/teams/MultiTech/code/libmDot-dev-mbed5/    //
-// * https://developer.mbed.org/teams/MultiTech/code/libmDot-mbed5/        //
-// * https://developer.mbed.org/teams/MultiTech/code/libxDot-dev-mbed5/    //
-// * https://developer.mbed.org/teams/MultiTech/code/libxDot-mbed5/        //
-/////////////////////////////////////////////////////////////////////////////
+//#include <OneWire.h>
+//#include <xdot_low_power.h>
 
-/////////////////////////////////////////////////////////////
-// * these options must match between the two devices in   //
-//   order for communication to be successful
-/////////////////////////////////////////////////////////////
-static uint8_t network_address[] = { 0x01, 0x02, 0x03, 0x04 };
-static uint8_t network_session_key[] = { 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04 };
-static uint8_t data_session_key[] =    { 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04 };
-
-// wireless bridge protocol
-const uint8_t TX_PWR = 20; // 20 dBm
-const float RX_SLEEP_TIME = 2000; // ms (one second resolution, min 2 seconds)
-const uint8_t TX_TIME = 30; // in ms
-
-//const uint8_t maxPayloadSize = 10; // Number of bytes (used for toa calcultion)
+#include "CommProtocolPeerBrute.h"
 
 ///////////////////////
 // I/O Configuration //
 ///////////////////////
 DigitalOut led1(GPIO0);
 AnalogIn an1(GPIO1);
-AnalogIn an2(GPIO2);
+//AnalogIn an2(GPIO2);
 
 // Inputs
 //DigitalIn gpio3(GPIO3);
 //DigitalIn wake_DOUT(WAKE);
 //DigitalIn i2cOut1(I2C1_SCL);
 //DigitalIn i2cOut2(I2C1_SDA);
-InterruptIn intTest(I2C1_SDA);
+//InterruptIn intTest(GPIO2);
 //DigitalIn uartOut1(UART1_CTS);
 //DigitalIn uartOut2(UART1_RTS);
 //DigitalIn jtag_gpio1(SWDIO);
@@ -63,19 +39,15 @@
 
 Serial pc(USBTX, USBRX);
 
-unsigned int callbackTime = 0;
-
-void testCallback () {
-    callbackTime = us_ticker_read();
-}
+//unsigned int callbackCnt = 0;
+//
+//static void testCallback () {
+////    callbackCnt = us_ticker_read();
+//    callbackCnt++;
+//}
 
 int main() {
-    unsigned int wakeMode;
     RadioEvent events;  // Custom event handler for automatically displaying RX data
-    uint32_t tx_frequency;
-    uint8_t tx_datarate;
-    uint8_t tx_power;
-    uint8_t frequency_band;
 
     pc.baud(115200);
 
@@ -93,7 +65,7 @@
     dot->setLogLevel(mts::MTSLog::INFO_LEVEL);
 
     // attach the custom events handler
-    dot->setEvents(&events);
+//    dot->setEvents(&events);
 
     // Setup programmable voltage detector
     // PVD_LEVEL0 Falling 1.85
@@ -110,69 +82,18 @@
     HAL_PWR_ConfigPVD(&pvdConfig);
     HAL_PWR_EnablePVD();
     logInfo("Programmable Voltage Detector set for level: %d", pvdConfig.PVDLevel);
+    // HAL_PWR_PVDCallback need to define this I think this will override the current implementation
 
     // TODO setup IO here
 
-    // update configuration if necessary
-    logInfo("Setting up peer to peer configuration");
-    if (dot->getJoinMode() != mDot::PEER_TO_PEER) {
-        logInfo("changing network join mode to PEER_TO_PEER");
-        if (dot->setJoinMode(mDot::PEER_TO_PEER) != mDot::MDOT_OK) {
-            logError("failed to set network join mode to PEER_TO_PEER");
-        }
-    }
-    frequency_band = dot->getFrequencyBand();
-    switch (frequency_band) {
-        case mDot::FB_EU868:
-            // 250kHz channels achieve higher throughput
-            // DR6 : SF7 @ 250kHz
-            // DR0 - DR5 (125kHz channels) available but much slower
-            tx_frequency = 869850000;
-            tx_datarate = mDot::DR6;
-            // the 869850000 frequency is 100% duty cycle if the total power is under 7 dBm - tx power 4 + antenna gain 3 = 7
-            tx_power = 4;
-            break;
-        case mDot::FB_US915:
-        case mDot::FB_AU915:
-        default:
-            // 500kHz channels achieve highest throughput
-            // DR8 : SF12 @ 500kHz
-            // DR9 : SF11 @ 500kHz
-            // DR10 : SF10 @ 500kHz
-            // DR11 : SF9 @ 500kHz
-            // DR12 : SF8 @ 500kHz
-            // DR13 : SF7 @ 500kHz
-            // DR0 - DR3 (125kHz channels) available but much slower
-            tx_frequency = 915500000;
-            tx_datarate = mDot::DR13;
-            // 915 bands have no duty cycle restrictions, set tx power to max
-            tx_power = 20;
-            break;
-    }
-    // in PEER_TO_PEER mode there is no join request/response transaction
-    // as long as both Dots are configured correctly, they should be able to communicate
-    update_peer_to_peer_config(network_address, network_session_key, data_session_key, tx_frequency, tx_datarate, tx_power);
+#if BRIDGE_TX_BRUTE
+    CommProtocolPeerBrute protocol(true); // TX
+#else
+    CommProtocolPeerBrute protocol(false); // RX
+#endif
+    protocol.init();
 
-    ///////////////////////////////
-	// Transmitter Configuration //
-	///////////////////////////////
-	#if BRIDGE_TX_BRUTE
-    wakeMode = mDot::INTERRUPT;
-	#endif
-
-	////////////////////////////
-	// Receiver Configuration //
-	////////////////////////////
-	#if BRIDGE_RX_BRUTE
-    wakeMode = mDot::RTC_ALARM_OR_INTERRUPT;
-	#endif
-
-    // Common Configuration
-    dot->setTxWait(false);
-    dot->setAck(0);  // Disable Ack
-    dot->setWakePin(WAKE); // Use the wake pin as sleep interrupt
-    dot->setClass("C"); // Set class C
-    dot->setTxPower(TX_PWR);
+    dot->setWakePin(WAKE);
 
     // save changes to configuration
     logInfo("saving configuration");
@@ -183,94 +104,102 @@
     // display configuration
     display_config();
 
+    uint16_t seqNum=0;
 
-    unsigned int nTimesToTx = ceil(RX_SLEEP_TIME / ((float)TX_TIME));
-    logInfo("RX_SLEEP_TIME %f, timeOnAir %lu, nTimesToTx %lu", RX_SLEEP_TIME, TX_TIME, nTimesToTx);
+    // mbed-os Interrupt setup
+//    intTest.mode(PullUp);
+//    intTest.fall(&testCallback);
+//    intTest.enable_irq(); // TODO check if this is useful
+
+//    dot->setWakePin(GPIO2); // This works but disables the wake button
+
+    // Using xdot hal libs
+//int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32_t id)
+//    gpio_irq_init();
 
-    uint16_t seqNum=0;
-    uint32_t cDwnLink = dot->getDownLinkCounter();
-
-    // Interrupt setup
-    intTest.mode(PullUp);
-    intTest.fall(testCallback);
+    // Try the STM32 way
+//    //EXTI structure to init EXT
+//    EXTI_InitTypeDef EXTI_InitStructure;
+//    //NVIC structure to set up NVIC controller
+//    NVIC_InitTypeDef NVIC_InitStructure;
+//    //Connect EXTI Line to Button Pin
+////    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
+//    GPIO_EXTILineConfig(STM_PORT(GPIO2), STM_PIN(GPIO2));
+//    //Configure Button EXTI line
+//    EXTI_InitStructure.EXTI_Line = EXTI_Line0;
+//    //select interrupt mode
+//    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
+//    //generate interrupt on rising edge
+//    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
+//    //enable EXTI line
+//    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
+//    //send values to registers
+//    EXTI_Init(&EXTI_InitStructure);
+//    //configure NVIC
+//    //select NVIC channel to configure
+//    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
+//    //set priority to lowest
+//    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
+//    //set subpriority to lowest
+//    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
+//    //enable IRQ channel
+//    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+//    //update NVIC registers
+//    NVIC_Init(&NVIC_InitStructure);
 
     while (true) {
         std::vector<uint8_t> data;
         led1=0;
 
-        // join network if not joined
-        if (!dot->getNetworkJoinStatus()) {
-            join_network();
-        }
-
-    	//////////////////////
-    	// Common main loop //
-    	//////////////////////
+		if (protocol.isTx()) {
+#if LED_FEEDBACK
+            led1=1;
+#endif
+            // TODO check for CC_IN
 
-        // TODO sample rotary
-        // TODO sample DIPs
+            data.push_back((seqNum >> 8) & 0xFF);
+            data.push_back(seqNum & 0xFF);
+            protocol.send(data);
+            seqNum++;
 
-    	//////////////////////////////////////////
-    	// Brute Protocol Transmitter main loop //
-    	//////////////////////////////////////////
-		#if BRIDGE_TX_BRUTE
 #if LED_FEEDBACK
-        led1=1;
+            led1=0;
 #endif
-        // TODO check for CC_IN
+            sleep_save_io();
+            sleep_configure_io();
+            dot->sleep(0, mDot::INTERRUPT, false);  // Go to sleep until wake button
+            sleep_restore_io();
+		}
 
-        data.push_back((seqNum >> 8) & 0xFF);
-        data.push_back(seqNum & 0xFF);
-        logInfo("Starting TX.  Time: %lu, seqNum: %lu", us_ticker_read(), seqNum);
-        for(uint i=0;i<nTimesToTx;++i) {
-        	dot->send(data);
-        }
-        seqNum++;
-        led1=0;
-		logInfo("Finished TX.  Time: %lu", us_ticker_read());
-        
-		sleep_save_io();
-		sleep_configure_io();
-        dot->sleep(0, wakeMode, false);  // Go to sleep until wake button
-        sleep_restore_io();
-		#endif
-
-    	///////////////////////////////////////
-    	// Brute Protocol Receiver main loop //
-    	///////////////////////////////////////
-		#if BRIDGE_RX_BRUTE
-        logInfo("Waiting for new message current DLC: %d, Time %d", cDwnLink, us_ticker_read());
-        wait(TX_TIME/1000.0); // Wait TX_TIME
-
-        // TODO need to figure out what to do when DLC get resets
-
-        if (cDwnLink < dot->getDownLinkCounter()) {
-			cDwnLink = dot->getDownLinkCounter();
-			dot->recv(data);
-			std::string dataStr(data.begin(), data.end());
-			logInfo("Got msg num: %d, payload: %s", seqNum, dataStr.c_str());
-			// TODO add CC_OUT code here
-			seqNum++;
+		if (protocol.isRx()) {
+		    bool msgPending;
+		    protocol.listen(msgPending);
+		    if (msgPending) {
+		        protocol.recv(data);
+                std::string dataStr(data.begin(), data.end());
+                logInfo("Got msg num: %d, payload: %s", seqNum, dataStr.c_str());
+                // TODO add CC_OUT code here
+                seqNum++;
 #if LED_FEEDBACK
-			led1 = 1;
-			wait(0.5);
+                led1 = 1;
+                wait(0.5);
 #endif
-        }
-		led1=0;
-        logInfo("Sleeping.  Time %d", us_ticker_read());
-		sleep_save_io();
-		sleep_configure_io();
-		// TODO maybe add if statement here to prevent double hits by sleeping for a longer time
-        dot->sleep(2, wakeMode, false);  // Go to sleep until wake button
-        sleep_restore_io();
-		#endif
+		    }
+            led1=0;
+            logInfo("Sleeping.  Time %d", us_ticker_read());
+            sleep_save_io();
+            sleep_configure_io();
+            // TODO maybe add if statement here to prevent double hits by sleeping for a longer time
+            dot->sleep(2, mDot::RTC_ALARM_OR_INTERRUPT, false);  // Go to sleep until wake button
+            sleep_restore_io();
+		}
 
         //////////////
         // I/O Play //
         //////////////
 
-        // Check interrupt
-        logInfo("Callback last called @ %d", callbackTime);
+//        // Check interrupt
+//        logInfo("Callback last called @ %d", callbackCnt);
 
 //        // Check Analog
 //        logInfo("Read AN1/GPIO1: %f", an1.read());
@@ -304,8 +233,17 @@
 //		uartOut1 = !uartOut1;
 //		uartOut2 = !uartOut2;
 
-        logInfo("================================");
-		wait(1.0);
+//        logInfo("================================");
+//        wait(1.0);
+//		sleep_save_io();
+//		sleep_configure_io();
+//        __GPIOA_CLK_ENABLE();
+//        __GPIOB_CLK_ENABLE();
+//        __GPIOC_CLK_ENABLE();
+//        __GPIOH_CLK_ENABLE();
+
+//        xdot_enter_stop_mode();
+//        dot->sleep(2, mDot::INTERRUPT, false);  // Go to sleep until wake button
         //////////////////
         // OneWire Play //
         //////////////////