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:
Tue Mar 14 08:32:55 2017 -0600
Parent:
61:8d9efd33cac9
Child:
63:e1efbe3402d9
Commit message:
First cut at pair code

Changed in this revision

xDotBridge/README.md Show annotated file Show diff for this revision Revisions of this file
xDotBridge/config.h Show annotated file Show diff for this revision Revisions of this file
xDotBridge/inc/BaseboardIO.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/inc/UserInterface.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/UserInterface.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/README.md	Thu Mar 09 16:47:42 2017 -0700
+++ b/xDotBridge/README.md	Tue Mar 14 08:32:55 2017 -0600
@@ -65,6 +65,24 @@
 and data session keys.  This guarantees by design that all message sent can
 only be received and decoded by units in the pair group.
 
+### Important LoRaWAN Parameters
+For peer to peer only a subset of parameters apply.  Many are obvious such as
+power, frequency, and basic command and control.  Below are a listing of the more
+detailed parameters and our current understanding as to how they effect performance:
+
+ * Network address  - In peer to peer this acts both as a tx and rx address.  In other
+ words if all the modems are the same address messages act as broadcast.  For the
+ wireless bridge, this is used as a sort of network ID since all communication is
+ broadcast.
+ * Network session key - This is one of two encryption key.  Currently, in peer to peer
+ both are just randomly generated.
+ * Data session key - This is second of two encryption key.  Currently, in peer to peer
+ both are just randomly generated.
+
+Not applicable parameters:
+ * Network ID - Used for OTA
+ * Network Key - Used for OTA
+
 ### Brute force algorithm
 TODO
 
@@ -108,11 +126,11 @@
 ==============================================
 = 0x0A | 4 Bytes | Reserved for Frequency    =
 ==============================================
-= 0x0D | 4 Bytes | Network ID                =
+= 0x0E | 4 Bytes | Network Address           =
 ==============================================
-= 0x12 | 8 Bytes | Network Key               =
+= 0x12 | 16 Bytes | Network Session Key       =
 ==============================================
-= 0x1A | 8 Bytes | Data session Key          =
+= 0x22 | 16 Bytes | Data session Key          =
 ==============================================
 * Total of 34 Bytes
 
@@ -170,42 +188,48 @@
 # Nonvolatile Memory Map
 ## Stored by dot firmware
  * 64-bit EUI
- * Network ID
  * DLC
  * ULC
- * Enc keys
-
 
 ## Protocol Parameters
 ==============================================
 = Dot Relative Addr | Size (in Bytes) | Name =
 ==============================================
-= 0x1000 | 2 Bytes | Protocol Flag           =
+= 0x1000 | 02 Bytes | Protocol Flag          =
+==============================================
+= 0x1002 | 02 Bytes | Protocol Rev           =
 ==============================================
-= 0x1002 | 2 Bytes | Protocol Rev            =
+= 0x1004 | 04 Bytes | Reserved for Frequency =
+==============================================
+= 0x1008 | 04 Bytes | Network Address        =
 ==============================================
-= 0x1004 | 2 Bytes | Logical Address Serial  =
+= 0x1010 | 16 Bytes | Network Session Key    =
+==============================================
+= 0x1020 | 16 Bytes | Data Session Key       =
 ==============================================
-= 0x1006 | 4 Bytes | Last Message SeqNum     =
+= 0x1030 | 02 Bytes | Logical Address Serial =
 ==============================================
-Space used is 10 bytes
+= 0x1032 | 04 Bytes | Last Message SeqNum    =
+==============================================
+Space needed is 54 bytes.  Spaced used is 50 bytes
+for better word alignment.
 
 ## IO Baseboard Parameters
 ==============================================
 = Dot Relative Addr | Size (in Bytes) | Name =
 ==============================================
-= 0x2000 | 2 Bytes | Baseboard Flag          =
+= 0x1100 | 2 Bytes | Baseboard Flag          =
 ==============================================
-= 0x2002 | 2 Bytes | Baseboard Rev           =
+= 0x1102 | 2 Bytes | Baseboard Rev           =
 ==============================================
-= 0x2004 | 2 Bytes | Baseboard Serial        =
+= 0x1104 | 2 Bytes | Baseboard Serial        =
 ==============================================
-= 0x2006 | 2 Bytes | Baseboard Configuration =
+= 0x1106 | 2 Bytes | Baseboard Configuration =
 ==============================================
-= 0x2010 | 8 Bytes | PortEx0 64 bit ROM Addr =
+= 0x1110 | 8 Bytes | PortEx0 64 bit ROM Addr =
 ==============================================
-= 0x2018 | 8 Bytes | PortEx1 64 bit ROM Addr =
+= 0x1118 | 8 Bytes | PortEx1 64 bit ROM Addr =
 ==============================================
 
-Space used is 32 bytes
+Space needed is 24 bytes.  Space used is 32 bytes.
 
--- a/xDotBridge/config.h	Thu Mar 09 16:47:42 2017 -0700
+++ b/xDotBridge/config.h	Tue Mar 14 08:32:55 2017 -0600
@@ -5,13 +5,13 @@
 #ifndef CONFIG_H_
 #define CONFIG_H_
 
-#define __TEST__ 1 // Comment out for main application
+//#define __TEST__ 1 // Comment out for main application
 
 // Manual test.  Comment out for main application.  Or uncomment for individual test.
 //#define __TEST_BBIO__
 //#define __TEST_LRR__
 //#define __TEST_PVD__
-#define __TEST_XDOT_DEV_COMM__
+//#define __TEST_XDOT_DEV_COMM__
 
 // These define which wireless bridge you are generating code for
 #define LED_FEEDBACK 1  // If 1 then LED is shown and 0 LED is not shown to conserve power
--- a/xDotBridge/inc/BaseboardIO.h	Thu Mar 09 16:47:42 2017 -0700
+++ b/xDotBridge/inc/BaseboardIO.h	Tue Mar 14 08:32:55 2017 -0600
@@ -9,7 +9,7 @@
 #ifndef BASEBOARDIO_H_
 #define BASEBOARDIO_H_
 
-const uint16_t BASEBOARDIO_NVM_START_ADDR = 0x1000;
+const uint16_t BASEBOARDIO_NVM_START_ADDR = 0x1100;
 const uint16_t BASEBOARDIO_NVM_SIZE = 32; // Bytes
 const uint16_t BASEBOARDIO_FLAG = 0x5A00;
 const uint16_t BASEBOARDIO_REV = 0x0000;
--- a/xDotBridge/inc/CommProtocolPeerBrute.h	Thu Mar 09 16:47:42 2017 -0700
+++ b/xDotBridge/inc/CommProtocolPeerBrute.h	Tue Mar 14 08:32:55 2017 -0600
@@ -14,14 +14,14 @@
 // 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_address[] = { 0x01, 0x00, 0x00, 0x00 }; // 0x00000000 reserved for multicast so use 1
 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 };
 
 const uint16_t PROTOCOL_NVM_START_ADDR = 0x1000;
-const uint16_t PROTOCOL_NVM_SIZE = 12; // Bytes
+const uint16_t PROTOCOL_NVM_SIZE = 54; // Bytes
 const uint16_t PROTOCOL_FLAG = 0x5A00;
-const uint16_t PROTOCOL_REV = 0x0000;
+const uint16_t PROTOCOL_REV = 0x0002;
 class NvmProtocolObj {
 public:
     NvmProtocolObj();
@@ -34,13 +34,26 @@
     uint16_t getProtocolRev();
     bool validProtocolRev();
 
+    void getNetworkAddr(std::vector<uint8_t> &addr);
+    void setNetworkAddr(const std::vector<uint8_t> &addr);
+    void getNetworkSessionKey(std::vector<uint8_t> &key);
+    void setNetworkSessionKey(const std::vector<uint8_t> &key);
+    void getDataSessionKey(std::vector<uint8_t> &key);
+    void setDataSessionKey(const std::vector<uint8_t> &key);
+
     uint16_t getLogicalAddr();
     void setLogicalAddr(uint16_t in);
     uint32_t getLastMsgSeq();
     void setLastMsgSeq(uint32_t in);
+
+    // TODO some day make these private with setters and getters
+    uint8_t  mNetworkAddr[4];
+    uint8_t  mNetworkSessionKey[16];
+    uint8_t  mDataSessionKey[16];
 private:
     uint16_t mProtocolFlag;
     uint16_t mProtocolRev;
+    uint32_t mFreq;
     uint16_t mLogicalAddr;
     uint32_t mSeqNum;
 };
@@ -90,7 +103,7 @@
      * @return Returns the result of all the commands
      */
     CmdResult init();
-    CmdResult dotDefaults();
+    CmdResult configForSavedNetwork();
 
     /**
      * @brief Sets weather this object is configured as a TX or RX
@@ -192,10 +205,10 @@
      */
     uint32_t getULC();
 
+    // TODO maybe this should be private
+    CmdResult configForPairingNetwork();
+
 private:
-//    uint8_t mNetworkAddr[4];
-//    uint8_t mNetwork_session_key[16];
-//    uint8_t mData_session_key[16];
     NvmProtocolObj mMemObj;
     bool mIsTx;
     uint32_t mPrevDownLinkCnt;
@@ -242,10 +255,9 @@
      * Generates new encryption keys for radio
      * @return
      */
+    CmdResult genEncypKey(std::vector<uint8_t> &newKey, uint8_t keySize, bool allowZero);
     CmdResult genEncypKey(std::vector<uint8_t> &newKey, uint8_t keySize);
 
-    CmdResult configForPairingNetwork();
-    CmdResult configForSavedNetwork();
 };
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xDotBridge/inc/UserInterface.h	Tue Mar 14 08:32:55 2017 -0600
@@ -0,0 +1,41 @@
+/*
+ * UserInterface.h
+ *
+ *  Created on: Feb 28, 2017
+ *      Author: mbriggs
+ */
+
+#ifndef XDOTBRIDGE_INC_USERINTERFACE_H_
+#define XDOTBRIDGE_INC_USERINTERFACE_H_
+
+#include <stdint.h>
+#include "BaseboardIO.h"
+
+const float RX_PAIR_WAIT_TIME = 30.0;
+const float TX_ACCEPT_WAIT_TIME = 10.0;
+
+enum PairBtnState {
+    pairBtnShortPress,
+    pairBtnMediumPress,
+    pairBtnLongPress
+};
+
+class PairBtnInterp {
+public:
+    // Start time < press time < stop time (all time in ms)
+    static const uint16_t ShortPressStartTime = 0;
+    static const uint16_t ShortPressStopTime = 4000;
+    static const uint16_t MediumPressStartTime = 4000;
+    static const uint16_t MediumPressStopTime  = 9000;
+    // Anything longer is a LongPress
+
+    static PairBtnState read(BaseboardIO *bbio);
+};
+
+class HoldTimeSetting {
+public:
+    static uint32_t rotVal2Msec(uint8_t in);
+    static float rotVal2Sec(uint8_t in) {return rotVal2Msec(in)/1000.0;}
+};
+
+#endif /* XDOTBRIDGE_INC_USERINTERFACE_H_ */
--- a/xDotBridge/src/BaseboardIO.cpp	Thu Mar 09 16:47:42 2017 -0700
+++ b/xDotBridge/src/BaseboardIO.cpp	Tue Mar 14 08:32:55 2017 -0600
@@ -11,9 +11,9 @@
 #include "xdot_low_power.h"
 
 // Original
-const float COIL_ON_TIME = 0.060; // 30 ms
+//const float COIL_ON_TIME = 0.030; // 30 ms
 // Test
-//const float COIL_ON_TIME = 0.30; // 300 ms
+const float COIL_ON_TIME = 0.300; // 300 ms
 
 
 // Port expander 0 (Currently U7)
--- a/xDotBridge/src/CommProtocolPeerBrute.cpp	Thu Mar 09 16:47:42 2017 -0700
+++ b/xDotBridge/src/CommProtocolPeerBrute.cpp	Tue Mar 14 08:32:55 2017 -0600
@@ -21,21 +21,34 @@
     logInfo("RX_SLEEP_TIME %f, timeOnAir %lu, nTimesToTx %lu", RX_SLEEP_TIME, TX_TIME, nTimesToTx);
 
     mIsTx = true; // default to TX
-//    mPrevDownLinkCnt = dot->getDownLinkCounter();
 }
 
 CmdResult CommProtocolPeerBrute::init()
 {
-    // FIXME add NVM stuff
-    dotDefaults();
+    CmdResult result;
+    if (dot == NULL) {
+        return cmdError;
+    }
+    result = readInfoFromNVM();
+    if (result != cmdSuccess) {
+        logInfo("Reverting to protocol defaults NVM Read failed");
+        mMemObj.setDefaults();
+    }
+    configForSavedNetwork();
 
+    writeInfoToNVM();
+
+    mPrevDownLinkCnt = dot->getDownLinkCounter();
     return cmdSuccess;
 }
-CmdResult CommProtocolPeerBrute::dotDefaults()
+CmdResult CommProtocolPeerBrute::configForSavedNetwork()
 {
-    // TODO add more error checking
-    logWarning("defaulting Dot configuration");
-    dot->resetConfig();
+    if (dot == NULL) {
+        return cmdError;
+    }
+
+//    logInfo("defaulting Dot configuration");
+//    dot->resetConfig();
 
     // Common Configuration
     dot->setAesEncryption(true);  // Enable encryption
@@ -43,7 +56,7 @@
     dot->setAck(0);  // Disable Ack
     dot->setClass("C"); // Set class C
     dot->setTxPower(TX_PWR);
-    dot->setPreserveSession(false); // TODO need to better handle counters
+    dot->setPreserveSession(false);
 
     // TODO break out in a utility function
     // update configuration if necessary
@@ -88,13 +101,37 @@
     // 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);
+    update_peer_to_peer_config(mMemObj.mNetworkAddr, mMemObj.mNetworkSessionKey,
+            mMemObj.mDataSessionKey, tx_frequency, tx_datarate, tx_power);
     dot->saveConfig();
     return cmdSuccess;
 }
 CmdResult CommProtocolPeerBrute::configForPairingNetwork()
 {
+    if (dot == NULL) {
+        return cmdError;
+    }
+
+//    logInfo("defaulting Dot configuration");
+//    dot->resetConfig();
+
+    // 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);
+    dot->setPreserveSession(false);
+    // 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;
@@ -127,8 +164,7 @@
             break;
     }
     update_peer_to_peer_config(pair_network_address, pair_network_session_key, pair_data_session_key, tx_frequency, tx_datarate, tx_power);
-    // TODO experiment if we need to save as I will need to save off previous settings to revert back
-//    dot->saveConfig();
+    dot->saveConfig(); // This is required for network settings to apply
     return cmdSuccess;
 }
 void CommProtocolPeerBrute::setTx(bool isTx)
@@ -147,26 +183,53 @@
     std::vector<uint8_t> key;
     key.reserve(16);
 
-    result = genEncypKey(key, 8);
+    // REPLACE WITH NETWORK ADDRESS
+//    result = genEncypKey(key, 8);
+//    if (result != cmdSuccess) {
+//        logError("Error generating network ID.");
+//        return cmdError;
+//    }
+//    if (dot->setNetworkId(key) != mDot::MDOT_OK) {
+//        logError("Error setting network ID.");
+//        return cmdError;
+//    }
+
+    result = genEncypKey(key, 4, false);
     if (result != cmdSuccess) {
-        logError("Error generating network ID.");
+        logError("Error generating network address.");
         return cmdError;
     }
-    dot->setNetworkId(key);
+    mMemObj.setNetworkAddr(key);
+//    if (dot->setNetworkAddress(key) != mDot::MDOT_OK) {
+//        logError("Error setting network address.");
+//        return cmdError;
+//    }
 
     result = genEncypKey(key, 16);
     if (result != cmdSuccess) {
         logError("Error generating network encryption keys.");
         return cmdError;
     }
-    dot->setNetworkKey(key);
+    mMemObj.setNetworkSessionKey(key);
+//    if (dot->setNetworkSessionKey(key) != mDot::MDOT_OK) {
+//        logError("Error setting network session key.");
+//        return cmdError;
+//    }
 
     result = genEncypKey(key, 16);
     if (result != cmdSuccess) {
         logError("Error generating data session encryption keys.");
         return cmdError;
     }
-    dot->setDataSessionKey(key);
+    mMemObj.setDataSessionKey(key);
+//    if (dot->setDataSessionKey(key) != mDot::MDOT_OK) {
+//        logError("Error setting data session key.");
+//        return cmdError;
+//    }
+
+    configForSavedNetwork();
+    writeInfoToNVM();
+    display_config();
 
     return cmdSuccess;
 }
@@ -252,7 +315,6 @@
     if (!msgPending) {
         return cmdTimeout;
     }
-    // TODO check request
 
     wait(1.0);  // Wait just a little so it is clear for requester that it is a pair message
     return sendPairAccepted();
@@ -280,20 +342,23 @@
     }
     logInfo("freq msg size %d", msg->size());
 
-    // Network ID
-    std::vector<uint8_t> *networkId = new std::vector<uint8_t>(dot->getNetworkId());
-    msg->insert(msg->end(),networkId->begin(), networkId->end());
-    delete networkId;
-    logInfo("netid msg size %d", msg->size());
+    // Network Address
+    std::vector<uint8_t> *networkAddr = new std::vector<uint8_t>;
+    mMemObj.getNetworkAddr(*networkAddr);
+    msg->insert(msg->end(),networkAddr->begin(), networkAddr->end());
+    delete networkAddr;
+    logInfo("netAddr msg size %d", msg->size());
 
-    // Network key
-    std::vector<uint8_t> *networkKey = new std::vector<uint8_t>(dot->getNetworkKey());
-    msg->insert(msg->end(),networkKey->begin(), networkKey->end());
-    delete networkKey;
-    logInfo("netKey msg size %d", msg->size());
+    // Network session key
+    std::vector<uint8_t> *networkSessionKey = new std::vector<uint8_t>;
+    mMemObj.getNetworkSessionKey(*networkSessionKey);
+    msg->insert(msg->end(),networkSessionKey->begin(), networkSessionKey->end());
+    delete networkSessionKey;
+    logInfo("netSessionKey msg size %d", msg->size());
 
     // Data session key
-    std::vector<uint8_t> *dataSessionKey = new std::vector<uint8_t>(dot->getDataSessionKey());
+    std::vector<uint8_t> *dataSessionKey = new std::vector<uint8_t>;
+    mMemObj.getDataSessionKey(*dataSessionKey);
     msg->insert(msg->end(),dataSessionKey->begin(), dataSessionKey->end());
     delete dataSessionKey;
 
@@ -320,7 +385,27 @@
     if (!msgPending) {
         return cmdTimeout;
     }
-    // TODO check request
+
+    std::vector<uint8_t> acceptMsg;
+    dot->recv(acceptMsg);
+    if (acceptMsg[0] != 0xFD || acceptMsg[1] != 0x02) {
+        logError("Invalid accept message flag.");
+        return cmdError;
+    }
+
+    std::vector<uint8_t> *netAddr = new std::vector<uint8_t>(acceptMsg.begin()+0x0E, acceptMsg.begin()+0x12);
+    mMemObj.setNetworkAddr(*netAddr);
+    delete netAddr;
+
+    std::vector<uint8_t> *netSessionKey = new std::vector<uint8_t>(acceptMsg.begin()+0x12, acceptMsg.begin()+0x22);
+    mMemObj.setNetworkSessionKey(*netSessionKey);
+    delete netSessionKey;
+
+    std::vector<uint8_t> *dataSessionKey = new std::vector<uint8_t>(acceptMsg.begin()+0x22, acceptMsg.begin()+0x32);
+    mMemObj.setDataSessionKey(*dataSessionKey);
+    delete dataSessionKey;
+
+    writeInfoToNVM();
 
     return cmdSuccess;
 }
@@ -340,7 +425,6 @@
 
 CmdResult CommProtocolPeerBrute::readInfoFromNVM()
 {
-    // TODO store / retrieve network keys
     bool nvmReadResult;
     uint8_t *data = new uint8_t [PROTOCOL_NVM_SIZE];
 
@@ -354,12 +438,12 @@
     if (!mMemObj.validProtocolFlag()) {
         logWarning("Invalid Protocol Flag.  Using default values.");
         mMemObj.setDefaults();
-        dotDefaults();
+        return cmdError;
     }
     else if (!mMemObj.validProtocolRev()) {
         logWarning("Invalid Protocol Rev.  Using default values.");
         mMemObj.setDefaults();
-        dotDefaults();
+        return cmdError;
     }
     return cmdSuccess;
 }
@@ -384,9 +468,18 @@
 
 CmdResult CommProtocolPeerBrute::genEncypKey(std::vector<uint8_t> &newKey, uint8_t keySize)
 {
+    return genEncypKey(newKey, keySize, true); // Default allow zero
+}
+CmdResult CommProtocolPeerBrute::genEncypKey(std::vector<uint8_t> &newKey, uint8_t keySize, bool allowZero)
+{
     newKey.clear();
     for (uint8_t i=0;i<keySize; i++){
-        newKey.push_back(dot->getRadioRandom());
+        if (allowZero) {
+            newKey.push_back(dot->getRadioRandom() & 0xFF);
+        }
+        else {
+            newKey.push_back((dot->getRadioRandom() % 254) + 1);
+        }
     }
     return cmdSuccess;
 }
@@ -400,6 +493,10 @@
 {
     mProtocolFlag = PROTOCOL_FLAG;
     mProtocolRev = PROTOCOL_REV;
+    mFreq = 915500000;
+    std::memset(mNetworkAddr, 0x00, sizeof(mNetworkAddr));
+    std::memset(mNetworkSessionKey, 0x00, sizeof(mNetworkSessionKey));
+    std::memset(mDataSessionKey, 0x00, sizeof(mDataSessionKey));
     mLogicalAddr = 0x00000000;
     mSeqNum = 0x00000000;
 }
@@ -410,9 +507,13 @@
     }
 
     mProtocolFlag   = *((uint16_t *) (data));
-    mProtocolRev    = *((uint16_t *) (data+2));
-    mLogicalAddr    = *((uint32_t *) (data+4));
-    mSeqNum         = *((uint32_t *) (data+6));
+    mProtocolRev    = *((uint16_t *) (data+0x02));
+    mFreq           = *((uint32_t *) (data+0x04));
+    std::memcpy(&mNetworkAddr,        data+0x08, 4);
+    std::memcpy(&mNetworkSessionKey,  data+0x10, 16);
+    std::memcpy(&mDataSessionKey,     data+0x20, 16);
+    mLogicalAddr    = *((uint32_t *) (data+0x30));
+    mSeqNum         = *((uint32_t *) (data+0x32));
 
     return cmdSuccess;
 }
@@ -421,8 +522,12 @@
 
     *((uint16_t *) (data))   = mProtocolFlag;
     *((uint16_t *) (data+2)) = mProtocolRev;
-    *((uint32_t *) (data+4)) = mLogicalAddr;
-    *((uint32_t *) (data+6)) = mSeqNum;
+    *((uint32_t *) (data+0x04)) = mFreq;
+    std::memcpy(data+0x08, &mNetworkAddr, 4);
+    std::memcpy(data+0x10, &mNetworkSessionKey, 16);
+    std::memcpy(data+0x20, &mDataSessionKey, 16);
+    *((uint32_t *) (data+0x30)) = mLogicalAddr;
+    *((uint32_t *) (data+0x32)) = mSeqNum;
 
     size = PROTOCOL_NVM_SIZE;
 
@@ -444,6 +549,51 @@
 {
     return mProtocolRev == PROTOCOL_REV;
 }
+void NvmProtocolObj::getNetworkAddr(std::vector<uint8_t> &addr)
+{
+    addr.clear();
+    addr.assign(mNetworkAddr, mNetworkAddr+sizeof(mNetworkAddr));
+}
+void NvmProtocolObj::setNetworkAddr(const std::vector<uint8_t> &addr)
+{
+    if (addr.size() > sizeof(mNetworkAddr)) {
+        // TODO log error
+        return;
+    }
+    for (uint8_t i=0; i < sizeof(mNetworkAddr); i++) {
+        mNetworkAddr[i] = addr[i];
+    }
+}
+void NvmProtocolObj::getNetworkSessionKey(std::vector<uint8_t> &key)
+{
+    key.clear();
+    key.assign(mNetworkSessionKey, mNetworkSessionKey+sizeof(mNetworkSessionKey));
+}
+void NvmProtocolObj::setNetworkSessionKey(const std::vector<uint8_t> &key)
+{
+    if (key.size() > sizeof(mNetworkSessionKey)) {
+        // TODO log error
+        return;
+    }
+    for (uint8_t i=0; i < sizeof(mNetworkSessionKey); i++) {
+        mNetworkSessionKey[i] = key[i];
+    }
+}
+void NvmProtocolObj::getDataSessionKey(std::vector<uint8_t> &key)
+{
+    key.clear();
+    key.assign(mDataSessionKey, mDataSessionKey+sizeof(mDataSessionKey));
+}
+void NvmProtocolObj::setDataSessionKey(const std::vector<uint8_t> &key)
+{
+    if (key.size() > sizeof(mDataSessionKey)) {
+        // TODO log error
+        return;
+    }
+    for (uint8_t i=0; i < sizeof(mDataSessionKey); i++) {
+        mDataSessionKey[i] = key[i];
+    }
+}
 uint16_t NvmProtocolObj::getLogicalAddr()
 {
     return mLogicalAddr;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xDotBridge/src/UserInterface.cpp	Tue Mar 14 08:32:55 2017 -0600
@@ -0,0 +1,67 @@
+/*
+ * UserInterface.cpp
+ *
+ */
+
+#include "UserInterface.h"
+
+uint32_t HoldTimeSetting::rotVal2Msec(uint8_t in) {
+    switch(in) {
+    case 1:
+        return 10e3; // 10 sec
+        break;
+    case 2:
+        return 20e3; // 20 sec
+        break;
+    case 3:
+        return 30e3; // 30 sec
+        break;
+    case 4:
+        return 40e3; // 40 sec
+        break;
+    case 5:
+        return 50e3; // 50 sec
+        break;
+    case 6:
+        return 60e3; // 60 sec
+        break;
+    case 7:
+        return 2*60e3; // 2 mins
+        break;
+    case 8:
+        return 5*60e3; // 5 mins
+        break;
+    case 9:
+        return 10*60e3; // 10 mins
+        break;
+    case 0:
+        return 500; // 0.5 sec
+        break;
+    default:  // Match case 0
+        return 500; // 0.5 sec
+    }
+}
+
+PairBtnState PairBtnInterp::read(BaseboardIO *bbio)
+{
+    const uint8_t holdCnt2ms = 100; // 100 ms per 0.1 sec count
+    uint8_t holdCnt = 0;
+    for (holdCnt=0; holdCnt < 90; holdCnt++) {
+        if (bbio->isPairBtn() == false){ // Button released
+            break;
+        }
+        // TODO Sleep here rather than just wait
+        wait(0.1);
+    }
+    if (ShortPressStartTime <= holdCnt*holdCnt2ms
+        && holdCnt*holdCnt2ms < ShortPressStopTime) {
+        return pairBtnShortPress;
+    }
+    else if (MediumPressStartTime <= holdCnt*holdCnt2ms
+            && holdCnt*holdCnt2ms < MediumPressStopTime) {
+        return pairBtnMediumPress;
+    }
+    else {
+        return pairBtnLongPress;
+    }
+}
--- a/xDotBridge/src/main.cpp	Thu Mar 09 16:47:42 2017 -0700
+++ b/xDotBridge/src/main.cpp	Tue Mar 14 08:32:55 2017 -0600
@@ -46,17 +46,24 @@
 
     dot = mDot::getInstance();
 
-    logInfo("mbed-os library version: %d", MBED_LIBRARY_VERSION);
-    logInfo(" libxDot-mbed5 library ID: %s", dot->getId().c_str());
-
     // make sure library logging is turned on
     dot->setLogLevel(mts::MTSLog::INFO_LEVEL);
 
+    logInfo("mbed-os library version: %d", MBED_LIBRARY_VERSION);
+    logInfo("libxDot-mbed5 library ID: %s", dot->getId().c_str());
+
     // attach the custom events handler
     dot->setEvents(&events);  // Little bonus event debug information
 
     // Finish radio init
+    pc.printf("= Protocol Init Starting                     =\r\n");
     protocol->init();
+    if (result == cmdSuccess) {
+        pc.printf("= Protocol Init Finished Successfully    =\r\n");
+    }
+    else {
+        pc.printf("= Protocol Init Finished with Error      =\r\n");
+    }
 
     // save changes to configuration
 //    logInfo("saving configuration");
@@ -87,6 +94,8 @@
     dot->setWakeMode(mDot::RTC_ALARM_OR_INTERRUPT);
     dot->setWakePin(UART1_RX);
 
+    display_config();  // Print configuration for now
+
     // display configuration
 //    display_config();
 
@@ -144,6 +153,7 @@
             if (protocol->isTx()) {
                 if (pairBtnState == pairBtnMediumPress) {
                     protocol->sampleDLC();
+                    protocol->configForPairingNetwork();
                     protocol->sendPairReq();
                     logInfo("Sent pair request.  Waiting %f secs for accept.", TX_ACCEPT_WAIT_TIME);
                     result = protocol->waitForAccept(TX_ACCEPT_WAIT_TIME);
@@ -153,11 +163,13 @@
                     else {
                         logInfo("Did not receive accept");
                     }
+                    protocol->configForSavedNetwork();
                 }
             }
             if (protocol->isRx()) {
                 if (pairBtnState == pairBtnMediumPress) {
                     protocol->sampleDLC();
+                    protocol->configForPairingNetwork();
                     bbio->ledOn();
                     logInfo("Waiting for pair request for %f seconds", RX_PAIR_WAIT_TIME);
                     result = protocol->waitForPairing(RX_PAIR_WAIT_TIME);
@@ -171,6 +183,7 @@
                     else {
                         logInfo("Unknown pair error");
                     }
+                    protocol->configForSavedNetwork();
                 }
                 else if (pairBtnState == pairBtnLongPress) {
                     logInfo("Clearing pair values and generating new ones.");
@@ -189,8 +202,6 @@
 		       bbio->isCCInAlert() || // If closure remains in effect
 		       (pairBtnIntFlag && (pairBtnState == pairBtnShortPress))) {
                 ccIntFlag = false;
-                pairBtnIntFlag = false;
-                tamperIntFlag = false;
                 #if LED_FEEDBACK
                 bbio->ledOn();
                 #endif
@@ -206,6 +217,8 @@
 		    }
 
             bbio->ledOff();
+            pairBtnIntFlag = false;
+            tamperIntFlag = false;
             bbio->prepareSleep();
 		    if (bbio->isCCInAlert()) { // Still in alert mode
                 dot->sleep(2, mDot::RTC_ALARM_OR_INTERRUPT, false);  // Go to sleep and check in 2 secs if CCInAlert is asserted
@@ -221,6 +234,7 @@
 		    protocol->listen(msgPending);
 		    logInfo("Loop Cnt %d.  Listening.", loopCnt);
 		    if (msgPending) {
+		        data.clear();
 		        protocol->recv(data);
                 std::string dataStr(data.begin(), data.end());
                 logInfo("Got msg num: %d, payload: %s", rxSeqNum, dataStr.c_str());