Custom "Installer Assistant" software. Modified Single Sweep Mode. Goes right into single sweep mode upon power-up and displays signal strength. Works with mbed-os 5.1.2 and mdot lib 5.1.5

Dependencies:   DOGS102 GpsParser ISL29011 MMA845x MPL3115A2 MTS-Serial NCP5623B libmDot-dev-mbed5-deprecated

Fork of MTDOT-BOX-EVB-Factory-Firmware by MultiTech

Files at this revision

API Documentation at this revision

Comitter:
Mike Fiore
Date:
Thu Feb 04 12:36:36 2016 -0600
Parent:
0:608d1d025f3c
Child:
2:705a6bdaef68
Child:
3:db75f686b8db
Commit message:
add rest of source - version 2.0.0

Changed in this revision

ButtonHandler/ButtonHandler.cpp Show annotated file Show diff for this revision Revisions of this file
ButtonHandler/ButtonHandler.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdAttention.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdAttention.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdData.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdData.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDataSessionKey.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDataSessionKey.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDeleteSurveyDataFile.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDeleteSurveyDataFile.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDeviceId.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDeviceId.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDisplayConfig.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDisplayConfig.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDummy.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdDummy.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdFactoryDefault.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdFactoryDefault.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdFrequencyBand.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdFrequencyBand.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdFrequencySubBand.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdFrequencySubBand.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdGetSurveyDataFile.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdGetSurveyDataFile.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdIdentification.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdIdentification.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdMaximumPower.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdMaximumPower.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdMaximumSize.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdMaximumSize.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdMinimumPower.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdMinimumPower.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdMinimumSize.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdMinimumSize.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkAddress.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkAddress.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkId.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkId.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkJoinMode.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkJoinMode.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkKey.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkKey.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkSessionKey.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdNetworkSessionKey.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdPublicNetwork.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdPublicNetwork.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSaveConfig.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdSaveConfig.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdTxDataRate.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdTxDataRate.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdTxPower.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdTxPower.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdWriteProtectedConfig.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/CmdWriteProtectedConfig.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/Command.cpp Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/Command.h Show annotated file Show diff for this revision Revisions of this file
CommandTerminal/Commands.h Show annotated file Show diff for this revision Revisions of this file
FileName.h Show annotated file Show diff for this revision Revisions of this file
Layout/Layout.cpp Show annotated file Show diff for this revision Revisions of this file
Layout/Layout.h Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutConfig.cpp Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutConfig.h Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutConfirm.cpp Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutConfirm.h Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutDemoSampling.cpp Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutDemoSampling.h Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutFile.cpp Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutFile.h Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutHelp.cpp Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutHelp.h Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutJoin.cpp Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutJoin.h Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutScrollSelect.cpp Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutScrollSelect.h Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutStartup.cpp Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutStartup.h Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutSurveyFailure.cpp Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutSurveyFailure.h Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutSurveyProgress.cpp Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutSurveyProgress.h Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutSurveySuccess.cpp Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutSurveySuccess.h Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutSweepComplete.cpp Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutSweepComplete.h Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutSweepProgress.cpp Show annotated file Show diff for this revision Revisions of this file
Layout/LayoutSweepProgress.h Show annotated file Show diff for this revision Revisions of this file
LoRaHandler/LoRaHandler.cpp Show annotated file Show diff for this revision Revisions of this file
LoRaHandler/LoRaHandler.h Show annotated file Show diff for this revision Revisions of this file
Mode/Mode.cpp Show annotated file Show diff for this revision Revisions of this file
Mode/Mode.h Show annotated file Show diff for this revision Revisions of this file
Mode/ModeConfig.cpp Show annotated file Show diff for this revision Revisions of this file
Mode/ModeConfig.h Show annotated file Show diff for this revision Revisions of this file
Mode/ModeDemo.cpp Show annotated file Show diff for this revision Revisions of this file
Mode/ModeDemo.h Show annotated file Show diff for this revision Revisions of this file
Mode/ModeJoin.cpp Show annotated file Show diff for this revision Revisions of this file
Mode/ModeJoin.h Show annotated file Show diff for this revision Revisions of this file
Mode/ModeSingle.cpp Show annotated file Show diff for this revision Revisions of this file
Mode/ModeSingle.h Show annotated file Show diff for this revision Revisions of this file
Mode/ModeSweep.cpp Show annotated file Show diff for this revision Revisions of this file
Mode/ModeSweep.h Show annotated file Show diff for this revision Revisions of this file
SensorHandler/SensorHandler.cpp Show annotated file Show diff for this revision Revisions of this file
SensorHandler/SensorHandler.h Show annotated file Show diff for this revision Revisions of this file
license.txt Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
version.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ButtonHandler/ButtonHandler.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,156 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "ButtonHandler.h"
+
+#define signal (int32_t)0xA0
+
+typedef enum {
+    b_none = 0,
+    b_sw1_fall,
+    b_sw1_rise,
+    b_sw2_fall,
+    b_sw2_rise
+} InternalButtonEvent;
+
+InternalButtonEvent event = b_none;
+bool check_sw1 = false;
+
+void b_worker(void const* argument) {
+    ButtonHandler* b = (ButtonHandler*)argument;
+    osEvent e;
+
+    while (true) {
+        e = Thread::signal_wait(signal, 250);
+        if (e.status == osEventSignal) {
+            switch (event) {
+                case b_sw1_fall:
+                    if (! b->_sw1_running) {
+                        check_sw1 = true;
+                        b->_sw1_running = true;
+                        b->_sw1_timer.reset();
+                        b->_sw1_timer.start();
+                    }
+                    break;
+                
+                case b_sw1_rise:
+                    if (b->_sw1_running) {
+                        check_sw1 = false;
+                        b->_sw1_running = false;
+                        b->_sw1_timer.stop();
+                        b->_sw1_time = b->_sw1_timer.read_ms();
+
+                        if (b->_sw1_time > b->_debounce_time) {
+                            b->_event = ButtonHandler::sw1_press;
+                            osSignalSet(b->_main, buttonSignal);
+                        }
+                    }
+                    break;
+
+                case b_sw2_fall:
+                    if (! b->_sw2_running) {
+                        b->_sw2_running = true;
+                        b->_sw2_timer.reset();
+                        b->_sw2_timer.start();
+                    }
+                    break;
+
+                case b_sw2_rise:
+                    if (b->_sw2_running) {
+                        b->_sw2_running = false;
+                        b->_sw2_timer.stop();
+                        b->_sw2_time = b->_sw2_timer.read_ms();
+
+                        if (b->_sw2_time > b->_debounce_time) {
+                            b->_event = ButtonHandler::sw2_press;
+                            osSignalSet(b->_main, buttonSignal);
+                        }
+                    }
+                    break;
+
+                default:
+                    break;
+            }
+        }
+
+        if (check_sw1) {
+            if (b->_sw1_timer.read_ms() > b->_hold_threshold) {
+                check_sw1 = false;
+                b->_sw1_running = false;
+                b->_sw1_timer.stop();
+                b->_event = ButtonHandler::sw1_hold;
+                osSignalSet(b->_main, buttonSignal);
+            }
+        }
+    }
+}
+
+ButtonHandler::ButtonHandler(osThreadId main)
+  : _main(main),
+    _thread(b_worker, (void*)this),
+    _sw1(PA_12),
+    _sw2(PA_11),
+    _sw1_time(0),
+    _sw2_time(0),
+    _sw1_running(false),
+    _sw2_running(false),
+    _event(none),
+    _debounce_time(20),
+    _hold_threshold(500)
+{
+    // fall handler called on press, rise handler called on release
+    _sw1.fall(this, &ButtonHandler::sw1_fall);
+    _sw1.rise(this, &ButtonHandler::sw1_rise);
+    // need to set mode to PullUp after attaching handlers - default is PullNone (see PinNames.h)
+    _sw1.mode(PullUp);
+
+    _sw2.fall(this, &ButtonHandler::sw2_fall);
+    _sw2.rise(this, &ButtonHandler::sw2_rise);
+    _sw2.mode(PullUp);
+}
+
+ButtonHandler::ButtonEvent ButtonHandler::getButtonEvent() {
+    ButtonEvent event = _event;
+    _event = none;
+    return event;
+}
+
+void ButtonHandler::sw1_fall() {
+    event = b_sw1_fall;
+    _thread.signal_set(signal);
+    _thread.signal_clr(signal);
+}
+
+void ButtonHandler::sw1_rise() {
+    event = b_sw1_rise;
+    _thread.signal_set(signal);
+    _thread.signal_clr(signal);
+}
+
+void ButtonHandler::sw2_fall() {
+    event = b_sw2_fall;
+    _thread.signal_set(signal);
+    _thread.signal_clr(signal);
+}
+
+void ButtonHandler::sw2_rise() {
+    event = b_sw2_rise;
+    _thread.signal_set(signal);
+    _thread.signal_clr(signal);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ButtonHandler/ButtonHandler.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,61 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __BUTTONHANDLER_H__
+#define __BUTTONHANDLER_H__
+
+#include "mbed.h"
+#include "rtos.h"
+
+#define buttonSignal (int32_t)0x01
+
+class ButtonHandler {
+    public:
+        typedef enum {
+            none = 0,
+            sw1_press,
+            sw1_hold,
+            sw2_press
+        } ButtonEvent;
+
+        ButtonHandler(osThreadId main);
+        ~ButtonHandler();
+
+        ButtonEvent getButtonEvent();
+
+        void sw1_fall();
+        void sw1_rise();
+        void sw2_fall();
+        void sw2_rise();
+
+        osThreadId _main;
+        Thread _thread;
+        InterruptIn _sw1;
+        InterruptIn _sw2;
+        Timer _sw1_timer;
+        Timer _sw2_timer;
+        time_t _sw1_time;
+        time_t _sw2_time;
+        bool _sw1_running;
+        bool _sw2_running;
+        ButtonEvent _event;
+        time_t _debounce_time;
+        time_t _hold_threshold;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdAttention.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,34 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdAttention.h"
+
+CmdAttention::CmdAttention(mDot* dot) : Command(dot, "Attention", "AT", "Attention") 
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+}
+
+CmdAttention::CmdAttention(mDot* dot, const char* name, const char* text, const char* desc) : Command(dot, name, text, desc)
+{
+    
+}
+
+uint32_t CmdAttention::action(std::vector<std::string> args) {
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdAttention.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,35 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDATTENTION_H__
+#define __CMDATTENTION_H__
+
+#include "Command.h"
+
+class CmdAttention : public Command {
+
+public:
+
+    CmdAttention(mDot* dot);   
+    CmdAttention(mDot* dot, const char* name, const char* text, const char* desc);
+    virtual uint32_t action(std::vector<std::string> args);
+    
+private:
+};
+
+#endif // __CMDATTENTION_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdData.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,74 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdData.h"
+
+//SPECIAL NOTE: +Data is stored in the LoraConfig StartUpMode field. We decided to use 5 LoRaConfig locations,
+// that are not used for the DotBox, for the 5 DotBox settings... +minsize, +maxsize, +minpwr, +maxpwr and +data.
+CmdData::CmdData(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Data", "AT+DATA", "Enable/disable sending survey data results packet to the network server upon each successful survey. (0: off, 1: on)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0,1)";
+    _queryable = true;
+}
+
+uint32_t CmdData::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("%s: ", name());
+        _serial.writef("%d\r\n", _dot->getStartUpMode());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        bool enable = (args[1] == "1");
+
+        if ((code = _dot->setStartUpMode(enable)) != mDot::MDOT_OK) {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+
+}
+
+bool CmdData::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        if (args[1] != "1" && args[1] != "0") {
+            setErrorMessage("Invalid parameter, expects (0: off, 1: on)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdData.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,39 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDDATA_H__
+#define __CMDDATA_H__
+
+#include "Command.h"
+
+class ModeConfig;
+
+class CmdData: public Command
+{
+
+public:
+
+    CmdData(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDDATA_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDataSessionKey.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,74 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdDataSessionKey.h"
+
+CmdDataSessionKey::CmdDataSessionKey(mDot* dot, mts::MTSSerial& serial) :
+    Command(dot, "Data Session Key", "AT+DSK", "Data session encryption key (16 bytes)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(hex:16)";
+    _queryable = true;
+}
+
+uint32_t CmdDataSessionKey::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Data Session Key: ");
+        _serial.writef("%s\r\n", mts::Text::bin2hexString(_dot->getDataSessionKey(), ".").c_str());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        std::vector<uint8_t> NewKey;
+
+        // Read in the key components...
+        readByteArray(args[1], NewKey, KEY_LENGTH);
+
+        if ((code = _dot->setDataSessionKey(NewKey)) == mDot::MDOT_OK) {
+            _serial.writef("Set Data Session Key: ");
+            _serial.writef("%s\r\n", mts::Text::bin2hexString(NewKey, ".").c_str());
+        } else {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdDataSessionKey::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2) {
+        if (!isHexString(args[1], 16)) {
+            setErrorMessage("Invalid key, expects (hex:16)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDataSessionKey.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,38 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDDATASESSIONKEY_H__
+#define __CMDDATASESSIONKEY_H__
+
+#include "Command.h"
+
+class ModeConfig;
+
+class CmdDataSessionKey : public Command {
+
+public:
+
+    CmdDataSessionKey(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDDATASESSIONKEY_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDeleteSurveyDataFile.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,38 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdDeleteSurveyDataFile.h"
+#include "FileName.h"
+
+CmdDeleteSurveyDataFile::CmdDeleteSurveyDataFile(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Delete Survey Data File", "AT+DSDF", "Delete the survey data file"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+}
+
+uint32_t CmdDeleteSurveyDataFile::action(std::vector<std::string> args)
+{
+    if (!_dot->deleteUserFile(file_name)) {
+	setErrorMessage("Failed to delete survey data file");
+	return 1;
+    }
+
+    return 0;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDeleteSurveyDataFile.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,38 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDDELETESURVEYDATAFILE_H__
+#define __CMDDELETESURVEYDATAFILE_H__
+
+#include "Command.h"
+
+class ModeConfig;
+
+class CmdDeleteSurveyDataFile: public Command
+{
+
+public:
+
+    CmdDeleteSurveyDataFile(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDDELETESURVEYDATAFILE_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDeviceId.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,75 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdDeviceId.h"
+#include <algorithm>
+
+CmdDeviceId::CmdDeviceId(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Device ID", "AT+DI", "Device EUI-64 (MSB) (unique, set at factory) (8 bytes)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(hex:8)";
+    _queryable = true;
+}
+
+uint32_t CmdDeviceId::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("%s: ", name());
+        _serial.writef("%s\r\n", mts::Text::bin2hexString(_dot->getDeviceId(), "-").c_str());
+    }
+#ifdef DEBUG_MAC    
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        std::vector<uint8_t> NewEUI;
+
+        // Read in the key components...
+        readByteArray(args[1], NewEUI, EUI_LENGTH);
+
+        if ((code = _dot->setDeviceId(NewEUI)) == mDot::MDOT_OK) {
+            _serial.writef("Set %s: ", name());
+            _serial.writef("%s\r\n", mts::Text::bin2hexString(NewEUI, "-").c_str());
+        } else {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+#endif
+    return 0;
+}
+
+bool CmdDeviceId::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+#ifdef DEBUG_MAC
+    if (args.size() == 2 && isHexString(args[1], 8))
+        return true;
+
+    setErrorMessage("Invalid id, expects (hex:8)");
+#else
+    setErrorMessage("Invalid arguments");
+#endif
+
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDeviceId.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,39 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDDEVICEID_H__
+#define __CMDDEVICEID_H__
+
+#include "Command.h"
+
+class ModeConfig;
+
+class CmdDeviceId : public Command {
+
+public:
+
+    CmdDeviceId(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDDEVICEID_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDisplayConfig.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,80 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdDisplayConfig.h"
+#include "version.h"
+#include "MTSLog.h"
+
+std::string version = MTDOT_BOX_VERSION;
+
+CmdDisplayConfig::CmdDisplayConfig(mDot* dot, mts::MTSSerial& serial)
+:
+  Command(dot, "Display Settings", "AT&V", "Displays current settings and status"),
+  _serial(serial) {
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "TABLE";
+}
+
+uint32_t CmdDisplayConfig::action(std::vector<std::string> args) {
+    _serial.writef("Firmware: \t\t%s\r\n", version.c_str());
+    _serial.writef("Library : \t\t%s\r\n", _dot->getId().c_str());
+	
+    _serial.writef("Device ID:\t\t");
+    _serial.writef("%s\r\n", mts::Text::bin2hexString(_dot->getDeviceId(), ":").c_str());
+
+    _serial.writef("Frequency Band:\t\t%s\r\n", mDot::FrequencyBandStr(_dot->getFrequencyBand()).c_str());
+    if (_dot->getFrequencyBand() == mDot::FB_915)
+	_serial.writef("Frequency Sub Band:\t%u\r\n", _dot->getFrequencySubBand());
+
+    _serial.writef("Public Network:\t\t%s\r\n", _dot->getPublicNetwork() ? "on" : "off");
+
+    _serial.writef("Network Address:\t%s\r\n", mts::Text::bin2hexString(_dot->getNetworkAddress()).c_str());
+
+    _serial.writef("Network ID:\t\t");
+    _serial.writef("%s\r\n", mts::Text::bin2hexString(_dot->getNetworkId(), ":").c_str());
+
+    _serial.writef("Network ID Passphrase:\t%s\r\n", _dot->getNetworkName().c_str());
+
+    _serial.writef("Network Key:\t\t");
+    _serial.writef("%s\r\n", mts::Text::bin2hexString(_dot->getNetworkKey(), ".").c_str());
+
+    _serial.writef("Network Key Passphrase:\t%s\r\n", _dot->getNetworkPassphrase().c_str());
+
+    _serial.writef("Network Session Key:\t");
+    _serial.writef("%s\r\n", mts::Text::bin2hexString(_dot->getNetworkSessionKey(), ".").c_str());
+
+    _serial.writef("Data Session Key:\t");
+    _serial.writef("%s\r\n", mts::Text::bin2hexString(_dot->getDataSessionKey(), ".").c_str());
+
+    _serial.writef("Network Join Mode:\t%s\r\n", mDot::JoinModeStr(_dot->getJoinMode()).c_str());
+
+    _serial.writef("Tx Data Rate:\t\t%s\r\n", mDot::DataRateStr(_dot->getTxDataRate()).c_str());
+    _serial.writef("Tx Power:\t\t%u\r\n", _dot->getTxPower());
+    //_serial.writef("Log Level:\t\t%ld\r\n", _dot->getLogLevel());
+    _serial.writef("Log Level:\t\t%ld\r\n", mts::MTSLog::TRACE_LEVEL);
+
+    _serial.writef("Maximum Size:\t\t%u\r\n",	_dot->getWakeDelay());		//DotBox +MaxSize is stored here.
+    _serial.writef("Minimum Size:\t\t%u\r\n",	_dot->getWakeInterval());	//DotBox +MinSize is stored here.
+    _serial.writef("Maximum Power:\t\t%u\r\n",	_dot->getWakeMode());		//DotBox +MaxPwr is stored here.
+    _serial.writef("Minimum Power:\t\t%u\r\n",	_dot->getWakeTimeout());	//DotBox +MinPwr is stored here.
+    _serial.writef("Data:\t\t\t%d\r\n",	_dot->getStartUpMode());			//DotBox +Data is stored here.
+
+
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDisplayConfig.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,37 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDDISPLAYCONFIG_H__
+#define __CMDDISPLAYCONFIG_H__
+
+#include "Command.h"
+
+class CmdDisplayConfig : public Command {
+
+public:
+
+    CmdDisplayConfig(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+
+private:
+
+    mts::MTSSerial& _serial;
+
+};
+
+#endif // __CMDDISPLAYCONFIG_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDummy.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,31 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdDummy.h"
+
+CmdDummy::CmdDummy(mDot* dot, const char* name, const char* txt, const char* dsc) : Command(dot, name, txt, dsc)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+}
+
+
+uint32_t CmdDummy::action(std::vector<std::string> args)
+{
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdDummy.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,34 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDDUMMY_H__
+#define __CMDDUMMY_H__
+
+#include "Command.h"
+
+class CmdDummy : public Command {
+
+public:
+
+    CmdDummy(mDot* dot, const char* name, const char* text, const char* desc);
+    virtual uint32_t action(std::vector<std::string> args);
+
+private:
+};
+
+#endif // __CMDDUMMY_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdFactoryDefault.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,49 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdFactoryDefault.h"
+
+CmdFactoryDefault::CmdFactoryDefault(mDot* dot) : Command(dot, "Reset Factory Defaults", "AT&F", "Reset current configuration to factory defaults")
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+}
+
+
+uint32_t CmdFactoryDefault::action(std::vector<std::string> args)
+{
+    _dot->resetConfig();
+
+//Factory defaults for the DotBox.
+    _dot->setTxDataRate(mDot::SF_7);
+    _dot->setFrequencySubBand(1);
+    _dot->setWakeDelay(242);		//DotBox +MaxSize is stored here. Default is 242.
+    _dot->setWakeInterval(11);		//DotBox +MinSize is stored here. Default is 11.
+    _dot->setWakeMode(20);		//DotBox +MaxPwr is stored here. Default is 20.
+    _dot->setWakeTimeout(2);		//DotBox +MinPwr is stored here. Default is 2.
+    _dot->setStartUpMode(0);		//DotBox +Data is stored here. Default is 0.
+    _dot->setVerbose(1);
+    _dot->setEcho(1);
+    _dot->setAck(1);
+    _dot->setJoinMode(mDot::OTA);
+    _dot->setNetworkName("MultiTech");
+    _dot->setNetworkPassphrase("MultiTech");
+	
+    _dot->resetNetworkSession();
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdFactoryDefault.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,34 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CmdFactoryDefault_H__
+#define __CmdFactoryDefault_H__
+
+#include "Command.h"
+
+class CmdFactoryDefault : public Command {
+
+public:
+
+    CmdFactoryDefault(mDot* dot);
+    virtual uint32_t action(std::vector<std::string> args);
+
+private:
+};
+
+#endif // __CmdFactoryDefault_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdFrequencyBand.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,81 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdFrequencyBand.h"
+
+CmdFrequencyBand::CmdFrequencyBand(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Frequency Band", "AT+FREQ", "Configured Frequency Band '868' or '915'"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(868,915)";
+    _queryable = true;
+}
+
+uint32_t CmdFrequencyBand::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Frequency Band: ");
+
+        _serial.writef("%s\r\n", mDot::FrequencyBandStr(_dot->getFrequencyBand()).c_str());
+    }
+
+#ifdef DEBUG_MAC
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint8_t band = mDot::FB_915;
+
+        if (mDot::FrequencyBandStr(mDot::FB_868).find(args[1]) != std::string::npos) {
+            band = mDot::FB_868;
+        }
+
+        if ((code = _dot->setFrequencyBand(band)) != mDot::MDOT_OK) {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+#endif
+
+    return 0;
+}
+
+bool CmdFrequencyBand::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+#ifdef DEBUG_MAC
+    if (args.size() == 2)
+    {
+        if (mDot::FrequencyBandStr(mDot::FB_868).find(args[1]) == std::string::npos &&
+            mDot::FrequencyBandStr(mDot::FB_915).find(args[1]) == std::string::npos)
+        {
+            setErrorMessage("Invalid parameter, expects (868,915)");
+            return false;
+        }
+
+        return true;
+    }
+#endif
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdFrequencyBand.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,39 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDFREQUENCYBAND_H__
+#define __CMDFREQUENCYBAND_H__
+
+#include "Command.h"
+
+class CommandTerminal;
+
+class CmdFrequencyBand : public Command {
+
+public:
+
+    CmdFrequencyBand(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDFREQUENCYBAND_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdFrequencySubBand.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,78 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdFrequencySubBand.h"
+
+CmdFrequencySubBand::CmdFrequencySubBand(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Frequency Sub-band", "AT+FSB", "Set the frequency sub-band for US 915, (0:ALL, 1-8)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0-8)";
+    _queryable = true;
+}
+
+uint32_t CmdFrequencySubBand::action(std::vector<std::string> args)
+{
+
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Frequency Sub Band: ");
+
+        _serial.writef("%u\r\n", _dot->getFrequencySubBand());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint32_t band;
+        sscanf(args[1].c_str(), "%lu", &band);
+
+        if ((code = _dot->setFrequencySubBand(band)) != mDot::MDOT_OK) {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdFrequencySubBand::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        uint32_t band;
+        if (sscanf(args[1].c_str(), "%u", &band) != 1) {
+            setErrorMessage("Invalid arguments");
+            return false;
+        }
+
+        if (band < mDot::FSB_ALL || band > mDot::FSB_8) {
+            setErrorMessage("Invalid channel band, expects (0-8)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdFrequencySubBand.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,38 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDFREQUENCYSUBBAND_H__
+#define __CMDFREQUENCYSUBBAND_H__
+
+#include "Command.h"
+
+class ModeConfig;
+
+class CmdFrequencySubBand : public Command {
+
+public:
+
+    CmdFrequencySubBand(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDFREQUENCYSUBBAND_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdGetSurveyDataFile.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,68 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdGetSurveyDataFile.h"
+#include "FileName.h"
+#include "MTSLog.h"
+
+CmdGetSurveyDataFile::CmdGetSurveyDataFile(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Get Survey Data File", "AT+GSDF", "Outputs the survey data file contents to the command port"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+}
+
+uint32_t CmdGetSurveyDataFile::action(std::vector<std::string> args)
+{
+    mDot::mdot_file file;
+    int buf_size = 512;
+    char buf[buf_size];
+    int read;
+    int read_size;
+
+    file = _dot->openUserFile(file_name, mDot::FM_RDONLY);
+    if (file.fd < 0) {
+        setErrorMessage("Failed to open file");
+        return 1;
+    }
+
+    // print header line with column labels
+    _serial.writef("ID,Status,Lock,Lat,Long,Alt,Time,Gateways,Margin,RSSIdown,SNRdown,DataRate,Power\r\n");
+
+    while (read < file.size) {
+        read_size = (file.size - read) > buf_size ? buf_size : file.size - read;
+        int size = _dot->readUserFile(file, (void*)buf, read_size);
+        if (size < 0) {
+            setErrorMessage("Failed to read file");
+            _dot->closeUserFile(file);
+            return 1;
+        }
+
+        for (int i = 0; i < size; i++) {
+            if (buf[i] == '\n')
+                _serial.writef("\r\n");
+            else
+                _serial.writef("%c", buf[i]);
+        }
+
+        read += size;
+    }
+
+    _dot->closeUserFile(file);
+    
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdGetSurveyDataFile.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,38 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDGETSURVEYDATAFILE_H__
+#define __CMDGETSURVEYDATAFILE_H__
+
+#include "Command.h"
+
+class ModeConfig;
+
+class CmdGetSurveyDataFile: public Command
+{
+
+public:
+
+    CmdGetSurveyDataFile(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDGETSURVEYDATAFILE_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdIdentification.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,38 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdIdentification.h"
+#include "version.h"
+
+CmdIdentification::CmdIdentification(mDot* dot, mts::MTSSerial& serial) : Command(dot, "Request Id", "ATI", "Request Identification"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+}
+
+uint32_t CmdIdentification::action(std::vector<std::string> args)
+{
+    std::string version = MTDOT_BOX_VERSION;
+#ifdef DEBUG_MAC
+    version += "-debug";
+#endif
+    _serial.writef("MultiTech mDot\r\n");
+    _serial.writef("Firmware: %s\r\n", version.c_str());
+    _serial.writef("Library : %s\r\n", _dot->getId().c_str());
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdIdentification.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,35 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDIDENTIFICATION_H__
+#define __CMDIDENTIFICATION_H__
+
+#include "Command.h"
+
+class CmdIdentification : public Command {
+
+public:
+
+    CmdIdentification(mDot* dot, mts::MTSSerial& serial);   
+    virtual uint32_t action(std::vector<std::string> args);
+    
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDIDENTIFICATION_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdMaximumPower.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,85 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdMaximumPower.h"
+
+//SPECIAL NOTE: Maximum power is stored in the LoraConfig WakeMode field. We decided to use 5 LoRaConfig locations,
+// that are not used for the DotBox, for the 5 DotBox settings... +minsize, +maxsize, +minpwr, +maxpwr and +data.
+CmdMaximumPower::CmdMaximumPower(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Maximum Power", "AT+MAXPWR", "Set the maximum transmit power for survey sweep mode"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(2-20)";
+    _queryable = true;
+}
+
+uint32_t CmdMaximumPower::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Maximum Power: ");
+        _serial.writef("%lu\r\n", _dot->getWakeMode());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint32_t power = 0;
+        sscanf(args[1].c_str(), "%lu", &power);
+        if ((code = _dot->setWakeMode(power)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdMaximumPower::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        uint32_t power = 0;
+        if (sscanf(args[1].c_str(), "%lu", &power) != 1) {
+            setErrorMessage("Invalid argument");
+            return false;
+        }
+
+        if (power < 2 || power > 20)
+        {
+            setErrorMessage("Invalid maximum transmit power for sweep survey mode, expects (2-20)");
+            return false;
+        }
+        if (power < _dot->getWakeTimeout())	//WakeTimeout holds the MinPower setting.
+        {
+            setErrorMessage("+MAXPWR cannot be less than +MINPWR. Please decrease +MINPWR first.");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdMaximumPower.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,39 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDMAXIMUMPOWER_H__
+#define __CMDMAXIMUMPOWER_H__
+
+#include "Command.h"
+
+class ModeConfig;
+
+class CmdMaximumPower: public Command
+{
+
+public:
+
+    CmdMaximumPower(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDMAXIMUMPOWER_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdMaximumSize.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,86 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdMaximumSize.h"
+
+//SPECIAL NOTE: Maximum size is stored in the LoraConfig WakeDelay field. We decided to use 5 LoRaConfig locations,
+// that are not used for the DotBox, for the 5 DotBox settings... +minsize, +maxsize, +minpwr, +maxpwr and +data.
+CmdMaximumSize::CmdMaximumSize(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Maximum Size", "AT+MAXSIZE", "Set the maximum payload size for survey sweep mode"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(11-242)";
+    _queryable = true;
+}
+
+uint32_t CmdMaximumSize::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Maximum Size: ");
+        _serial.writef("%lu\r\n", _dot->getWakeDelay());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint32_t size = 0;
+        sscanf(args[1].c_str(), "%lu", &size);
+
+        if ((code = _dot->setWakeDelay(size)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdMaximumSize::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        uint32_t size = 0;
+        if (sscanf(args[1].c_str(), "%lu", &size) != 1) {
+            setErrorMessage("Invalid argument");
+            return false;
+        }
+
+        if (size < 11 || size > 242)
+        {
+            setErrorMessage("Invalid maximum payload size, expects (11-242)");
+            return false;
+        }
+        if (size < _dot->getWakeInterval())	//WakeInterval holds the MinSize setting.
+        {
+            setErrorMessage("+MAXSIZE cannot be less than +MINSIZE. Please decrease +MINSIZE first.");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdMaximumSize.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,39 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDMAXIMUMSIZE_H__
+#define __CMDMAXIMUMSIZE_H__
+
+#include "Command.h"
+
+class ModeConfig;
+
+class CmdMaximumSize: public Command
+{
+
+public:
+
+    CmdMaximumSize(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDMAXIMUMSIZE_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdMinimumPower.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,86 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdMinimumPower.h"
+
+//SPECIAL NOTE: Minimum power is stored in the LoraConfig WakeTimeout field. We decided to use 5 LoRaConfig locations,
+// that are not used for the DotBox, for the 5 DotBox settings... +minsize, +maxsize, +minpwr, +maxpwr and +data.
+CmdMinimumPower::CmdMinimumPower(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Minimum Power", "AT+MINPWR", "Set the minimum transmit power for survey sweep mode"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(2-20)";
+    _queryable = true;
+}
+
+uint32_t CmdMinimumPower::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Minimum Power: ");
+        _serial.writef("%lu\r\n", _dot->getWakeTimeout());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint32_t power = 0;
+        sscanf(args[1].c_str(), "%lu", &power);
+
+        if ((code = _dot->setWakeTimeout(power)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdMinimumPower::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        uint32_t power = 0;
+        if (sscanf(args[1].c_str(), "%lu", &power) != 1) {
+            setErrorMessage("Invalid argument");
+            return false;
+        }
+
+        if (power < 2 || power > 20)
+        {
+            setErrorMessage("Invalid minimum transmit power for sweep survey mode, expects (2-20)");
+            return false;
+        }
+        if (power > _dot->getWakeMode())	//WakeMode holds the MaxPower setting.
+        {
+            setErrorMessage("+MINPWR cannot be greater than +MAXPWR. Please increase +MAXPWR first.");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdMinimumPower.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,39 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDMINIMUMPOWER_H__
+#define __CMDMINIMUMPOWER_H__
+
+#include "Command.h"
+
+class ModeConfig;
+
+class CmdMinimumPower: public Command
+{
+
+public:
+
+    CmdMinimumPower(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDMINIMUMPOWER_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdMinimumSize.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,85 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdMinimumSize.h"
+
+//SPECIAL NOTE: Minimum size is stored in the LoraConfig WakeInterval field. We decided to use 5 LoRaConfig locations,
+// that are not used for the DotBox, for the 5 DotBox settings... +minsize, +maxsize, +minpwr, +maxpwr and +data.
+CmdMinimumSize::CmdMinimumSize(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Minimum Size", "AT+MINSIZE", "Set the minimum payload size for survey sweep mode"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(11-242)";
+    _queryable = true;
+}
+
+uint32_t CmdMinimumSize::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Minimum Size: ");
+        _serial.writef("%lu\r\n", _dot->getWakeInterval());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint32_t size = 0;
+        sscanf(args[1].c_str(), "%lu", &size);
+
+        if ((code = _dot->setWakeInterval(size)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdMinimumSize::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        uint32_t size = 0;
+        if (sscanf(args[1].c_str(), "%lu", &size) != 1) {
+            setErrorMessage("Invalid argument");
+            return false;
+        }
+
+        if (size < 11 || size > 242)
+        {
+            setErrorMessage("Invalid minimum payload size, expects (11-242)");
+            return false;
+        }
+        if (size > _dot->getWakeDelay())	//WakeDelay holds the MaxSize setting.
+        {
+            setErrorMessage("+MINSIZE cannot be greater than +MAXSIZE. Please increase +MAXSIZE first.");
+            return false;
+        }
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdMinimumSize.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,39 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDMINIMUMSIZE_H__
+#define __CMDMINIMUMSIZE_H__
+
+#include "Command.h"
+
+class ModeConfig;
+
+class CmdMinimumSize: public Command
+{
+
+public:
+
+    CmdMinimumSize(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDMINIMUMSIZE_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkAddress.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,90 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdNetworkAddress.h"
+#include <algorithm>
+
+CmdNetworkAddress::CmdNetworkAddress(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Network Address", "AT+NA", "Network address (devAddr in LoraMac) (4 bytes)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(hex:4)";
+    _queryable = true;
+}
+
+uint32_t CmdNetworkAddress::action(std::vector<std::string> args)
+{
+    std::vector<uint8_t> addr;
+
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Network Address: ");
+
+        addr = _dot->getNetworkAddress();
+
+        _serial.writef("%02x:%02x:%02x:%02x\r\n", addr[0], addr[1], addr[2], addr[3]);
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint8_t temp;
+        uint32_t step = 2;
+
+        if (args[1].find(":") != std::string::npos || args[1].find(".") != std::string::npos || args[1].find("-") != std::string::npos)
+            step = 3;
+
+        // Convert the ASCII hex data to binary...
+        for (size_t i = 0; i < args[1].size(); i += step) 
+        {
+            sscanf(&args[1][i], "%02x", &temp);
+            addr.push_back(temp);
+        }
+
+        if ((code = _dot->setNetworkAddress(addr)) == mDot::MDOT_OK) {
+            _serial.writef("Set Network Address: ");
+            _serial.writef("%02x:%02x:%02x:%02x\r\n", addr[0], addr[1], addr[2], addr[3]);
+        } else {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdNetworkAddress::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1) {
+        return true;
+    }
+
+    if (args.size() == 2) {
+        if (!isHexString(args[1], 4))
+        {
+            setErrorMessage("Invalid address, expects (hex:4)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkAddress.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,38 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDNETWORKADDRESS_H__
+#define __CMDNETWORKADDRESS_H__
+
+#include "Command.h"
+
+class ModeConfig;
+
+class CmdNetworkAddress : public Command {
+
+public:
+
+    CmdNetworkAddress(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDNETWORKADDRESS_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkId.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,128 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdNetworkId.h"
+
+CmdNetworkId::CmdNetworkId(mDot* dot, mts::MTSSerial& serial) :
+    Command(dot, "Network ID", "AT+NI", "Configured Network EUI/Name (App EUI in LoraMac) AT+NI=0,hex AT+NI=1,network_name  (Net ID = crc64(network_name)) (8 bytes)"),
+            _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0,(hex:8)),(1,(string:128))";
+    _queryable = true;
+}
+
+uint32_t CmdNetworkId::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Network ID: ");
+
+        _serial.writef("%s\r\n", mts::Text::bin2hexString(_dot->getNetworkId(), ":").c_str());
+
+        if (!_dot->getNetworkName().empty())
+            _serial.writef("Passphrase: '%s'\r\n", _dot->getNetworkName().c_str());
+    }
+    else
+    {
+        int32_t code;
+
+        if (args[1].find("1") == 0 && args[1].size() == 1)
+        {
+            std::string text;
+            if (args.size() > 3)
+            {
+                // passphrase was split on commas
+                for (size_t i = 2; i < args.size(); i++)
+                {
+                    text.append(args[i]);
+                    if (i < args.size() - 1)
+                        text.append(",");
+                }
+            }
+            else
+            {
+                text = args[2];
+            }
+
+            if ((code = _dot->setNetworkName(text)) == mDot::MDOT_OK)
+            {
+                _serial.writef("Set Network Name: ");
+                _serial.writef("%s\r\n", text.c_str());
+            }
+            else
+            {
+                std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+                setErrorMessage(error);
+                return 1;
+            }
+
+        }
+        else
+        {
+            std::vector<uint8_t> NewKey;
+            readByteArray(args[2], NewKey, EUI_LENGTH);
+            if ((code = _dot->setNetworkId(NewKey)) == mDot::MDOT_OK)
+            {
+                _serial.writef("Set Network ID: ");
+                _serial.writef("%s\r\n", mts::Text::bin2hexString(NewKey, ".").c_str());
+            }
+            else
+            {
+                std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+                setErrorMessage(error);
+                return 1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+bool CmdNetworkId::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 3) {
+        if (args[1] != "0" && args[1] != "1") {
+            setErrorMessage("Invalid type, expects (0,1)");
+            return false;
+        }
+        if (args[1] == "0" && !isHexString(args[2], 8)) {
+            setErrorMessage("Invalid ID, expects (hex:8");
+            return false;
+        }
+
+        if (args[1] == "1" && args[2].size() < 8) {
+            setErrorMessage("Invalid name, expects minimum 8 characters");
+            return false;
+        }
+
+        if (args[1] == "1" && args[2].size() > 128) {
+            setErrorMessage("Invalid name, expects (string:128)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkId.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,38 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDNETWORKID_H__
+#define __CMDNETWORKID_H__
+
+#include "Command.h"
+
+class ModeConfig;
+
+class CmdNetworkId : public Command {
+
+public:
+
+    CmdNetworkId(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDNETWORKID_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkJoinMode.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,72 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdNetworkJoinMode.h"
+
+CmdNetworkJoinMode::CmdNetworkJoinMode(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Network Join Mode", "AT+NJM", "0: Manual configuration, 1: OTA Network Join (default: 1)"),
+        _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0-1)";
+    _queryable = true;
+}
+
+uint32_t CmdNetworkJoinMode::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("%s: ", name());
+
+        _serial.writef("%u\r\n", _dot->getJoinMode());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint8_t mode = (args[1] == "1") ? 1 : 0;
+        if ((code = _dot->setJoinMode(mode)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdNetworkJoinMode::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        if (!(args[1] == "0" || args[1] == "1"))
+        {
+            setErrorMessage("Invalid parameter, expects (0: Manual, 1: OTA)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkJoinMode.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,38 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDNETWORKJOINMODE_H__
+#define __CMDNETWORKJOINMODE_H__
+
+#include "Command.h"
+
+class ModeConfig;
+
+class CmdNetworkJoinMode : public Command {
+
+public:
+
+    CmdNetworkJoinMode(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDNETWORKJOINMODE_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkKey.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,128 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdNetworkKey.h"
+
+CmdNetworkKey::CmdNetworkKey(mDot* dot, mts::MTSSerial& serial) :
+    Command(dot, "Network Key", "AT+NK", "Configured network key/passphrase (App Key in LoraMac) AT+NK=0,hex  AT+NK=1,passphrase (Net key = cmac(passphrase)) (16 bytes)"),
+    _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0,(hex:16)),(1,(string:128))";
+    _queryable = true;
+}
+
+uint32_t CmdNetworkKey::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Network Key: ");
+
+        _serial.writef("%s\r\n", mts::Text::bin2hexString(_dot->getNetworkKey(), ".").c_str());
+        if (!_dot->getNetworkPassphrase().empty())
+            _serial.writef("Passphrase: '%s'\r\n", _dot->getNetworkPassphrase().c_str());
+
+    }
+    else if (args.size() == 3)
+    {
+        int32_t code;
+
+        if (args[1].find("1") == 0 && args[1].size() == 1)
+        {
+            std::string text;
+            if (args.size() > 3)
+            {
+                // passphrase was split on commas
+                for (size_t i = 2; i < args.size(); i++)
+                {
+                    text.append(args[i]);
+                    if (i < args.size() - 1)
+                        text.append(",");
+                }
+            }
+            else
+            {
+                text = args[2];
+            }
+
+            if ((code = _dot->setNetworkPassphrase(text)) == mDot::MDOT_OK)
+            {
+                _serial.writef("Set Network Passphrase: ");
+                _serial.writef("%s\r\n", text.c_str());
+            }
+            else
+            {
+                std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+                setErrorMessage(error);
+                return 1;
+            }
+        }
+        else
+        {
+            std::vector<uint8_t> NewKey;
+            readByteArray(args[2], NewKey, KEY_LENGTH);
+            if ((code = _dot->setNetworkKey(NewKey)) == mDot::MDOT_OK)
+            {
+                _serial.writef("Set Network Key: ");
+                _serial.writef("%s\r\n", mts::Text::bin2hexString(NewKey, ".").c_str());
+            }
+            else
+            {
+                std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+                setErrorMessage(error);
+                return 1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+bool CmdNetworkKey::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 3) {
+        if (args[1] != "0" && args[1] != "1") {
+            setErrorMessage("Invalid type, expects (0,1)");
+            return false;
+        }
+        if (args[1] == "0" && !isHexString(args[2], 16)) {
+            setErrorMessage("Invalid key, expects (hex:16)");
+            return false;
+        }
+
+        if (args[1] == "1" && args[2].size() < 8) {
+            setErrorMessage("Invalid name, expects minimum 8 characters");
+            return false;
+        }
+
+        if (args[1] == "1" && (args[2].size() > 128 || args[2].size() < 8)) {
+            setErrorMessage("Invalid passphrase, expects (string:8-128)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkKey.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,40 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef __CMDNETWORKKEY_H__
+#define __CMDNETWORKKEY_H__
+
+
+#include "Command.h"
+
+class ModeConfig;
+
+class CmdNetworkKey : public Command {
+
+public:
+
+    CmdNetworkKey(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDNETWORKKEY_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkSessionKey.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,75 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdNetworkSessionKey.h"
+
+CmdNetworkSessionKey::CmdNetworkSessionKey(mDot* dot, mts::MTSSerial& serial) :
+    Command(dot, "Network Session Key", "AT+NSK", "Network session encryption key (16 bytes)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(hex:16)";
+    _queryable = true;
+}
+
+uint32_t CmdNetworkSessionKey::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Network Session Key: ");
+
+        _serial.writef("%s\r\n", mts::Text::bin2hexString(_dot->getNetworkSessionKey(), ".").c_str());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        std::vector<uint8_t> NewKey;
+
+        // Read in the key components...
+        readByteArray(args[1], NewKey, KEY_LENGTH);
+
+        if ((code = _dot->setNetworkSessionKey(NewKey)) == mDot::MDOT_OK) {
+            _serial.writef("Set Network Session Key: ");
+            _serial.writef("%s\r\n", mts::Text::bin2hexString(NewKey, ".").c_str());
+        } else {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdNetworkSessionKey::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2) {
+        if (!isHexString(args[1], 16)) {
+            setErrorMessage("Invalid key, expects (hex:16)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdNetworkSessionKey.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,38 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDNETWORKSESSIONKEY_H__
+#define __CMDNETWORKSESSIONKEY_H__
+
+#include "Command.h"
+
+class ModeConfig;
+
+class CmdNetworkSessionKey : public Command {
+
+public:
+
+    CmdNetworkSessionKey(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDNETWORKSESSIONKEY_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdPublicNetwork.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,70 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdPublicNetwork.h"
+
+CmdPublicNetwork::CmdPublicNetwork(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Public Network", "AT+PN", "Enable/disable public network mode. (0: off, 1: on)"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(0,1)";
+    _queryable = true;
+}
+
+uint32_t CmdPublicNetwork::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("%s: ", name());
+
+        _serial.writef("%d\r\n", _dot->getPublicNetwork());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        bool enable = (args[1] == "1");
+
+        if ((code = _dot->setPublicNetwork(enable)) != mDot::MDOT_OK) {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdPublicNetwork::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        if (args[1] != "1" && args[1] != "0") {
+            setErrorMessage("Invalid parameter, expects (0: off, 1: on)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdPublicNetwork.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,39 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDPUBLICNETWORK_H__
+#define __CMDPUBLICNETWORK_H__
+
+#include "Command.h"
+
+class ModeConfig;
+
+class CmdPublicNetwork : public Command {
+
+public:
+
+    CmdPublicNetwork(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDPUBLICNETWORK_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSaveConfig.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,35 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdSaveConfig.h"
+
+CmdSaveConfig::CmdSaveConfig(mDot* dot) : Command(dot, "Save Configuration", "AT&W", "Save configuration to flash memory")
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+}
+
+
+uint32_t CmdSaveConfig::action(std::vector<std::string> args)
+{
+    if (!_dot->saveConfig()) {
+      setErrorMessage("Failed to save to flash");
+      return 1;
+    }
+    
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdSaveConfig.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,35 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef __CmdSaveConfig_H__
+#define __CmdSaveConfig_H__
+
+#include "Command.h"
+
+class CmdSaveConfig : public Command {
+
+public:
+
+    CmdSaveConfig(mDot* dot);
+    virtual uint32_t action(std::vector<std::string> args);
+
+private:
+};
+
+#endif // __CmdSaveConfig_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdTxDataRate.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,107 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdTxDataRate.h"
+
+CmdTxDataRate::CmdTxDataRate(mDot* dot, mts::MTSSerial& serial) :
+    Command(dot, "Tx Data Rate", "AT+TXDR", "Set the Tx data rate for LoRa demo mode"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+
+    if (_dot->getFrequencyBand() == mDot::FB_915)
+        _usage = "(7-10)";
+    else
+        _usage = "(7-12)";
+    _queryable = true;
+}
+
+uint32_t CmdTxDataRate::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Tx Data Rate: ");
+
+        _serial.writef("%s\r\n", mDot::DataRateStr(_dot->getTxDataRate()).c_str());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint8_t datarate = 0;
+        uint8_t i;
+
+        for (i = 0; i < 8; i++)
+        {
+            if (mDot::DataRateStr(i).find(args[1].c_str()) != std::string::npos)
+            {
+                datarate = i;
+                break;
+            }
+        }
+
+        if ((code = _dot->setTxDataRate(datarate)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdTxDataRate::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        uint8_t i;
+        int datarate = -1;
+        for (i = 0; i < 8; i++)
+        {
+            if (mDot::DataRateStr(i).find(args[1].c_str()) != std::string::npos)
+            {
+                datarate = i;
+                break;
+            }
+        }
+
+        if (datarate < 0)
+        {       
+            if (_dot->getFrequencyBand() == mDot::FB_915)
+                setErrorMessage("Invalid data rate, expects (7-10)");
+            else
+                setErrorMessage("Invalid data rate, expects (7-12)");
+            return false;
+        }   
+
+        if (_dot->getFrequencyBand() == mDot::FB_915) {
+            if (datarate < 2) {
+                setErrorMessage("Invalid data rate, expects (7-10)");
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdTxDataRate.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,38 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDTXDATARATE_H__
+#define __CMDTXDATARATE_H__
+
+#include "Command.h"
+
+class ModeConfig;
+
+class CmdTxDataRate : public Command {
+
+public:
+
+    CmdTxDataRate(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+    
+private:   
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDTXDATARATE_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdTxPower.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,80 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdTxPower.h"
+
+CmdTxPower::CmdTxPower(mDot* dot, mts::MTSSerial& serial) :
+        Command(dot, "Tx Power", "AT+TXP", "Set the Tx power for LoRa demo mode"), _serial(serial)
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+    _usage = "(2-20)";
+    _queryable = true;
+}
+
+uint32_t CmdTxPower::action(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+    {
+        if (_dot->getVerbose())
+            _serial.writef("Tx Power: ");
+
+        _serial.writef("%lu\r\n", _dot->getTxPower());
+    }
+    else if (args.size() == 2)
+    {
+        int32_t code;
+        uint32_t power = 0;
+        sscanf(args[1].c_str(), "%lu", &power);
+
+        if ((code = _dot->setTxPower(power)) != mDot::MDOT_OK)
+        {
+            std::string error = mDot::getReturnCodeString(code) + " - " + _dot->getLastError();
+            setErrorMessage(error);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+bool CmdTxPower::verify(std::vector<std::string> args)
+{
+    if (args.size() == 1)
+        return true;
+
+    if (args.size() == 2)
+    {
+        uint32_t power = 0;
+        if (sscanf(args[1].c_str(), "%lu", &power) != 1) {
+            setErrorMessage("Invalid argument");
+            return false;
+        }
+
+        if (power < 2 || power > 20)
+        {
+            setErrorMessage("Invalid power, expects (2-20)");
+            return false;
+        }
+
+        return true;
+    }
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdTxPower.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,39 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CMDTXPOWER_H__
+#define __CMDTXPOWER_H__
+
+#include "Command.h"
+
+class ModeConfig;
+
+class CmdTxPower: public Command
+{
+
+public:
+
+    CmdTxPower(mDot* dot, mts::MTSSerial& serial);
+    virtual uint32_t action(std::vector<std::string> args);
+    virtual bool verify(std::vector<std::string> args);
+
+private:
+    mts::MTSSerial& _serial;
+};
+
+#endif // __CMDTXPOWER_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdWriteProtectedConfig.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,35 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "CmdWriteProtectedConfig.h"
+
+CmdWriteProtectedConfig::CmdWriteProtectedConfig(mDot* dot) :
+        Command(dot, "Write Protected Config", "AT&WP", "Write protected config to flash (DeviceId and Frequency Band)")
+{
+    _help = std::string(text()) + ": " + std::string(desc());
+}
+
+uint32_t CmdWriteProtectedConfig::action(std::vector<std::string> args)
+{
+    if (!_dot->saveProtectedConfig()) {
+      setErrorMessage("Failed to save to flash");
+      return 1;
+    }
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CmdWriteProtectedConfig.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,35 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef __CMDWRITEPROTECTEDCONFIG_H__
+#define __CMDWRITEPROTECTEDCONFIG_H__
+
+#include "Command.h"
+
+class CmdWriteProtectedConfig : public Command {
+
+public:
+
+    CmdWriteProtectedConfig(mDot* dot);
+    virtual uint32_t action(std::vector<std::string> args);
+
+private:
+};
+
+#endif // __CMDWRITEPROTECTEDCONFIG_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/Command.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,146 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "Command.h"
+#include <algorithm>
+
+const char Command::newline[] = "\r\n";
+
+Command::Command(mDot* dot) : _dot(dot)
+{
+    _usage = "NONE";
+    _queryable = false;
+}
+
+Command::Command(mDot* dot, const char* name, const char* text, const char* desc) :
+    _dot(dot), _name(name), _text(text), _desc(desc)
+{
+    _usage = "NONE";
+    _queryable = false;
+}
+
+std::string &Command::errorMessage()
+{
+    return _errorMessage;
+}
+
+void Command::setErrorMessage(const char* message)
+{
+    _errorMessage.assign(message);
+}
+
+void Command::setErrorMessage(const std::string& message)
+{
+    _errorMessage.assign(message);
+}
+
+const std::string Command::usage() const
+{
+    std::string usage(_text);
+    usage.append(": ");
+    usage.append(_usage);
+    return usage;
+}
+
+const bool Command::queryable()
+{
+    return _queryable;
+}
+
+void Command::readByteArray(const std::string& input, std::vector<uint8_t>& out, size_t len)
+{
+    // if input length is greater than expected byte output
+    // there must be a delimiter included
+    if (input.length() > len * 2)
+    {
+        std::vector < std::string > bytes;
+        if (input.find(" ") != std::string::npos)
+            bytes = mts::Text::split(input, " ");
+        else if (input.find(":") != std::string::npos)
+            bytes = mts::Text::split(input, ":");
+        else if (input.find("-") != std::string::npos)
+            bytes = mts::Text::split(input, "-");
+        else if (input.find(".") != std::string::npos)
+            bytes = mts::Text::split(input, ".");
+
+        if (bytes.size() != len) {
+            return;
+        }
+
+        uint8_t temp;
+        // Read in the key components...
+        for (size_t i = 0; i < len; i++)
+        {
+            sscanf(bytes[i].c_str(), "%02x", &temp);
+            out.push_back(temp);
+        }
+    }
+    else
+    {
+        // no delims
+        uint8_t temp;
+
+        // Read in the key components...
+        for (size_t i = 0; i < len; i++)
+        {
+            if (i * 2 < input.size())
+            {
+                sscanf(input.substr(i * 2).c_str(), "%02x", &temp);
+                out.push_back(temp);
+            }
+        }
+    }
+}
+
+bool Command::isHexString(const std::string& str, size_t bytes) {
+    size_t numDelims = bytes - 1;
+    size_t minSize = bytes * 2;
+    size_t maxSize = minSize + numDelims;
+
+    if (str.size() == minSize) {
+        return str.find_first_not_of("0123456789abcdefABCDEF") == std::string::npos;
+    }
+    else if (str.size() == maxSize) {
+        if (str.find_first_of(":-.") == std::string::npos) {
+            // no delim found
+            return false;
+        }
+        if (str.find(":") != std::string::npos && std::count(str.begin(), str.end(), ':') != numDelims) {
+            return false;
+        }
+        if (str.find(".") != std::string::npos && std::count(str.begin(), str.end(), '.') != numDelims) {
+            return false;
+        }
+        if (str.find("-") != std::string::npos && std::count(str.begin(), str.end(), '-') != numDelims) {
+            return false;
+        }
+
+        return str.find_first_not_of("0123456789abcdefABCDEF:-.") == std::string::npos;
+    }   
+
+    return false;
+}
+
+bool Command::verify(std::vector<std::string> args) {
+    if (args.size() == 1)
+        return true;
+
+    setErrorMessage("Invalid arguments");
+    return false;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/Command.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,115 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ ******************************************************************************
+ * File Name          : Command.h
+ * Date               : 18/04/2014 10:57:12
+ * Description        : This file provides code for command line prompt
+ ******************************************************************************
+ *
+ * COPYRIGHT(c) 2014 MultiTech Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *   1. Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright notice,
+ *      this list of conditions and the following disclaimer in the documentation
+ *      and/or other materials provided with the distribution.
+ *   3. Neither the name of STMicroelectronics nor the names of its contributors
+ *      may be used to endorse or promote products derived from this software
+ *      without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+#include "mbed.h"
+#include "mDot.h"
+#include "MTSSerial.h"
+#include "MTSText.h"
+#include <cstdlib>
+#include <string>
+#include <vector>
+#include "limits.h"
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __command_H
+#define __command_H
+
+#define KEY_LENGTH 16
+#define EUI_LENGTH 8
+#define PASSPHRASE_LENGTH 128
+
+class Command {
+
+    public:
+
+        Command(mDot* dot);
+        Command(mDot* dot, const char* name, const char* text, const char* desc);
+        virtual ~Command() {};
+
+        const char* name() const { return _name; };
+        const char* text() const { return _text; };
+        const char* desc() const { return _desc; };
+        const char* help() const { return _help.c_str(); };
+
+        virtual uint32_t action(std::vector<std::string> args) = 0;
+        virtual bool verify(std::vector<std::string> args);
+        const std::string usage() const;
+        std::string& errorMessage();
+        const bool queryable();
+
+        static const char newline[];
+        static void readByteArray(const std::string& input, std::vector<uint8_t>& out, size_t len);
+
+        static bool isHexString(const std::string& str, size_t bytes);
+        static bool isBaudRate(uint32_t baud);
+
+    protected:
+
+        void setErrorMessage(const char* message);
+        void setErrorMessage(const std::string& message);
+        std::string _help;
+        std::string _usage;
+        bool _queryable;
+        mDot* _dot;
+
+    private:
+
+        const char* _name;
+        const char* _text;
+        const char* _desc;
+        std::string _errorMessage;
+
+};
+
+#endif /*__ command_H */
+
+/************************ (C) COPYRIGHT MultiTech Systems, Inc *****END OF FILE****/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/Commands.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,52 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "Command.h"
+
+#include "CmdAttention.h"
+#include "CmdIdentification.h"
+
+#include "CmdFactoryDefault.h"
+#include "CmdSaveConfig.h"
+#include "CmdDisplayConfig.h"
+#include "CmdFrequencyBand.h"
+#include "CmdDeviceId.h"
+#include "CmdPublicNetwork.h"
+#include "CmdNetworkAddress.h"
+#include "CmdNetworkSessionKey.h"
+#include "CmdDataSessionKey.h"
+#include "CmdNetworkKey.h"
+#include "CmdNetworkId.h"
+#include "CmdNetworkJoinMode.h"
+#include "CmdTxDataRate.h"
+#include "CmdTxPower.h"
+#include "CmdFrequencySubBand.h"
+
+#include "CmdMinimumSize.h"
+#include "CmdMaximumSize.h"
+#include "CmdMinimumPower.h"
+#include "CmdMaximumPower.h"
+#include "CmdData.h"
+#include "CmdGetSurveyDataFile.h"
+#include "CmdDeleteSurveyDataFile.h"
+
+#include "CmdDummy.h"
+
+#ifdef MTS_RADIO_DEBUG_COMMANDS
+#include "CmdWriteProtectedConfig.h"
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FileName.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,24 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __FILENAME_H__
+#define __FILENAME_H__
+
+extern char* file_name;
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/Layout.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,133 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "Layout.h"
+#include "font_6x8.h"
+
+Label::Label(uint8_t col, uint8_t row, std::string value)
+  : _col(col),
+    _row(row),
+    _value(value)
+{}
+
+Field::Field(uint8_t col, uint8_t row, uint8_t maxSize)
+  : _col(col),
+    _row(row),
+    _maxSize(maxSize)
+{}
+
+Image::Image(uint8_t col, uint8_t row, const uint8_t* bmp)
+  : _col(col),
+    _row(row),
+    _bmp(bmp)
+{}
+
+Layout::Layout(DOGS102* lcd) : _lcd(lcd) {}
+
+Layout::~Layout() {}
+
+void Layout::clear() {
+    _lcd->clearBuffer();
+}
+
+void Layout::startUpdate() {
+    _lcd->startUpdate();
+}
+
+void Layout::endUpdate() {
+    _lcd->endUpdate();
+}
+
+bool Layout::writeLabel(const Label& label) {
+    return writeText(label._col, label._row, label._value.c_str(), label._value.size());
+}
+
+bool Layout::writeField(const Field& field, const std::string& value, bool apply) {
+    bool ret;
+    std::string v = value;
+
+    if (apply)
+        startUpdate();
+
+    // fill the whole length with blank space in case the previous value was longer than this one
+    while (v.size() < field._maxSize)
+        v += " ";
+
+    ret = writeText(field._col, field._row, v.c_str(), field._maxSize);
+
+    if (apply)
+        endUpdate();
+
+    return true;
+}
+
+bool Layout::writeField(const Field& field, const char* value, size_t size, bool apply) {
+    bool ret;
+    char buf[32];
+
+    // fill the whole length with blank space in case the previous value was longer than this one
+    memset(buf, ' ', sizeof(buf));
+
+    if (apply)
+        startUpdate();
+
+    snprintf(buf, sizeof(buf), "%s", value);
+    // wipe out the null character - the LCD driver will just skip that character otherwise
+    buf[size] = ' ';
+
+    ret = writeText(field._col, field._row, buf, field._maxSize);
+
+    if (apply)
+        endUpdate();
+
+    return true;
+}
+
+bool Layout::writeImage(const Image& image, bool apply) {
+    bool ret;
+
+    if (apply)
+        startUpdate();
+
+    ret = writeBmp(image._row, image._col, image._bmp);
+
+    if (apply)
+        endUpdate();
+
+    return ret;
+}
+
+void Layout::removeField(const Field& field) {
+    startUpdate();
+    std::string s(' ', field._maxSize);
+    writeText(field._row, field._col, s.c_str(), s.size());
+    endUpdate();
+}
+
+bool Layout::writeText(uint8_t col, uint8_t row, const char* value, size_t size) {
+    _lcd->writeText(col*6, row, font_6x8, value, size);
+
+    return true;
+}
+
+bool Layout::writeBmp(uint8_t col, uint8_t row, const uint8_t* bmp) {
+    _lcd->writeBitmap(col*6, row, bmp);
+
+    return true;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/Layout.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,76 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LAYOUT_H__
+#define __LAYOUT_H__
+
+#include "DOGS102.h"
+#include <string>
+
+class Label {
+    public:
+        Label(uint8_t col, uint8_t row, std::string value);
+
+        uint8_t _col;
+        uint8_t _row;
+        std::string _value;
+};
+
+class Field {
+    public:
+        Field(uint8_t col, uint8_t row, uint8_t maxSize);
+
+        uint8_t _col;
+        uint8_t _row;
+        uint8_t _maxSize;
+};
+
+class Image {
+    public:
+        Image(uint8_t col, uint8_t row, const uint8_t* bmp);
+
+        uint8_t _col;
+        uint8_t _row;
+        const uint8_t* _bmp;
+};
+
+class Layout {
+    public:
+        Layout(DOGS102* lcd);
+        ~Layout();
+
+        virtual void display() = 0;
+        
+    protected:
+        void clear();
+        void startUpdate();
+        void endUpdate();
+        bool writeLabel(const Label& label);
+        bool writeField(const Field& field, const std::string& value, bool apply = false);
+        bool writeField(const Field& field, const char* value, size_t size, bool apply = false);
+        bool writeImage(const Image& image, bool apply = false);
+        void removeField(const Field& field);
+
+    private:
+        bool writeText(uint8_t col, uint8_t row, const char* value, size_t size);
+        bool writeBmp(uint8_t col, uint8_t row, const uint8_t* bmp);
+
+        DOGS102* _lcd;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutConfig.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,91 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "LayoutConfig.h"
+
+LayoutConfig::LayoutConfig(DOGS102* lcd)
+  : Layout(lcd),
+    _lMode(0, 0, "Configuration"),
+    _fHeader(0, 1, 17),
+    _fMsg1(0, 3, 17),
+    _fMsg2(0, 4, 17),
+    _fMsg3(0, 5, 17)
+{
+    _timer.start();
+}
+
+LayoutConfig::~LayoutConfig() {}
+
+void LayoutConfig::display() {
+    clear();
+    startUpdate();
+    writeLabel(_lMode);
+    endUpdate();
+    update1of3();
+}
+
+void LayoutConfig::roll(){
+    if(_timer.read_ms() < _duration){
+        return;
+    }
+    if(_screen == 3){
+        _screen = 1;
+    }
+    else
+        _screen++;
+    
+    switch(_screen){
+        case 1:
+            update1of3();
+            break;
+        case 2:
+            update2of3();
+            break;
+        case 3:
+            update3of3();
+            break;
+    }
+}
+
+void LayoutConfig::update1of3() {
+    _screen = 1;
+    _timer.reset();
+    _duration = 4000;
+    writeField(_fHeader, string("1 of 3"), true);
+    writeField(_fMsg1, string("Connect to MTMDK"), true);
+    writeField(_fMsg2, string("using the 8 pin"), true);
+    writeField(_fMsg3, string("ribbon cable."), true);
+}
+
+void LayoutConfig::update2of3() {
+    _timer.reset();
+    _duration = 3000;
+    writeField(_fHeader, string("2 of 3"), true);
+    writeField(_fMsg1, string("Plug MTMDK into a"), true);
+    writeField(_fMsg2, string("PC."), true);
+    writeField(_fMsg3, string(""), true);
+}
+
+void LayoutConfig::update3of3() {
+    _timer.reset();
+    _duration = 5000;
+    writeField(_fHeader, string("3 of 3"), true);
+    writeField(_fMsg1, string("Run com s/w on"), true);
+    writeField(_fMsg2, string("new TTY/COM at"), true);
+    writeField(_fMsg3, string("115200 bps."), true);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutConfig.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,46 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LAYOUTCONFIG_H__
+#define __LAYOUTCONFIG_H__
+
+#include "Layout.h"
+
+class LayoutConfig : public Layout {
+    public:
+        LayoutConfig(DOGS102* lcd);
+        ~LayoutConfig();
+
+        void display();
+        void roll();
+
+    private:
+        Label _lMode;
+        Field _fHeader;
+        Field _fMsg1;
+        Field _fMsg2;
+        Field _fMsg3;
+		Timer _timer;		
+		uint8_t _screen;
+		uint32_t _duration;
+	    void update1of3();
+	    void update2of3();
+		void update3of3();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutConfirm.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,46 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "LayoutConfirm.h"
+
+LayoutConfirm::LayoutConfirm(DOGS102* lcd)
+  : Layout(lcd),
+    _lMsg1(0, 0, "Are You Sure You"),
+    _lMsg2(0, 1, "Want to Erase It?"),
+    _lIns1(0, 4, "Hold SW1 any time"),
+    _lIns2(0, 5, "for Main Menu"),
+    _lSw1(15, 7, "No"),
+    _lSw2(0, 7, "Yes")
+{}
+
+LayoutConfirm::~LayoutConfirm() {}
+
+void LayoutConfirm::display() {
+    clear();
+    startUpdate();
+
+    writeLabel(_lMsg1);
+    writeLabel(_lMsg2);
+    writeLabel(_lIns1);
+    writeLabel(_lIns2);
+    writeLabel(_lSw1);
+    writeLabel(_lSw2);
+
+    endUpdate();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutConfirm.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,40 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LAYOUTCONFIRM_H__
+#define __LAYOUTCONFIRM_H__
+
+#include "Layout.h"
+
+class LayoutConfirm : public Layout {
+    public:
+        LayoutConfirm(DOGS102* lcd);
+        ~LayoutConfirm();
+
+        void display();
+
+    private:
+        Label _lMsg1;
+        Label _lMsg2;
+        Label _lIns1;
+        Label _lIns2;
+        Label _lSw1;
+        Label _lSw2;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutDemoSampling.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,189 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "LayoutDemoSampling.h"
+
+LayoutDemoSampling::LayoutDemoSampling(DOGS102* lcd)
+  : Layout(lcd),
+    _lAccx(0, 0, "AccX"),
+    _lAccy(6, 0, "AccY"),
+    _lAccz(12, 0, "AccZ"),
+    _lPres(0, 2, "Press="),
+    _lAlt(0, 3, "Alt="),
+    _lTemp(0, 4, "Temp="),
+    _lLight(0, 5, "Light="),
+    _fAccx(0, 1, 5),
+    _fAccy(6, 1, 5),
+    _fAccz(12, 1, 5),
+    _fPres(6, 2, 11),
+    _fAlt(4, 3, 13),
+    _fTemp(5, 4, 12),
+    _fLight(6, 5, 11),
+    _fInfo(0, 6, 17),
+    _fSw1(9, 7, 8),
+    _fSw2(0, 7, 8)
+{}
+
+LayoutDemoSampling::~LayoutDemoSampling() {}
+
+void LayoutDemoSampling::display() {
+    clear();
+    startUpdate();
+
+    writeLabel(_lAccx);
+    writeLabel(_lAccy);
+    writeLabel(_lAccz);
+    writeLabel(_lPres);
+    writeLabel(_lAlt);
+    writeLabel(_lTemp);
+    writeLabel(_lLight);
+
+    endUpdate();
+}
+
+void LayoutDemoSampling::updateInfo(std::string info) {
+    writeField(_fInfo, info, true);
+}
+
+void LayoutDemoSampling::updateSw1(std::string sw1) {
+    writeField(_fSw1, sw1, true);
+}
+
+void LayoutDemoSampling::updateSw2(std::string sw2) {
+    writeField(_fSw2, sw2, true);
+}
+
+void LayoutDemoSampling::updateCountdown(uint32_t seconds) {
+    char buf[32];
+    size_t size;
+    std::string s;
+
+    // make sure the string version is used
+    writeField(_fInfo, string("No Free Channel"), true);
+    size = snprintf(buf, sizeof(buf), "%lu s", seconds);
+    for (int i = 0; i < _fSw1._maxSize - size; i++)
+        s.append(" ");
+    s.append(buf, size);
+    writeField(_fSw1, s, true);
+}
+
+void LayoutDemoSampling::updateInterval(uint32_t seconds) {
+    char buf[32];
+    size_t size;
+
+    if (seconds < 60)
+        size = snprintf(buf, sizeof(buf), "Interval %lu s", seconds);
+    else if (seconds < 60 * 60)
+        size = snprintf(buf, sizeof(buf), "Interval %lu min", seconds / 60);
+    else
+        size = snprintf(buf, sizeof(buf), "Interval %lu hr", seconds / (60 * 60));
+
+    writeField(_fInfo, buf, size, true);
+}
+
+void LayoutDemoSampling::updateAccelerationX(int16_t x) {
+    char buf[16];
+    size_t size;
+    float fx = (float)x;
+    fx /= 1024;
+    // We can only display 5 characters.
+    // For numbers < -1, we display -#.#g. For example -1.3g
+    if(fx < -1){
+        size = snprintf(buf, sizeof(buf), "%4.1fg", fx);
+    }
+    // For numbers > -1 and < 0, we display -.##g. For example -.13g
+    else if(fx < 0){
+        size = snprintf(buf, sizeof(buf), "%4.2fg", fx);
+        for(uint8_t i = 1; i < 5; i++ ){
+            buf[i] = buf[i+1];
+        }
+    }
+    // For numbers > 0, we display #.##g. For example 0.13g.
+    else{
+        size = snprintf(buf, sizeof(buf), "%4.2fg", fx);
+    }
+    writeField(_fAccx, buf, size, true);
+}
+    
+void LayoutDemoSampling::updateAccelerationY(int16_t y) {
+    char buf[16];
+    size_t size;
+    float fy = (float)y;
+    fy /= 1024;
+    if(fy < -1){
+        size = snprintf(buf, sizeof(buf), "%4.1fg", fy);
+    }
+    else if(fy < 0){
+        size = snprintf(buf, sizeof(buf), "%4.2fg", fy);
+        for(uint8_t i = 1; i < 5; i++ ){
+            buf[i] = buf[i+1];
+        }
+    }
+    else{
+        size = snprintf(buf, sizeof(buf), "%4.2fg", fy);
+    }
+    writeField(_fAccy, buf, size, true);
+}
+    
+void LayoutDemoSampling::updateAccelerationZ(int16_t z) {
+    char buf[16];
+    size_t size;
+    float fz = (float)z;
+    fz /= 1024;
+    if(fz < -1){
+        size = snprintf(buf, sizeof(buf), "%1.1fg", fz);
+    }
+    else if(fz < 0){
+        size = snprintf(buf, sizeof(buf), "%4.2fg", fz);
+        for(uint8_t i = 1; i < 5; i++ ){
+            buf[i] = buf[i+1];
+        }
+    }
+    else{
+        size = snprintf(buf, sizeof(buf), "%1.2fg", fz);
+    }
+    writeField(_fAccz, buf, size, true);
+}
+
+void LayoutDemoSampling::updatePressure(float pressure) {
+    char buf[16];
+    size_t size;
+    size = snprintf(buf, sizeof(buf), "%3.2f kPa", pressure/1000);    
+    writeField(_fPres, buf, size, true);
+}
+
+void LayoutDemoSampling::updateAltitude(float altitude) {
+    char buf[16];
+    size_t size;
+    size = snprintf(buf, sizeof(buf), "%5.2f m", altitude);    
+    writeField(_fAlt, buf, size, true);
+}
+
+void LayoutDemoSampling::updateTemperature(float temperature) {
+    char buf[16];
+    size_t size;
+    size = snprintf(buf, sizeof(buf), "%3.2f C", temperature);    
+    writeField(_fTemp, buf, size, true);
+}
+
+void LayoutDemoSampling::updateLight(float light) {
+    char buf[16];
+    size_t size;
+    size = snprintf(buf, sizeof(buf), "%4.2f lx", light);
+    writeField(_fLight, buf, size, true);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutDemoSampling.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,65 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LAYOUTDEMOSAMPLING_H__
+#define __LAYOUTDEMOSAMPLING_H__
+
+#include "Layout.h"
+#include "MMA845x.h"
+
+class LayoutDemoSampling : public Layout {
+    public:
+        LayoutDemoSampling(DOGS102* lcd);
+        ~LayoutDemoSampling();
+
+        void display();
+        void updateInfo(std::string info);
+        void updateSw1(std::string sw1);
+        void updateSw2(std::string sw2);
+        void updateCountdown(uint32_t seconds);
+        void updateInterval(uint32_t seconds);
+		void updateAccelerationX(int16_t x);
+		void updateAccelerationY(int16_t y);
+		void updateAccelerationZ(int16_t z);
+		void updatePressure(float pressure);
+		void updateAltitude(float altitude);
+		void updateTemperature(float temperature);
+		void updateLight(float light);
+
+    private:
+        Label _lAccx;
+        Label _lAccy;
+        Label _lAccz;
+        Label _lPres;
+        Label _lAlt;
+        Label _lTemp;
+        Label _lLight;
+        
+        Field _fAccx;
+        Field _fAccy;
+        Field _fAccz;
+        Field _fPres;
+        Field _fAlt;
+        Field _fTemp;
+        Field _fLight;
+        Field _fInfo;
+        Field _fSw1;
+        Field _fSw2;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutFile.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,48 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "LayoutFile.h"
+
+LayoutFile::LayoutFile(DOGS102* lcd)
+  : Layout(lcd),
+    _lMsg1(0, 0, "Erase or Append"),
+    _lMsg2(0, 1, "to Existing"),
+    _lMsg3(0, 2, "Survey Data File?"),
+    _lIns1(0, 4, "Hold SW1 any time"),
+    _lIns2(0, 5, "for Main Menu"),
+    _lSw1(11, 7, "Append"),
+    _lSw2(0, 7, "Erase")
+{}
+
+LayoutFile::~LayoutFile() {}
+
+void LayoutFile::display() {
+    clear();
+    startUpdate();
+
+    writeLabel(_lMsg1);
+    writeLabel(_lMsg2);
+    writeLabel(_lMsg3);
+    writeLabel(_lIns1);
+    writeLabel(_lIns2);
+    writeLabel(_lSw1);
+    writeLabel(_lSw2);
+
+    endUpdate();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutFile.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,41 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LAYOUTFILE_H__
+#define __LAYOUTFILE_H__
+
+#include "Layout.h"
+
+class LayoutFile : public Layout {
+    public:
+        LayoutFile(DOGS102* lcd);
+        ~LayoutFile();
+
+        void display();
+
+    private:
+        Label _lMsg1;
+        Label _lMsg2;
+        Label _lMsg3;
+        Label _lIns1;
+        Label _lIns2;
+        Label _lSw1;
+        Label _lSw2;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutHelp.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,63 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "LayoutHelp.h"
+
+LayoutHelp::LayoutHelp(DOGS102* lcd)
+  : Layout(lcd),
+    _lIns1(0, 4, "Hold SW1 any time"),
+    _lIns2(0, 5, "for Main Menu"),
+    _fMode(0, 0, 17),
+    _fDesc(0, 1, 17),
+    _fMsg(0, 6, 17),
+    _fSw1(9, 7, 8),
+    _fSw2(0, 7, 8)
+{}
+
+LayoutHelp::~LayoutHelp() {}
+
+void LayoutHelp::display() {
+    clear();
+    startUpdate();
+
+    writeLabel(_lIns1);
+    writeLabel(_lIns2);
+
+    endUpdate();
+}
+
+void LayoutHelp::updateMode(std::string mode) {
+    writeField(_fMode, mode, true);
+}
+
+void LayoutHelp::updateDescription(std::string description) {
+    writeField(_fDesc, description, true);
+}
+
+void LayoutHelp::updateMsg(std::string msg) {
+    writeField(_fMsg, msg, true);
+}
+
+void LayoutHelp::updateSw1(std::string s) {
+    writeField(_fSw1, s, true);
+}
+
+void LayoutHelp::updateSw2(std::string s) {
+    writeField(_fSw2, s, true);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutHelp.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,48 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LAYOUTHELP_H__
+#define __LAYOUTHELP_H__
+
+#include "Layout.h"
+
+class LayoutHelp : public Layout {
+    public:
+        LayoutHelp(DOGS102* lcd);
+        ~LayoutHelp();
+
+        void display();
+        void updateMode(std::string mode);
+        void updateDescription(std::string description);
+        void updateMsg(std::string msg);
+        void updateSw1(std::string s);
+        void updateSw2(std::string s);
+
+    private:
+        Label _lIns1;
+        Label _lIns2;
+
+        Field _fMode;
+        Field _fDesc;
+        Field _fMsg;
+        Field _fSw1;
+        Field _fSw2;
+
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutJoin.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,121 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "LayoutJoin.h"
+
+LayoutJoin::LayoutJoin(DOGS102* lcd, uint8_t band)
+  : Layout(lcd),
+    _lId(0, 1, "NI="),
+    _lKey(0, 2, "NK="),
+    _lFsb(0, 3, "FSB="),
+    _lRate(0, 5, "DR="),
+    _lPower(6, 5, "P="),
+    _lAttempt(11, 5, "A="),
+    _fStatus(0, 0, 17),
+    _fId(3, 1, 14),
+    _fKey(3, 2, 14),
+    _fFsb(4, 3, 2),
+    _fRate(3, 5, 2),
+    _fPower(8, 5, 2),
+    _fAttempt(13, 5, 4),
+    _fCountdown(0, 7, 9),
+    _fCountdownLabel(0, 6, 17),
+    _fCancel(11, 7, 6),
+    _band(band)
+{}
+
+LayoutJoin::~LayoutJoin() {}
+
+void LayoutJoin::display() {
+    clear();
+    startUpdate();
+
+    writeLabel(_lId);
+    writeLabel(_lKey);
+    if (_band == mDot::FB_915) {
+        writeLabel(_lFsb);
+    }
+    writeLabel(_lRate);
+    writeLabel(_lPower);
+    writeLabel(_lAttempt);
+
+    displayCancel();
+    
+    endUpdate();
+}
+
+void LayoutJoin::updateId(std::string id) {
+    writeField(_fId, id, true);
+}
+
+void LayoutJoin::updateKey(std::string key) {
+    writeField(_fKey, key, true);
+}
+
+void LayoutJoin::updateFsb(uint8_t band) {
+    char buf[8];
+    size_t size;
+
+    size = snprintf(buf, sizeof(buf), "%u", band);
+    writeField(_fFsb, buf, size, true);
+}
+
+void LayoutJoin::updateRate(std::string rate) {
+    writeField(_fRate, rate, true);
+}
+
+void LayoutJoin::updatePower(uint32_t power) {
+    char buf[16];
+    size_t size;
+
+    size = snprintf(buf, sizeof(buf), "%lu", power);
+    writeField(_fPower, buf, size, true);
+}
+
+void LayoutJoin::updateAttempt(uint32_t attempt) {
+    char buf[16];
+    size_t size;
+
+    size = snprintf(buf, sizeof(buf), "%lu", attempt);
+    writeField(_fAttempt, buf, size, true);
+}
+
+void LayoutJoin::updateStatus(std::string status) {
+    writeField(_fStatus, status, true);
+}
+
+void LayoutJoin::updateCountdown(uint32_t seconds) {
+    char buf[16];
+    size_t size;
+
+    // make sure the string version is used
+    writeField(_fCountdownLabel, string("No Free Channel"), true);
+    size = snprintf(buf, sizeof(buf), "%lu s", seconds);
+    writeField(_fCountdown, buf, size, true);
+}
+
+void LayoutJoin::displayCancel(bool display) {
+    std::string str;
+    if (display)
+        str = "Cancel";
+    else
+        str = string(17, ' ');
+
+    writeField(_fCancel, str, true);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutJoin.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,63 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LAYOUTJOIN_H__
+#define __LAYOUTJOIN_H__
+
+#include "Layout.h"
+#include "mDot.h"
+
+class LayoutJoin : public Layout {
+    public:
+        LayoutJoin(DOGS102* lcd, uint8_t band);
+        ~LayoutJoin();
+
+        void display();
+
+        void updateId(std::string id);
+        void updateKey(std::string key);
+        void updateFsb(uint8_t band);
+        void updateRate(std::string rate);
+        void updatePower(uint32_t power);
+        void updateAttempt(uint32_t attempt);
+        void updateStatus(std::string status);
+        void updateCountdown(uint32_t seconds);
+        void displayCancel(bool display = true);
+
+    private:
+        Label _lId;
+        Label _lKey;
+        Label _lFsb;
+        Label _lRate;
+        Label _lPower;
+        Label _lAttempt;
+
+        Field _fStatus;
+        Field _fId;
+        Field _fKey;
+        Field _fFsb;
+        Field _fRate;
+        Field _fPower;
+        Field _fAttempt;
+        Field _fCountdown;
+        Field _fCountdownLabel;
+        Field _fCancel;
+        uint8_t _band;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutScrollSelect.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,262 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "LayoutScrollSelect.h"
+#include "MTSLog.h"
+
+LayoutScrollSelect::LayoutScrollSelect(DOGS102* lcd, Items items, std::string info1, std::string info2)
+  : Layout(lcd),
+    _lSw1(0, 7, "Scroll"),
+    _lSw2(11, 7, "Select"),
+    _lInfo1(0, 0, info1),
+    _lInfo2(0, 1, info2),
+    _lCursor(0, 4, "=>"),
+    _fItem1(3, 2, 14),
+    _fItem2(3, 3, 14),
+    _fItem3(3, 4, 14),
+    _fItem4(3, 5, 14),
+    _fItem5(3, 6, 14),
+    _items(items)
+{
+    _size = _items.size();
+    _selected = 0;
+}
+
+LayoutScrollSelect::~LayoutScrollSelect() {}
+
+void LayoutScrollSelect::display() {
+    clear();
+    startUpdate();
+
+    writeLabel(_lSw1);
+    writeLabel(_lSw2);
+    writeLabel(_lInfo1);
+    writeLabel(_lInfo2);
+    writeLabel(_lCursor);
+
+    switch (_size) {
+        case 0:
+            // special case - no items
+            //    (empty)
+            //    (empty)
+            // => (empty)
+            //    (empty)
+            //    (empty)
+            break;
+
+        case 1:
+            // special case - 1 item
+            //    (empty)
+            //    (empty)
+            // => item1
+            //    (empty)
+            //    (empty)
+            writeField(_fItem3, _items[0]);
+            break;
+
+        case 2:
+            // special case - 2 items
+            //    (empty)
+            //    (empty)
+            // => item1
+            //    item2
+            //    (empty)
+            writeField(_fItem3, _items[0]);
+            writeField(_fItem4, _items[1]);
+            break;
+
+        case 3:
+            // special case - 3 items
+            //    (empty)
+            //    item3
+            // => item1
+            //    item2
+            //    (empty)
+            writeField(_fItem2, _items[2]);
+            writeField(_fItem3, _items[0]);
+            writeField(_fItem4, _items[1]);
+            break;
+
+        case 4:
+            // special case - 4 items
+            //    item3
+            //    item4
+            // => item1
+            //    item2
+            //    (empty)
+            writeField(_fItem1, _items[2]);
+            writeField(_fItem2, _items[3]);
+            writeField(_fItem3, _items[0]);
+            writeField(_fItem4, _items[1]);
+            break;
+
+        default:
+            // this is the generic case - should handle lists of 5+ items correctly
+            //    item4         item6           item9
+            //    item5         item7           item10
+            // => item1      => item1        => item1
+            //    item2         item2           item2
+            //    item3         item3           item3
+            writeField(_fItem1, _items[_size - 2]);
+            writeField(_fItem2, _items[_size - 1]);
+            writeField(_fItem3, _items[0]);
+            writeField(_fItem4, _items[1]);
+            writeField(_fItem5, _items[2]);
+            break;
+    }
+
+    endUpdate();
+}
+
+void LayoutScrollSelect::scroll() {
+    size_t index;
+
+    switch (_size) {
+        case 0:
+        case 1:
+            // nothing to scroll
+            break;
+
+        case 2:
+            // special case - 2 items
+            //    (empty)  ->     (empty)
+            //    (empty)  ->     (empty)
+            // => item1    ->  => item2
+            //    item2    ->     item1
+            //    (empty)  ->     (empty)
+
+            index = _selected;
+            // keep selected item up to date
+            increment(_selected);
+
+            startUpdate();
+            // previously selected item moves down to field4
+            writeField(_fItem4, _items[index]);
+            increment(index);
+            // other item moves up to field3
+            writeField(_fItem3, _items[index]);
+            endUpdate();
+            break;
+
+        case 3:
+            // special case - 3 items
+            //    (empty)  ->     (empty)
+            //    item3    ->     item1  
+            // => item1    ->  => item2
+            //    item2    ->     item3
+            //    (empty)  ->     (empty)
+            
+            index = _selected;
+            // keep selected item up to date
+            increment(_selected);
+
+            startUpdate();
+            // previously selected item moves up to field2
+            writeField(_fItem2, _items[index]);
+            increment(index);
+            // new selected item moves up to field3
+            writeField(_fItem3, _items[index]);
+            increment(index);
+            // item from field2 moves down to field4
+            writeField(_fItem4, _items[index]);
+            endUpdate();
+            break;
+
+        case 4:
+            // special case - 4 items
+            //    item3    ->     item4  
+            //    item4    ->     item1  
+            // => item1    ->  => item2
+            //    item2    ->     item3
+            //    (empty)  ->     (empty)
+            
+            index = _selected;
+            // keep selected item up to date
+            increment(_selected);
+
+            startUpdate();
+            // previously selected item moves up to field2
+            writeField(_fItem2, _items[index]);
+            increment(index);
+            // new selected item moves up to field3
+            writeField(_fItem3, _items[index]);
+            increment(index);
+            // item from field1 moves down to field4
+            writeField(_fItem4, _items[index]);
+            increment(index);
+            // item from field2 moves up to field1
+            writeField(_fItem1, _items[index]);
+            endUpdate();
+            break;
+
+        default:
+            // this is the generic case - should handle lists of 5+ items correctly
+            //    item4    ->     item5           item6    ->     item7
+            //    item5    ->     item1           item7    ->     item1
+            // => item1    ->  => item2        => item1    ->  => item2
+            //    item2    ->     item3           item2    ->     item3
+            //    item3    ->     item4           item3    ->     item4
+            
+            index = _selected;
+            // keep selected item up to date
+            increment(_selected);
+
+            startUpdate();
+            decrement(index);
+            // item from field2 moves up to field1
+            writeField(_fItem1, _items[index]);
+            increment(index);
+            // previously selected item moves up to field2
+            writeField(_fItem2, _items[index]);
+            increment(index);
+            // new selected item moves up to field3
+            writeField(_fItem3, _items[index]);
+            increment(index);
+            // item from field5 moves up to field4
+            writeField(_fItem4, _items[index]);
+            increment(index);
+            // next item (from field1 or off screen) moves up to field5
+            writeField(_fItem5, _items[index]);
+            endUpdate();
+            break;
+      }
+}
+
+std::string LayoutScrollSelect::select() {
+    std::string selected = "";
+    if (_size > 0)
+        selected = _items[_selected];
+
+    return selected;
+}
+
+void LayoutScrollSelect::increment(size_t& index) {
+    if (_size > 1) {
+        index++;
+        index %= _size;
+    }
+}
+
+void LayoutScrollSelect::decrement(size_t& index) {
+    if (_size > 1) {
+        if (index == 0)
+            index = _size - 1;
+        else
+            index--;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutScrollSelect.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,58 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LAYOUTSCROLLSELECT_H__
+#define __LAYOUTSCROLLSELECT_H__
+
+#include "Layout.h"
+#include <vector>
+
+typedef std::vector<std::string> Items;
+
+class LayoutScrollSelect : public Layout {
+    public:
+        LayoutScrollSelect(DOGS102* lcd, Items items, std::string info1 = "", std::string info2 = "");
+        ~LayoutScrollSelect();
+
+        void display();
+
+        void scroll();
+        std::string select();
+
+    private:
+        void increment(size_t& index);
+        void decrement(size_t& index);
+
+        Label _lSw1;
+        Label _lSw2;
+        Label _lInfo1;
+        Label _lInfo2;
+        Label _lCursor;
+
+        Field _fItem1;
+        Field _fItem2;
+        Field _fItem3;
+        Field _fItem4;
+        Field _fItem5;
+
+        Items _items;
+        size_t _selected;
+        size_t _size;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutStartup.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,64 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "LayoutStartup.h"
+#include "MultiTech_Logo.h"
+#include "version.h"
+#include "MTSText.h"
+
+LayoutStartup::LayoutStartup(DOGS102* lcd, mDot* dot)
+  : Layout(lcd),
+    _dot(dot),
+    _lName(0, 3, "MTDOT-BOX/EVB"),
+    _lInfo(0, 4, "Factory Firmware"),
+    _lVersion(0, 5, "Version"),
+    _fName(14, 3, 3),
+    _fVersion(8, 5, 9),
+    _fId(0, 7, 17),
+    _fGps(0, 6, 17),
+    _iLogo(0, 0, MultiTech_Logo)
+{}
+
+LayoutStartup::~LayoutStartup() {}
+
+void LayoutStartup::display() {
+    std::string version = MTDOT_BOX_VERSION;
+    std::string id = mts::Text::bin2hexString(_dot->getDeviceId());
+
+    clear();
+    startUpdate();
+
+    writeImage(_iLogo);
+    writeLabel(_lName);
+    writeLabel(_lInfo);
+    writeLabel(_lVersion);
+    writeField(_fName, mDot::FrequencyBandStr(_dot->getFrequencyBand()).substr(3));
+    writeField(_fVersion, version);
+    writeField(_fId, id);
+
+    endUpdate();
+}
+
+void LayoutStartup::updateGPS(bool gps) {
+    char buf[32];
+    size_t size;
+
+    size = snprintf(buf, sizeof(buf), "%sGPS Detected", gps ? "" : "No ");
+    writeField(_fGps, buf, size);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutStartup.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,48 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LAYOUTSTARTUP_H__
+#define __LAYOUTSTARTUP_H__
+
+#include "Layout.h"
+#include "mDot.h"
+
+class LayoutStartup : public Layout {
+    public:
+        LayoutStartup(DOGS102* lcd, mDot* dot);
+        ~LayoutStartup();
+
+        void display();
+        void updateGPS(bool gps);
+
+    private:
+        mDot* _dot;
+
+        Label _lName;
+        Label _lInfo;
+        Label _lVersion;
+
+        Field _fName;
+        Field _fVersion;
+        Field _fGps;
+        Field _fId;
+
+        Image _iLogo;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutSurveyFailure.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,134 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "LayoutSurveyFailure.h"
+
+LayoutSurveyFailure::LayoutSurveyFailure(DOGS102* lcd)
+  : Layout(lcd),
+    _lTitle(0, 1, "Survey Failed"),
+    _lId(0, 0, "ID"),
+    _lDr(8, 0, "DR"),
+    _lPwr(13, 0, "P"),
+    _fId(2, 0, 5),
+    _fDr(10, 0, 2),
+    _fPwr(14, 0, 2),
+    _fGpsLat(0, 4, 17),
+    _fGpsLon(0, 3, 17),
+    _fGpsTime(0, 5, 17),
+    _fInfo(0, 6, 17),
+    _fSw1(9, 7, 8),
+    _fSw2(0, 7, 8)
+{}
+
+LayoutSurveyFailure::~LayoutSurveyFailure() {}
+
+void LayoutSurveyFailure::display() {
+    clear();
+    startUpdate();
+
+    writeLabel(_lTitle);
+    writeLabel(_lId);
+    writeLabel(_lDr);
+    writeLabel(_lPwr);
+
+    endUpdate();
+}
+
+void LayoutSurveyFailure::updateId(uint32_t id) {
+    char buf[16];
+    size_t size;
+
+    size = snprintf(buf, sizeof(buf), "%lu", id);
+    writeField(_fId, buf, size, true);
+}
+
+void LayoutSurveyFailure::updateRate(std::string rate) {
+    writeField(_fDr, rate, true);
+}
+
+void LayoutSurveyFailure::updatePower(uint32_t power) {
+    char buf[16];
+    size_t size;
+
+    size = snprintf(buf, sizeof(buf), "%lu", power);
+    writeField(_fPwr, buf, size, true);
+}
+
+void LayoutSurveyFailure::updateGpsLatitude(GPSPARSER::latitude lat) {
+    char buf[32];
+    size_t size;
+
+    size = snprintf(buf, sizeof(buf), "%d %d %d.%03d %c",
+        abs(lat.degrees),
+        lat.minutes,
+        (lat.seconds * 6) / 1000,
+        (lat.seconds * 6) % 1000,
+        (lat.degrees > 0) ? 'N' : 'S');
+    writeField(_fGpsLat, buf, size, true);
+}
+
+void LayoutSurveyFailure::updateGpsLatitude(std::string msg) {
+    writeField(_fGpsLat, msg, true);
+}
+
+void LayoutSurveyFailure::updateGpsLongitude(GPSPARSER::longitude lon) {
+    char buf[32];
+    size_t size;
+
+    size = snprintf(buf, sizeof(buf), "%d %d %d.%03d %c",
+        abs(lon.degrees),
+        lon.minutes,
+        (lon.seconds * 6) / 1000,
+        (lon.seconds * 6) % 1000,
+        (lon.degrees > 0) ? 'E' : 'W');
+    writeField(_fGpsLon, buf, size, true);
+}
+
+void LayoutSurveyFailure::updateGpsTime(struct tm time) {
+    char buf[32];
+    size_t size;
+
+    size = snprintf(buf, sizeof(buf), "%02d:%02d %02d/%02d/%04d",
+        time.tm_hour,
+        time.tm_min,
+        time.tm_mon + 1,
+        time.tm_mday,
+        time.tm_year + 1900);
+    writeField(_fGpsTime, buf, size, true);
+}
+
+void LayoutSurveyFailure::updateInfo(std::string info) {
+    writeField(_fInfo, info, true);
+}
+
+void LayoutSurveyFailure::updateSw1(std::string sw1) {
+    writeField(_fSw1, sw1, true);
+}
+
+void LayoutSurveyFailure::updateSw2(std::string sw2) {
+    writeField(_fSw2, sw2, true);
+}
+
+void LayoutSurveyFailure::updatePassFail(uint8_t pass, uint8_t fail) {
+    char buf[32];
+    size_t size;
+
+    size = snprintf(buf, sizeof(buf), "Pass %u Fail %u", pass, fail);
+    writeField(_fGpsTime, buf, size, true);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutSurveyFailure.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,60 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LAYOUTSURVEYFAILURE_H__
+#define __LAYOUTSURVEYFAILURE_H__
+
+#include "Layout.h"
+#include "GPSPARSER.h"
+
+class LayoutSurveyFailure : public Layout {
+    public:
+        LayoutSurveyFailure(DOGS102* lcd);
+        ~LayoutSurveyFailure();
+
+        void display();
+        void updateId(uint32_t id);
+        void updateRate(std::string rate);
+        void updatePower(uint32_t power);
+        void updateGpsLatitude(GPSPARSER::latitude lat);
+        void updateGpsLatitude(std::string msg);
+        void updateGpsLongitude(GPSPARSER::longitude lon);
+        void updateGpsTime(struct tm time);
+        void updateInfo(std::string info);
+        void updateSw1(std::string sw1);
+        void updateSw2(std::string sw2);
+        void updatePassFail(uint8_t pass, uint8_t fail);
+
+    private:
+        Label _lTitle;
+        Label _lId;
+        Label _lDr;
+        Label _lPwr;
+
+        Field _fId;
+        Field _fDr;
+        Field _fPwr;
+        Field _fGpsLat;
+        Field _fGpsLon;
+        Field _fGpsTime;
+        Field _fInfo;
+        Field _fSw1;
+        Field _fSw2;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutSurveyProgress.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,52 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "LayoutSurveyProgress.h"
+
+LayoutSurveyProgress::LayoutSurveyProgress(DOGS102* lcd)
+  : Layout(lcd),
+    _lMsg1(5, 2, "Survey"),
+    _lMsg2(7, 3, "in"),
+    _lMsg3(4, 4, "Progress"),
+    _fCountdownLabel(0, 6, 17),
+    _fCountdown(0, 7, 9)
+{}
+
+LayoutSurveyProgress::~LayoutSurveyProgress() {}
+
+void LayoutSurveyProgress::display() {
+    clear();
+    startUpdate();
+
+    writeLabel(_lMsg1);
+    writeLabel(_lMsg2);
+    writeLabel(_lMsg3);
+
+    endUpdate();
+}
+
+void LayoutSurveyProgress::updateCountdown(uint32_t seconds) {
+    char buf[16];
+    size_t size;
+
+    // make sure the string version is used
+    writeField(_fCountdownLabel, string("No Free Channel"), true);
+    size = snprintf(buf, sizeof(buf), "%lu s", seconds);
+    writeField(_fCountdown, buf, size, true);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutSurveyProgress.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,42 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LAYOUTSURVEYPROGRESS_H__
+#define __LAYOUTSURVEYPROGRESS_H__
+
+#include "Layout.h"
+
+class LayoutSurveyProgress : public Layout {
+    public:
+        LayoutSurveyProgress(DOGS102* lcd);
+        ~LayoutSurveyProgress();
+
+        void display();
+
+        void updateCountdown(uint32_t seconds);
+
+    private:
+        Label _lMsg1;
+        Label _lMsg2;
+        Label _lMsg3;
+
+        Field _fCountdownLabel;
+        Field _fCountdown;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutSurveySuccess.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,170 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "LayoutSurveySuccess.h"
+#include "MTSLog.h"
+
+LayoutSurveySuccess::LayoutSurveySuccess(DOGS102* lcd)
+  : Layout(lcd),
+    _lId(0, 0, "ID"),
+    _lDr(8, 0, "DR"),
+    _lPwr(13, 0, "P"),
+    _lUp(0, 1, "UP Margin"),
+    _lDown(0, 2, "DWN"),
+    _fId(2, 0, 5),
+    _fDr(10, 0, 2),
+    _fPwr(14, 0, 2),
+    _fUpMargin(10, 1, 5),
+    _fDownRssi(4, 2, 7),
+    _fDownSnr(12, 2, 5),
+    _fGpsLat(0, 4, 17),
+    _fGpsLon(0, 3, 17),
+    _fGpsTime(0, 5, 17),
+    _fInfo(0, 6, 17),
+    _fSw1(9, 7, 8),
+    _fSw2(0, 7, 8)
+{}
+
+LayoutSurveySuccess::~LayoutSurveySuccess() {}
+
+void LayoutSurveySuccess::display() {
+    clear();
+    startUpdate();
+
+    writeLabel(_lId);
+    writeLabel(_lDr);
+    writeLabel(_lPwr);
+    writeLabel(_lUp);
+    writeLabel(_lDown);
+
+    endUpdate();
+}
+
+void LayoutSurveySuccess::updateId(uint32_t id) {
+    char buf[16];
+    size_t size;
+
+    size = snprintf(buf, sizeof(buf), "%lu", id);
+    writeField(_fId, buf, size, true);
+}
+
+void LayoutSurveySuccess::updateRate(std::string rate) {
+    writeField(_fDr, rate, true);
+}
+
+void LayoutSurveySuccess::updatePower(uint32_t power) {
+    char buf[16];
+    size_t size;
+
+    size = snprintf(buf, sizeof(buf), "%lu", power);
+    writeField(_fPwr, buf, size, true);
+}
+
+void LayoutSurveySuccess::updateStats(LoRaHandler::LoRaLink link) {
+    char buf[16];
+    size_t size;
+
+    startUpdate();
+
+    size = snprintf(buf, sizeof(buf), "%d", link.up.dBm);
+    writeField(_fUpMargin, buf, size);
+
+    memset(buf, 0, sizeof(buf));
+    size = snprintf(buf, sizeof(buf), "%3d dbm", link.down.rssi);
+    writeField(_fDownRssi, buf, size);
+
+    memset(buf, 0, sizeof(buf));
+    size = snprintf(buf, sizeof(buf), "%2.1f", (float)link.down.snr / 10.0);
+    writeField(_fDownSnr, buf, size);
+
+    endUpdate();
+}
+
+void LayoutSurveySuccess::updateGpsLatitude(GPSPARSER::latitude lat) {
+    char buf[32];
+    size_t size;
+
+    size = snprintf(buf, sizeof(buf), "%d %d %d.%03d %c",
+        abs(lat.degrees),
+        lat.minutes,
+        (lat.seconds * 6) / 1000,
+        (lat.seconds * 6) % 1000,
+        (lat.degrees > 0) ? 'N' : 'S');
+    writeField(_fGpsLat, buf, size, true);
+}
+
+void LayoutSurveySuccess::updateGpsLatitude(std::string msg) {
+    writeField(_fGpsLat, msg, true);
+}
+
+void LayoutSurveySuccess::updateGpsLongitude(GPSPARSER::longitude lon) {
+    char buf[32];
+    size_t size;
+
+    size = snprintf(buf, sizeof(buf), "%d %d %d.%03d %c",
+        abs(lon.degrees),
+        lon.minutes,
+        (lon.seconds * 6) / 1000,
+        (lon.seconds * 6) % 1000,
+        (lon.degrees > 0) ? 'E' : 'W');
+    writeField(_fGpsLon, buf, size, true);
+}
+
+void LayoutSurveySuccess::updateGpsTime(struct tm time) {
+    char buf[32];
+    size_t size;
+
+    size = snprintf(buf, sizeof(buf), "%02d:%02d %02d/%02d/%04d",
+        time.tm_hour,
+        time.tm_min,
+        time.tm_mon + 1,
+        time.tm_mday,
+        time.tm_year + 1900);
+    writeField(_fGpsTime, buf, size, true);
+}
+
+void LayoutSurveySuccess::updateInfo(std::string info) {
+    writeField(_fInfo, info, true);
+}
+
+void LayoutSurveySuccess::updateSw1(std::string sw1) {
+    writeField(_fSw1, sw1, true);
+}
+
+void LayoutSurveySuccess::updateSw2(std::string sw2) {
+    writeField(_fSw2, sw2, true);
+}
+
+void LayoutSurveySuccess::updateCountdown(uint32_t seconds) {
+    char buf[32];
+    size_t size;
+
+    // make sure the string version is used
+    writeField(_fInfo, string("No Free Channel"), true);
+    size = snprintf(buf, sizeof(buf), "%lu s", seconds);
+    writeField(_fSw2, buf, size, true);
+}
+
+void LayoutSurveySuccess::updatePassFail(uint8_t pass, uint8_t fail) {
+    char buf[32];
+    size_t size;
+
+    size = snprintf(buf, sizeof(buf), "Pass %u Fail %u", pass, fail);
+    writeField(_fGpsTime, buf, size, true);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutSurveySuccess.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,67 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LAYOUTSURVEYSUCCESS_H__
+#define __LAYOUTSURVEYSUCCESS_H__
+
+#include "Layout.h"
+#include "LoRaHandler.h"
+#include "GPSPARSER.h"
+
+class LayoutSurveySuccess : public Layout {
+    public:
+        LayoutSurveySuccess(DOGS102* lcd);
+        ~LayoutSurveySuccess();
+
+        void display();
+        void updateId(uint32_t id);
+        void updateRate(std::string rate);
+        void updatePower(uint32_t power);
+        void updateStats(LoRaHandler::LoRaLink link);
+        void updateGpsLatitude(GPSPARSER::latitude lat);
+        void updateGpsLatitude(std::string msg);
+        void updateGpsLongitude(GPSPARSER::longitude lon);
+        void updateGpsTime(struct tm time);
+        void updateInfo(std::string info);
+        void updateSw1(std::string sw1);
+        void updateSw2(std::string sw2);
+        void updateCountdown(uint32_t seconds);
+        void updatePassFail(uint8_t pass, uint8_t fail);
+
+    private:
+        Label _lId;
+        Label _lDr;
+        Label _lPwr;
+        Label _lUp;
+        Label _lDown;
+        
+        Field _fId;
+        Field _fDr;
+        Field _fPwr;
+        Field _fUpMargin;
+        Field _fDownRssi;
+        Field _fDownSnr;
+        Field _fGpsLat;
+        Field _fGpsLon;
+        Field _fGpsTime;
+        Field _fInfo;
+        Field _fSw1;
+        Field _fSw2;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutSweepComplete.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,71 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "LayoutSweepComplete.h"
+
+LayoutSweepComplete::LayoutSweepComplete(DOGS102* lcd)
+  : Layout(lcd),
+    _lId(0, 0, "ID"),
+    _lInfo(0, 1, "Sweep Finished"),
+    _lPass(0, 5, "Pass"),
+    _lFail(9, 5, "Fail"),
+    _lSw2(0, 7, "Sweep"),
+    _fId(2, 0, 5),
+    _fPass(5, 5, 2),
+    _fFail(14, 5, 2)
+{}
+
+LayoutSweepComplete::~LayoutSweepComplete() {}
+
+void LayoutSweepComplete::display() {
+    clear();
+    startUpdate();
+
+    writeLabel(_lId);
+    writeLabel(_lInfo);
+    writeLabel(_lPass);
+    writeLabel(_lFail);
+    writeLabel(_lSw2);
+
+    endUpdate();
+}
+
+void LayoutSweepComplete::updateId(uint32_t id) {
+    char buf[16];
+    size_t size;
+
+    size = snprintf(buf, sizeof(buf), "%lu", id);
+    writeField(_fId, buf, size, true);
+}
+
+void LayoutSweepComplete::updatePass(uint8_t pass) {
+    char buf[8];
+    size_t size;
+
+    size = snprintf(buf, sizeof(buf), "%u", pass);
+    writeField(_fPass, buf, size, true);
+}
+
+void LayoutSweepComplete::updateFail(uint8_t fail) {
+    char buf[8];
+    size_t size;
+
+    size = snprintf(buf, sizeof(buf), "%u", fail);
+    writeField(_fFail, buf, size, true);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutSweepComplete.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,46 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LAYOUTSWEEPCOMPLETE_H__
+#define __LAYOUTSWEEPCOMPLETE_H__
+
+#include "Layout.h"
+
+class LayoutSweepComplete : public Layout {
+    public:
+        LayoutSweepComplete(DOGS102* lcd);
+        ~LayoutSweepComplete();
+
+        void display();
+        void updateId(uint32_t id);
+        void updatePass(uint8_t pass);
+        void updateFail(uint8_t fail);
+
+    private:
+        Label _lId;
+        Label _lInfo;
+        Label _lPass;
+        Label _lFail;
+        Label _lSw2;
+        
+        Field _fId;
+        Field _fPass;
+        Field _fFail;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutSweepProgress.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,61 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "LayoutSweepProgress.h"
+
+LayoutSweepProgress::LayoutSweepProgress(DOGS102* lcd)
+  : Layout(lcd),
+    _lMsg1(6, 2, "Sweep"),
+    _lMsg2(7, 3, "in"),
+    _lMsg3(4, 4, "Progress"),
+    _fProgress(6, 1, 5),
+    _fCountdownLabel(0, 6, 17),
+    _fCountdown(0, 7, 9)
+{}
+
+LayoutSweepProgress::~LayoutSweepProgress() {}
+
+void LayoutSweepProgress::display() {
+    clear();
+    startUpdate();
+
+    writeLabel(_lMsg1);
+    writeLabel(_lMsg2);
+    writeLabel(_lMsg3);
+
+    endUpdate();
+}
+
+void LayoutSweepProgress::updateProgress(uint8_t complete, uint8_t total) {
+    char buf[8];
+    size_t size;
+
+    size = snprintf(buf, sizeof(buf), "%u/%u", complete, total);
+    writeField(_fProgress, buf, size, true);
+}
+
+void LayoutSweepProgress::updateCountdown(uint32_t seconds) {
+    char buf[16];
+    size_t size;
+
+    // make sure the string version is used
+    writeField(_fCountdownLabel, string("No Free Channel"), true);
+    size = snprintf(buf, sizeof(buf), "%lu s", seconds);
+    writeField(_fCountdown, buf, size, true);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Layout/LayoutSweepProgress.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,44 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LAYOUTSWEEPPROGRESS_H__
+#define __LAYOUTSWEEPPROGRESS_H__
+
+#include "Layout.h"
+
+class LayoutSweepProgress : public Layout {
+    public:
+        LayoutSweepProgress(DOGS102* lcd);
+        ~LayoutSweepProgress();
+
+        void display();
+
+        void updateProgress(uint8_t complete, uint8_t total);
+        void updateCountdown(uint32_t seconds);
+
+    private:
+        Label _lMsg1;
+        Label _lMsg2;
+        Label _lMsg3;
+
+        Field _fProgress;
+        Field _fCountdownLabel;
+        Field _fCountdown;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LoRaHandler/LoRaHandler.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,182 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "LoRaHandler.h"
+
+#define signal (int32_t)0xA0
+
+typedef enum {
+    l_none = 0,
+    l_link_check,
+    l_send,
+    l_join
+} InternalLoRa;
+
+uint8_t cmd = l_none;
+std::vector<uint8_t> send_data;
+
+void l_worker(void const* argument) {
+    LoRaHandler* l = (LoRaHandler*)argument;
+    osEvent e;
+
+    l->_dot = mDot::getInstance();
+    int32_t ret;
+    mDot::link_check lc;
+    mDot::rssi_stats rs;
+    mDot::snr_stats ss;
+
+    while (true) {
+        e = Thread::signal_wait(signal);
+        if (e.status == osEventSignal) {
+            l->_status = LoRaHandler::busy;
+            l->_tick.attach(l, &LoRaHandler::blinker, 0.05);
+            switch (cmd) {
+                case l_link_check:
+                    l->_mutex.lock();
+                    lc = l->_dot->networkLinkCheck();
+                    l->_mutex.unlock();
+                    if (lc.status) {
+                        l->_link.up = lc;
+                        l->_mutex.lock();
+                        rs = l->_dot->getRssiStats();
+                        ss = l->_dot->getSnrStats();
+                        l->_mutex.unlock();
+                        l->_link.down.rssi = rs.last;
+                        l->_link.down.snr = ss.last;
+                        l->_status = LoRaHandler::link_check_success;
+                    } else {
+                        l->_status = LoRaHandler::link_check_failure;
+                    }
+                    osSignalSet(l->_main, loraSignal);
+                    l->_tick.detach();
+                    l->_activity_led = LoRaHandler::green;
+                    break;
+                
+                case l_send:
+                    l->_mutex.lock();
+                    ret = l->_dot->send(send_data);
+                    l->_mutex.unlock();
+                    if (ret == mDot::MDOT_OK)
+                        l->_status = LoRaHandler::send_success;
+                    else
+                        l->_status = LoRaHandler::send_failure;
+                    osSignalSet(l->_main, loraSignal);
+                    l->_tick.detach();
+                    l->_activity_led = LoRaHandler::green;
+                    break;
+
+                case l_join:
+                    l->_mutex.lock();
+                    ret = l->_dot->joinNetworkOnce();
+                    l->_join_attempts++;
+                    l->_mutex.unlock();
+                    if (ret == mDot::MDOT_OK) {
+                        l->_status = LoRaHandler::join_success;
+                    } else {
+                        l->_status = LoRaHandler::join_failure;
+                    }
+                    osSignalSet(l->_main, loraSignal);
+                    l->_tick.detach();
+                    l->_activity_led = LoRaHandler::green;
+                    break;
+
+                default:
+                    l->_status = LoRaHandler::none;
+                    break;
+            }
+        }
+    }
+}
+
+LoRaHandler::LoRaHandler(osThreadId main)
+  : _main(main),
+    _thread(l_worker, (void*)this),
+    _status(none),
+    _join_attempts(1),
+    _activity_led(XBEE_DIO1, PIN_OUTPUT, PullNone, red)
+{
+    _link.status = false;
+    _activity_led = red;
+}
+
+bool LoRaHandler::linkCheck() {
+    return action(l_link_check);
+}
+
+bool LoRaHandler::send(std::vector<uint8_t> data) {
+    send_data = data;
+    return action(l_send);
+}
+
+bool LoRaHandler::join() {
+        return action(l_join);
+}
+
+bool LoRaHandler::action(uint8_t c) {
+    if (_status != busy) {
+        cmd = c;
+        _thread.signal_set(signal);
+        _thread.signal_clr(signal);
+        return true;
+    }
+
+    return false;
+}
+
+LoRaHandler::LoRaStatus LoRaHandler::getStatus() {
+    LoRaStatus status;
+    _mutex.lock();
+    status = _status;
+    _mutex.unlock();
+
+    return status;
+}
+
+LoRaHandler::LoRaLink LoRaHandler::getLinkCheckResults() {
+    LoRaLink link;
+    _mutex.lock();
+    link = _link;
+    _mutex.unlock();
+
+    return link;
+}
+
+uint32_t LoRaHandler::getJoinAttempts() {
+    uint32_t val;
+
+    _mutex.lock();
+    val = _join_attempts;
+    _mutex.unlock();
+
+    return val;
+}
+
+void LoRaHandler::resetJoinAttempts() {
+    _mutex.lock();
+    _join_attempts = 1;
+    _mutex.unlock();
+}
+
+void LoRaHandler::blinker() {
+    _activity_led = !_activity_led;
+}
+
+void LoRaHandler::resetActivityLed() {
+    _activity_led = red;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LoRaHandler/LoRaHandler.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,76 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LORAHANDLER_H__
+#define __LORAHANDLER_H__
+
+#include "mDot.h"
+
+#define loraSignal (int32_t)0x02
+
+class LoRaHandler {
+    public:
+        typedef enum {
+            none = 0,
+            busy,
+            link_check_success,
+            send_success,
+            join_success,
+            link_check_failure,
+            send_failure,
+            join_failure
+        } LoRaStatus;
+
+        typedef struct {
+            bool status;
+            mDot::link_check up;
+            mDot::ping_response down;
+        } LoRaLink;
+
+        typedef enum {
+            green = 0,
+            red
+        } LedColor;
+
+        LoRaHandler(osThreadId main);
+        ~LoRaHandler();
+
+        bool linkCheck();
+        bool send(std::vector<uint8_t> data);
+        bool join();
+        bool action(uint8_t cmd);
+        LoRaStatus getStatus();
+        LoRaLink getLinkCheckResults();
+        uint32_t getJoinAttempts();
+        void resetJoinAttempts();
+        void blinker();
+        void resetActivityLed();
+
+        osThreadId _main;
+        Thread _thread;
+        LoRaStatus _status;
+        LoRaLink _link;
+        mDot* _dot;
+        Mutex _mutex;
+        uint32_t _join_attempts;
+        DigitalInOut _activity_led;
+        Ticker _tick;
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Mode/Mode.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,339 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "Mode.h"
+#include "MTSLog.h"
+
+/*
+ * union for converting from 32-bit to 4 8-bit values
+ */
+union convert32 {
+    int32_t f_s;		// convert from signed 32 bit int
+    uint32_t f_u;		// convert from unsigned 32 bit int
+    uint8_t t_u[4];		// convert to 8 bit unsigned array
+}convertL;
+
+/*
+ * union for converting from 16- bit to 2 8-bit values
+ */
+union convert16 {
+    int16_t f_s;		// convert from signed 16 bit int
+    uint16_t f_u;		// convert from unsigned 16 bit int
+    uint8_t t_u[2];		// convert to 8 bit unsigned array
+} convertS;
+
+
+Mode::Mode(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora, GPSPARSER* gps, SensorHandler* sensors)
+  : _lcd(lcd),
+    _buttons(buttons),
+    _dot(dot),
+    _lora(lora),
+    _gps(gps),
+    _sensors(sensors),
+    _main_id(Thread::gettid()),
+    _index(0),
+    _band(_dot->getFrequencyBand()),
+    _sub_band(_dot->getFrequencySubBand()),
+    _data_rate(mDot::SF_7),
+    _power(2),
+    _next_tx(0),
+    _send_data(false),
+    _gps_available(_gps->gpsDetected())
+{}
+
+Mode::~Mode() {}
+
+bool Mode::deleteDataFile() {
+    bool ret = true;
+
+    // if survey data file exists, attempt to delete it
+    std::vector<mDot::mdot_file> files = _dot->listUserFiles();
+    for (std::vector<mDot::mdot_file>::iterator it = files.begin(); it != files.end(); it++)
+        if (it->name == file_name) {
+            if (! _dot->deleteUserFile(file_name))
+                ret = false;
+            break;
+        }
+
+    return ret;
+}
+
+// ID, Status, Lock, Lat, Long, Alt, Time, RSSIup, SNRup, RSSIdown, SNRdown, DataRate, Power
+bool Mode::appendDataFile(const DataItem& data) {
+    char main_buf[256];
+    char id_buf[16];
+    char lat_buf[32];
+    char lon_buf[32];
+    char alt_buf[16];
+    char time_buf[32];
+    char stats_buf[32];
+    size_t size;
+
+    snprintf(id_buf, sizeof(id_buf), "%c%ld", (data.type == single) ? 'L' : 'S', data.index);
+
+    // if we had GPS lock, format GPS data
+    if (data.gps_lock) {
+        snprintf(lat_buf, sizeof(lat_buf), "%d %d %d.%03d %c",
+            abs(data.gps_latitude.degrees),
+            data.gps_latitude.minutes,
+            (data.gps_latitude.seconds * 6) / 1000,
+            (data.gps_latitude.seconds * 6) % 1000,
+            (data.gps_latitude.degrees > 0) ? 'N' : 'S');
+        snprintf(lon_buf, sizeof(lon_buf), "%d %d %d.%03d %c",
+            abs(data.gps_longitude.degrees),
+            data.gps_longitude.minutes,
+            (data.gps_longitude.seconds * 6) / 1000,
+            (data.gps_longitude.seconds * 6) % 1000,
+            (data.gps_longitude.degrees > 0) ? 'E' : 'W');
+        snprintf(alt_buf, sizeof(alt_buf), "%d",
+            data.gps_altitude);
+        snprintf(time_buf, sizeof(time_buf), "%02d:%02d:%02d %02d/%02d/%04d",
+            data.gps_time.tm_hour,
+            data.gps_time.tm_min,
+            data.gps_time.tm_sec,
+            data.gps_time.tm_mon + 1,
+            data.gps_time.tm_mday,
+            data.gps_time.tm_year + 1900);
+    }
+
+    if (data.status) {
+        float down_snr = (float)data.link.down.snr / 10.0;
+        snprintf(stats_buf, sizeof(stats_buf), "%lu,%ld,%d,%2.1f",
+            data.link.up.gateways,
+            data.link.up.dBm,
+            abs(data.link.down.rssi),
+            down_snr);
+    }
+
+    size = snprintf(main_buf, sizeof(main_buf), "%s,%c,%ld,%s,%s,%s,%s,%s,%s,%lu\n",
+        id_buf,
+        data.status ? 'S' : 'F',
+        data.gps_lock ? data.gps_sats : 0,
+        (data.gps_lock) ? lat_buf : "",
+        (data.gps_lock) ? lon_buf : "",
+        (data.gps_lock) ? alt_buf : "",
+        (data.gps_lock) ? time_buf : "",
+        data.status ? stats_buf : ",,,",
+        _dot->DataRateStr(data.data_rate).substr(3).c_str(),
+        data.power);
+
+    if (size < 0) {
+        logError("failed to format survey data");
+        return false;
+    }
+
+    if (! _dot->appendUserFile(file_name, (void*)main_buf, size)) {
+        logError("failed to write survey data to file");
+        return false;
+    } else {
+        logInfo("successfully wrote survey data to file\r\n\t%s", main_buf);
+    }
+
+    return true;
+}
+
+void Mode::updateData(DataItem& data, DataType type, bool status) {
+    data.type = type;
+    data.index = _index;
+    data.status = status;
+    data.gps_lock = _gps->getLockStatus();
+    data.gps_sats = _gps->getNumSatellites();
+    data.gps_longitude = _gps->getLongitude();
+    data.gps_latitude = _gps->getLatitude();
+    data.gps_altitude = _gps->getAltitude();
+    data.gps_time = _gps->getTimestamp();
+    data.link = _link_check_result;
+    data.data_rate = _data_rate;
+    data.power = _power;
+}
+
+void Mode::updateSensorData(SensorItem& data) {
+    data.accel_data = _sensors->getAcceleration();
+    data.baro_data = _sensors->getBarometer();
+    data.lux_data_raw = _sensors->getLightRaw();
+    data.pressure_raw = _sensors->getPressureRaw();
+    data.light = _sensors->getLight();
+    data.pressure = _sensors->getPressure();
+    data.altitude = _sensors->getAltitude();
+    data.temperature = _sensors->getTemp(SensorHandler::CELSIUS);
+}
+
+uint32_t Mode::getIndex(DataType type) {
+    uint32_t index = 0;
+    mDot::mdot_file file;
+    size_t buf_size = 128;
+    char buf[buf_size];
+    bool done = false;
+    char search;
+
+    int read_offset;
+    int read_size;
+    int reduce = buf_size - 32;
+    int bytes_read;
+    int ret;
+    int current;
+
+    if (type == single)
+        search = 'L';
+    else
+        search = 'S';
+
+    file = _dot->openUserFile(file_name, mDot::FM_RDONLY);
+    if (file.fd < 0) {
+        logError("failed to open survey data file");
+    } else {
+        //logInfo("file size %d", file.size);
+        if (file.size > buf_size) {
+            read_offset = file.size - buf_size - 1;
+            read_size = buf_size;
+        } else {
+            read_offset = 0;
+            read_size = file.size;
+        }
+
+        while (! done) {
+            if (read_offset == 0)
+                done = true;
+
+            //logInfo("reading from index %d, %d bytes", read_offset, read_size);
+
+            if (! _dot->seekUserFile(file, read_offset, SEEK_SET)) {
+                logError("failed to seek %d/%d", read_offset, file.size);
+                return 0;
+            }
+            memset(buf, 0, buf_size);
+            ret = _dot->readUserFile(file, (void*)buf, read_size);
+            if (ret != read_size) {
+                logError("failed to read");
+                return 0;
+            }
+            //logInfo("read %d bytes [%s]", ret, buf);
+	    bytes_read = file.size - read_offset;
+	    //logInfo("read %d total bytes", bytes_read);
+
+            // read_size - 1 is the last byte in the buffer
+            for (current = read_size - 1; current >= 0; current--) {
+		// generic case where a preceding newline exists
+                if (buf[current] == '\n' && current != read_size - 1) {
+                    int test = current;
+                    //logInfo("found potential %d, %c", read_offset + current, buf[test + 1]);
+                    if (buf[test + 1] == search) {
+                        sscanf(&buf[test + 2], "%ld", &index);
+                        done = true;
+                        break;
+                    }
+		// special case where the index we're looking for is in the first entry - no newline
+                } else if (current == 0 && bytes_read >= file.size) {
+                    int test = current;
+                    //logInfo("found potential %d, %c", read_offset + current, buf[test + 1]);
+		    if (buf[test] == search) {
+			sscanf(&buf[test + 1], "%ld", &index);
+			done = true;
+			break;
+		    }
+		}
+            }
+
+            read_offset = (read_offset - reduce > 0) ? read_offset - reduce : 0;
+        }
+        _dot->closeUserFile(file);
+    }
+
+    logInfo("returning index %d", index);
+
+    return index;
+}
+
+std::vector<uint8_t> Mode::formatSurveyData(DataItem& data) {
+    std::vector<uint8_t> send_data;
+    uint8_t satfix;
+
+    send_data.clear();
+    send_data.push_back(0x1D);			// key for start of data structure
+    send_data.push_back(0x1A);			// key for uplink QOS + RF Pwr
+    convertS.f_s = data.link.up.gateways;
+    send_data.push_back(convertS.t_u[1]);
+    send_data.push_back(convertS.t_u[0]);
+    send_data.push_back((data.link.up.dBm) & 0xFF);
+    send_data.push_back(data.power);
+
+    send_data.push_back(0x1B);			// key for downlink QOS
+    convertS.f_s=data.link.down.rssi;
+    send_data.push_back(convertS.t_u[1]);
+    send_data.push_back(convertS.t_u[0]);
+    send_data.push_back((data.link.down.snr/10) & 0xFF);
+
+    // collect GPS data if GPS device detected
+    if (_gps->gpsDetected() && ((_data_rate != mDot::SF_10) || (_band == mDot::FB_868))){
+	    send_data.push_back(0x19);			// key for GPS Lock Status
+	    satfix = (_gps->getNumSatellites() << 4 ) | (_gps->getFixStatus() & 0x0F );
+	    send_data.push_back(satfix);
+
+	    if (_gps->getLockStatus()){				    // if gps has a lock
+		    // Send GPS data if GPS device locked
+		    send_data.push_back(0x15);			    // key for GPS Latitude
+		    send_data.push_back(data.gps_latitude.degrees);
+		    send_data.push_back(data.gps_latitude.minutes);
+		    convertS.f_s = data.gps_latitude.seconds;
+		    send_data.push_back(convertS.t_u[1]);
+		    send_data.push_back(convertS.t_u[0]);
+
+		    send_data.push_back(0x16);			    // key for GPS Longitude
+		    convertS.f_s = data.gps_longitude.degrees;
+		    send_data.push_back(convertS.t_u[1]);
+		    send_data.push_back(convertS.t_u[0]);
+
+		    send_data.push_back(data.gps_longitude.minutes);
+		    convertS.f_s = data.gps_longitude.seconds;
+		    send_data.push_back(convertS.t_u[1]);
+		    send_data.push_back(convertS.t_u[0]);
+	    }
+    }
+    // key for end of data structure		
+    send_data.push_back(0x1D);					
+
+    return send_data;
+}
+
+std::vector<uint8_t> Mode::formatSensorData(SensorItem& data) {
+    std::vector<uint8_t> send_data;
+    send_data.clear();
+    send_data.push_back(0x0E);			// key for Current Acceleration 3-Axis Value
+    convertS.f_s = data.accel_data._x *4;	// shift data 2 bits while retaining sign
+    send_data.push_back(convertS.t_u[1]);	// get 8 MSB of 14 bit value
+    convertS.f_s = data.accel_data._y * 4;	// shift data 2 bits while retaining sign
+    send_data.push_back(convertS.t_u[1]);	// get 8 MSB of 14 bit value
+    convertS.f_s = data.accel_data._z * 4;	// shift data 2 bits while retaining sign
+    send_data.push_back(convertS.t_u[1]);	// get 8 MSB of 14 bit value
+    send_data.push_back(0x08);			// key for Current Pressure Value
+    convertL.f_u = data.pressure_raw;		// pressure data is 20 bits unsigned
+    send_data.push_back(convertL.t_u[2]);
+    send_data.push_back(convertL.t_u[1]);
+    send_data.push_back(convertL.t_u[0]);
+    send_data.push_back(0x05);			// key for Current Ambient Light Value
+    convertS.f_u = data.lux_data_raw;		// data is 16 bits unsigned
+    send_data.push_back(convertS.t_u[1]);
+    send_data.push_back(convertS.t_u[0]);
+    send_data.push_back(0x0B);			// key for Current Temperature Value
+    convertS.f_s = data.baro_data._temp; 	// temperature is signed 12 bit
+    send_data.push_back(convertS.t_u[1]);
+    send_data.push_back(convertS.t_u[0]);
+
+    return send_data;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Mode/Mode.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,104 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __MODE_H__
+#define __MODE_H__
+
+#include "DOGS102.h"
+#include "ButtonHandler.h"
+#include "mDot.h"
+#include "LoRaHandler.h"
+#include "GPSPARSER.h"
+#include "SensorHandler.h"
+#include "ISL29011.h"
+#include "MMA845x.h"
+#include "MPL3115A2.h"
+#include "FileName.h"
+
+class Mode {
+    public:
+        typedef enum {
+            single = 0,
+            sweep
+        } DataType;
+
+        typedef struct {
+            DataType type;
+            int32_t index;
+            bool status;
+	    bool gps_lock;
+            int32_t gps_sats;
+            GPSPARSER::longitude gps_longitude;
+            GPSPARSER::latitude gps_latitude;
+            int16_t gps_altitude;
+            struct tm gps_time;
+            LoRaHandler::LoRaLink link;
+            uint8_t data_rate;
+            uint32_t power;
+        } DataItem;
+
+        typedef struct {
+            MMA845x_DATA accel_data;
+            MPL3115A2_DATA baro_data;
+            uint16_t lux_data_raw;
+            uint32_t pressure_raw;
+            float light;
+            float pressure;
+			float altitude;
+			float temperature;			
+        } SensorItem;		
+
+        Mode(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora, GPSPARSER* gps, SensorHandler* sensors);
+        ~Mode();
+
+        virtual bool start() = 0;
+
+    protected:
+        bool deleteDataFile();
+        bool appendDataFile(const DataItem& data);
+        void updateData(DataItem& data, DataType type, bool status);
+		void updateSensorData(SensorItem& data);
+        uint32_t getIndex(DataType type);
+
+        std::vector<uint8_t> formatSurveyData(DataItem& data);
+        std::vector<uint8_t> formatSensorData(SensorItem& data);
+
+        DOGS102* _lcd;
+        ButtonHandler* _buttons;
+        mDot* _dot;
+        LoRaHandler* _lora;
+	GPSPARSER* _gps;
+	SensorHandler* _sensors;
+        osThreadId _main_id;
+        uint32_t _index;
+        uint8_t _band;
+        uint8_t _sub_band;
+        uint8_t _data_rate;
+        uint32_t _power;
+        uint32_t _next_tx;
+        ButtonHandler::ButtonEvent _be;
+        LoRaHandler::LoRaStatus _ls;
+        LoRaHandler::LoRaLink _link_check_result;
+        uint8_t _state;
+        bool _send_data;
+	bool _gps_available;
+	uint8_t _initial_data_rate;
+	uint8_t _initial_power;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Mode/ModeConfig.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,358 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "ModeConfig.h"
+#include "ctype.h"
+#include "Command.h"
+#include "ButtonHandler.h"
+#include <cstdarg>
+#include <deque>
+
+const char ModeConfig::newline[] = "\r\n";
+
+// Command error text...
+const char ModeConfig::command_error[] = "Command not found!\r\n";
+
+// Response texts...
+const char ModeConfig::done[] = "\r\nOK\r\n";
+const char ModeConfig::error[] = "\r\nERROR\r\n";
+
+void ModeConfig::addCommand(Command* cmd) {
+    _commands.push_back(cmd);
+}
+
+ModeConfig::ModeConfig(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora, GPSPARSER* gps, SensorHandler* sensors)
+: Mode(lcd, buttons, dot, lora, gps, sensors),
+  _lc(lcd),
+  _serial(USBTX, USBRX, 512, 512)
+{
+    _serial.baud(115200);
+
+    addCommand(new CmdAttention(_dot));
+    addCommand(new CmdIdentification(_dot, _serial));
+    addCommand(new CmdFactoryDefault(_dot));
+    addCommand(new CmdSaveConfig(_dot));
+    addCommand(new CmdDisplayConfig(_dot, _serial));
+
+    addCommand(new CmdFrequencyBand(_dot, _serial));
+    addCommand(new CmdFrequencySubBand(_dot, _serial));
+    addCommand(new CmdPublicNetwork(_dot, _serial));
+    addCommand(new CmdDeviceId(_dot, _serial));
+
+    addCommand(new CmdNetworkAddress(_dot, _serial));
+    addCommand(new CmdNetworkSessionKey(_dot, _serial));
+    addCommand(new CmdDataSessionKey(_dot, _serial));
+    addCommand(new CmdNetworkKey(_dot, _serial));
+    addCommand(new CmdNetworkId(_dot, _serial));
+
+    addCommand(new CmdNetworkJoinMode(_dot, _serial));
+    addCommand(new CmdTxDataRate(_dot, _serial));
+    addCommand(new CmdTxPower(_dot, _serial));
+
+    addCommand(new CmdMinimumSize(_dot, _serial));
+    addCommand(new CmdMaximumSize(_dot, _serial));
+    addCommand(new CmdMinimumPower(_dot, _serial));
+    addCommand(new CmdMaximumPower(_dot, _serial));
+    addCommand(new CmdData(_dot, _serial));
+    addCommand(new CmdGetSurveyDataFile(_dot, _serial));
+    addCommand(new CmdDeleteSurveyDataFile(_dot, _serial));
+    addCommand(new CmdDummy(_dot, "Exit to main menu", "AT+EXIT", "Exit configuration and return to the main menu"));
+
+#if MTS_RADIO_DEBUG_COMMANDS
+    addCommand(new CmdWriteProtectedConfig(_dot));
+#endif
+}
+
+void ModeConfig::printHelp() {
+    const char* name = NULL;
+    const char* text = NULL;
+    const char* desc = NULL;
+    const char* tab = "\t";
+
+    std::string header("Command");
+    header.append(tab);
+    header.append(tab);
+    header.append("Name");
+    header.append(tab);
+    header.append(tab);
+    header.append(tab);
+    header.append("Description");
+
+    write(newline);
+    write(header.c_str());
+    write(newline);
+    write(newline);
+    for (std::vector<Command*>::iterator it = _commands.begin(); it != _commands.end(); ++it) {
+        name = (*it)->name();
+        text = (*it)->text();
+        desc = (*it)->desc();
+        write(text);
+        if (strlen(text) < 8)
+            write(tab);
+        write(tab);
+        write(name);
+        if (strlen(name) < 8)
+            write(tab);
+        if (strlen(name) < 16)
+            write(tab);
+        write(tab);
+        write(desc);
+        write(newline);
+    }
+
+    write(newline);
+}
+
+bool ModeConfig::writeable() {
+    return _serial.writeable();
+}
+
+bool ModeConfig::readable() {
+    return _serial.readable();
+}
+
+char ModeConfig::read() {
+    char ch;
+    _serial.read(&ch, 1);
+    return ch;
+}
+
+void ModeConfig::write(const char* message) {
+    while (!writeable())
+        ;
+    _serial.write(message, strlen(message));
+}
+
+void ModeConfig::writef(const char* format, ...) {
+    char buff[256];
+
+    va_list ap;
+    va_start(ap, format);
+    int size = vsnprintf(buff, 256, format, ap);
+    while (!writeable())
+        ;
+    _serial.write(buff, size);
+    va_end(ap);
+}
+
+bool ModeConfig::start() {
+    char ch;
+    bool running = true;
+    bool echo = _dot->getEcho();
+    std::string command;
+    std::deque<std::string> history;
+    int history_index = -1;
+    std::vector<std::string> args;
+
+    osSignalClear(_main_id, buttonSignal);
+
+    _lc.display();
+
+    //Run terminal session
+    while (running) {
+        _lc.roll();
+           
+        osEvent e = Thread::signal_wait(buttonSignal, 20);
+        if (e.status == osEventSignal) {
+            ButtonHandler::ButtonEvent _be = _buttons->getButtonEvent();
+            switch (_be) {
+                case ButtonHandler::sw1_press:
+                    break;
+                case ButtonHandler::sw2_press:
+                    break;
+                case ButtonHandler::sw1_hold:
+                    return true;
+                default:
+                    break;
+            }
+        }
+		
+        ch = '\0';
+
+        // read characters
+        if (readable()) {
+            ch = read();
+
+            if (ch == '\b' || ch == 0x7f) {
+                if (!command.empty()) {
+                    writef("\b \b");
+                    command.erase(command.size() - 1);
+                }
+                continue;
+            } else if (ch == 0x1b || ch == 0x09) {
+                osDelay(20);
+                // catch escape sequence, or tab
+                char ch1, ch2;
+
+                if (readable()) {
+                    ch1 = read();
+                    if (readable())
+                        ch2 = read();
+
+                    if (ch1 == 0x5b && ch2 == 0x41) {
+                        // up key
+                        for (int i = 0; i < command.size()+1; i++) {
+                            writef("\b \b");
+                        }
+                        if (history.size() > 0) {
+                            if (++history_index >= history.size() - 1)
+                                history_index = history.size() - 1;
+
+                            command = history[history_index];
+                            writef("%s", history[history_index].c_str());
+                        } else {
+                            command.clear();
+                        }
+                    } else if (ch1 == 0x5b && ch2 == 0x42) {
+
+                        // down key
+                        for (int i = 0; i < command.size()+1; i++) {
+                            writef("\b \b");
+                        }
+
+                        if (--history_index < 0) {
+                            history_index = -1;
+                            command.clear();
+                        } else {
+                            command = history[history_index];
+                            writef("%s", history[history_index].c_str());
+                        }
+                    }
+                }
+                while (readable()) read();
+                continue;
+            } else {
+                command += ch;
+            }
+
+            // echo chars if enabled
+            if (echo && !(ch == '\r' || ch == '\n'))
+                writef("%c", ch);
+        }
+
+        // look for end of command line
+        if (command.find("\n") != std::string::npos || command.find("\r") != std::string::npos) {
+            // remove new line or cr character
+            command.erase(command.size() - 1);
+            write("\r"); // match standard modem output
+            write(newline);
+        } else {
+            continue;
+        }
+
+        // trim whitespace from command
+        mts::Text::trim(command, "\r\n\t ");
+
+        if (command.size() < 1) {
+            command.clear();
+            continue;
+        }
+
+        // parse command and args
+        args.clear();
+
+        // find first '=' character
+        size_t delim_index = command.find("=");
+        if (delim_index != std::string::npos) {
+            args.push_back(command.substr(0, delim_index));
+        } else {
+            // find first ' ' character
+            delim_index = command.find(" ");
+            if (delim_index != std::string::npos) {
+                args.push_back(command.substr(0, delim_index));
+            } else {
+                args.push_back(command);
+            }
+        }
+
+        if (delim_index != std::string::npos) {
+            std::vector<std::string> params = mts::Text::split(command.substr(delim_index + 1), ",");
+            args.insert(args.end(), params.begin(), params.end());
+        }
+
+        args[0] = mts::Text::toUpper(args[0]);
+
+        // print help
+        if ((args[0].find("?") == 0 || args[0].find("HELP") == 0) && args.size() == 1) {
+            printHelp();
+            command.clear();
+        } else if (args[0].find("AT+EXIT") == 0 && args[0].length() == 7) {
+            write(done);        
+	    return true;
+        } else {
+            bool found = false;
+            bool query = false;
+
+            std::string lookfor = args[0];
+
+            // per command help
+            if ((args[0].find("?") == 0 || args[0].find("HELP") == 0))
+                lookfor = mts::Text::toUpper(args[1]);
+
+            // trim off any trailing '?' and mark as a query command
+            if (args[0].rfind("?") == args[0].length() - 1) {
+                query = true;
+                lookfor = args[0].substr(0, args[0].length() - 1);
+            }
+
+            // search for command
+            for (std::vector<Command*>::iterator it = _commands.begin(); it != _commands.end() && !found; ++it) {
+                Command* cmd = *it;
+
+                // match CMD or CMD? syntax if command is queryable
+                if (lookfor == cmd->text() && (!query || (query && cmd->queryable()))) {
+                    found = true;
+                    if (args[0] == "HELP") {
+                        writef("%s%s", cmd->help(), newline);
+                        write(done);
+                    }
+
+                    else if (args.size() > 1 && args[1] == "?") {
+                        writef("%s%s", cmd->usage().c_str(), newline);
+                        write(done);
+                    } else if (!cmd->verify(args)) {
+                        writef("%s%s", cmd->errorMessage().c_str(), newline);
+                        writef("%s", error);
+                    } else {
+                        if (cmd->action(args) == 0) {
+                            writef("%s", done);
+                        } else {
+                            writef("%s%s", cmd->errorMessage().c_str(), newline);
+                            writef("%s", error);
+                        }
+                    }
+                }
+            }
+
+            if (!found) {
+                writef("%s", command_error);
+                writef("%s", error);
+            }
+        }
+
+        if (history.size() == 0 || history.front() != command)
+            history.push_front(command);
+        history_index = -1;
+        command.clear();
+
+        while (history.size() > 10)
+            history.pop_back();
+
+    }
+	return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Mode/ModeConfig.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,62 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __MODECONFIG_H__
+#define __MODECONFIG_H__
+
+#include "Mode.h"
+#include "LayoutConfig.h"  
+#include "mbed.h"
+#include "MTSSerial.h"
+#include "Commands.h"
+
+class ModeConfig : public Mode {
+
+public:
+
+    ModeConfig(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora, GPSPARSER* gps, SensorHandler* sensors);
+    
+    // Command error text...
+    static const char command_error[];
+    
+    // Response texts...
+    static const char newline[];
+    static const char done[];
+    static const char error[];
+
+    bool start();
+    
+private: 
+
+    mts::MTSSerial _serial;
+    LayoutConfig _lc;
+    std::vector<Command*> _commands;
+
+    void addCommand(Command* cmd);
+    
+    void printHelp();
+
+    bool readable();
+    bool writeable();
+    char read();
+    void write(const char* message);
+    void writef(const char* format, ... );
+    
+};
+
+#endif // __MODECONFIG_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Mode/ModeDemo.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,198 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "ModeDemo.h"
+#include "MTSLog.h"
+
+// 10 s, 30 s, 1 min, 5 min, 10 min, 15 min, 30 min 1 hour
+const uint32_t ModeDemo::_intervals[] = { 10, 30, 60, 5 * 60, 10 * 60, 15 * 60, 30 * 60 };
+
+ModeDemo::ModeDemo(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora, GPSPARSER* gps, SensorHandler* sensors)
+  : Mode(lcd, buttons, dot, lora, gps, sensors),
+    _help(lcd),
+    _sam(lcd),
+    _interval(0)
+{}
+
+ModeDemo::~ModeDemo() {}
+
+bool ModeDemo::start() {
+    bool send = false;
+    bool no_channel = false;
+
+    // clear any stale signals
+    osSignalClear(_main_id, buttonSignal | loraSignal);
+
+    _initial_data_rate = _dot->getTxDataRate();
+
+    // use configured data rate and power if possible
+    if (_band == mDot::FB_915 && _initial_data_rate == mDot::SF_10) {
+        logInfo("using SF_9 instead of SF_10 - SF_10 max packet size is too small for data");
+        _dot->setTxDataRate(mDot::SF_9);
+    }
+
+    _state = show_help;
+    displayHelp();
+
+    while (true) {
+        osEvent e = Thread::signal_wait(0, 250);
+        if (e.status == osEventSignal) {
+            if (e.value.signals & buttonSignal) {
+                _be = _buttons->getButtonEvent();
+
+                switch (_be) {
+                    case ButtonHandler::sw1_press:
+                        switch (_state) {
+                            case show_help:
+                                _state = sampling;
+                                _mode = trigger;
+                                _sam.display();
+                                _sam.updateSw1("    Send");
+                                _sam.updateSw2("Back");
+                                break;
+                            case sampling:
+                                if (_mode == trigger) {
+                                    if (_dot->getNextTxMs() > 0)
+                                        no_channel = true;
+                                    else
+                                        send = true;
+                                } else {
+                                    _interval = (_interval + 1) % (sizeof(_intervals) / sizeof(uint32_t));
+                                    _sam.updateInterval(_intervals[_interval]);
+                                }
+                                break;
+                        }
+                        break;
+
+                    case ButtonHandler::sw2_press:
+                        switch (_state) {
+                            case show_help:
+                                _state = sampling;
+                                _mode = interval;
+                                _send_timer.start();
+                                _sam.display();
+                                _sam.updateSw1("Interval");
+                                _sam.updateSw2("Back");
+                                _sam.updateInterval(_intervals[_interval]);
+                                break;
+                            case sampling:
+                                no_channel = false;
+                                send = false;
+                                _send_timer.stop();
+                                _send_timer.reset();
+                                _state = show_help;
+                                displayHelp();
+                                break;
+                        }
+                        break;
+                    case ButtonHandler::sw1_hold:
+                        _send_timer.stop();
+                        _send_timer.reset();
+                        if (_band == mDot::FB_915)
+                            _dot->setTxDataRate(_initial_data_rate);
+                        return true;
+                }
+            }
+            if (e.value.signals & loraSignal) {
+                _ls = _lora->getStatus();
+                switch (_ls) {
+                    case LoRaHandler::send_success:
+                        switch (_state) {
+                            case sampling:
+                                if (_mode == trigger) {
+                                    _sam.updateSw1("    Send");
+                                    _sam.updateInfo("                 ");
+                                } else {
+                                    _sam.updateSw1("Interval");
+                                    _sam.updateInterval(_intervals[_interval]);
+                                }
+                                _sam.updateSw2("Back");
+                                break;
+                        }
+                        break;
+
+                    case LoRaHandler::send_failure:
+                        switch (_state) {
+                            case sampling:
+                                if (_mode == trigger) {
+                                    _sam.updateSw1("    Send");
+                                    _sam.updateInfo("                 ");
+                                } else {
+                                    _sam.updateSw1("Interval");
+                                    _sam.updateInterval(_intervals[_interval]);
+                                }
+                                _sam.updateSw2("Back");
+                                break;
+                        }
+                        break;
+                }
+            }
+        }
+
+        if (_send_timer.read_ms() > _intervals[_interval] * 1000) {
+            _send_timer.reset();
+            if (_dot->getNextTxMs() > 0)
+                no_channel = true;
+            else
+                send = true;
+        }
+        if (no_channel) {
+            uint32_t t = _dot->getNextTxMs();
+            if (t > 0) {
+                logInfo("next tx %lu ms", t);
+                _sam.updateCountdown(t / 1000);
+            } else {
+                no_channel = false;
+                send = true;
+            }
+        }
+        if (send) {
+            std::vector<uint8_t> s_data = formatSensorData(_data);
+            logInfo("sending data %s %d", _dot->DataRateStr(_dot->getTxDataRate()).c_str(), _dot->getTxPower());
+            _sam.updateInfo("Sending...");
+            _sam.updateSw1("        ");
+            _sam.updateSw2("        ");
+            send = false;
+            // we don't care if the server actually gets this packet or not
+            // we won't retry anyway
+            _dot->setAck(0);
+            _dot->setTxWait(false);
+            _lora->send(s_data);
+            osDelay(500);
+        }
+        if(_state != show_help){
+            updateSensorData(_data);
+            _sam.updateAccelerationX(_data.accel_data._x);
+            _sam.updateAccelerationY(_data.accel_data._y);
+            _sam.updateAccelerationZ(_data.accel_data._z);
+    		_sam.updatePressure(_data.pressure);
+    		_sam.updateAltitude(_data.altitude);
+    		_sam.updateTemperature(_data.temperature);
+    		_sam.updateLight(_data.light);        
+        }
+    }
+}
+
+void ModeDemo::displayHelp() {
+    _help.display();
+    _help.updateMode("LoRa Demo");
+    _help.updateDescription("Select TX Method");
+    _help.updateSw1(" Trigger");
+    _help.updateSw2("Interval");
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Mode/ModeDemo.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,57 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __MODEDEMO_H__
+#define __MODEDEMO_H__
+
+#include "Mode.h"
+#include "LayoutHelp.h"
+#include "LayoutDemoSampling.h"
+
+class ModeDemo : public Mode {
+    public:
+        ModeDemo(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora, GPSPARSER* gps, SensorHandler* sensors);
+        ~ModeDemo();
+
+        bool start();
+
+    private:
+        void displayHelp();
+
+        typedef enum {
+            show_help = 0,
+            sampling,
+            success,
+            failure
+        } state;
+
+        typedef enum {
+            trigger = 0,
+            interval
+        } mode;
+
+        LayoutHelp _help;
+        LayoutDemoSampling _sam;
+        SensorItem _data;
+        mode _mode;
+        Timer _send_timer;
+        uint8_t _interval;
+        static const uint32_t _intervals[];
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Mode/ModeJoin.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,126 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "ModeJoin.h"
+#include "MTSLog.h"
+#include "MTSText.h"
+
+ModeJoin::ModeJoin(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora, GPSPARSER* gps, SensorHandler* sensors)
+  : Mode(lcd, buttons, dot, lora, gps, sensors),
+    _join(lcd, _band),
+    _joined(false)
+{}
+
+ModeJoin::~ModeJoin() {}
+
+bool ModeJoin::start() {
+    bool joining = false;
+
+    // clear any stale signals
+    osSignalClear(_main_id, buttonSignal | loraSignal);
+
+    _initial_data_rate = _dot->getTxDataRate();
+    _initial_power = _dot->getTxPower();
+
+    _data_rate = (_band == mDot::FB_915) ? mDot::SF_10 : mDot::SF_12;
+    _power = 20;
+    _joined = false;
+
+    display();
+
+    _dot->setTxDataRate(_data_rate);
+    _dot->setTxPower(_power);
+    _lora->resetJoinAttempts();
+
+    while (! _joined) {
+        _next_tx = _dot->getNextTxMs();
+        if (! joining && _next_tx > 0) {
+            logInfo("next tx %lu ms", _next_tx);
+            _join.updateStatus("Waiting...");
+            _join.updateCountdown(_next_tx / 1000);
+        } else if (! joining) {
+            logInfo("attempting to join");
+            joining = true;
+            display();
+            _lora->join();
+        }
+
+        osEvent e = Thread::signal_wait(0, 250);
+        if (e.status == osEventSignal) {
+            if (e.value.signals & buttonSignal) {
+                _be = _buttons->getButtonEvent();
+                switch (_be) {
+                    case ButtonHandler::sw1_press:
+                        _dot->setTxDataRate(_initial_data_rate);
+                        _dot->setTxPower(_initial_power);
+                        return false;
+                    case ButtonHandler::sw2_press:
+                        break;
+                    case ButtonHandler::sw1_hold:
+                        _dot->setTxDataRate(_initial_data_rate);
+                        _dot->setTxPower(_initial_power);
+                        return false;
+                }
+            }
+            if (e.value.signals & loraSignal) {
+                _ls = _lora->getStatus();
+                switch (_ls) {
+                    case LoRaHandler::join_success:
+                        _join.updateStatus("Join Success!");
+                        _join.displayCancel(false);
+                        logInfo("joined");
+                        _joined = true;
+                        osDelay(2000);
+                        _dot->setTxDataRate(_initial_data_rate);
+                        _dot->setTxPower(_initial_power);
+                        return true;
+
+                    case LoRaHandler::join_failure:
+                        logInfo("failed to join");
+                        joining = false;
+                        break;
+                }
+            }
+        }
+    }
+
+    _dot->setTxDataRate(_initial_data_rate);
+    _dot->setTxPower(_initial_power);
+    return false;
+}
+
+void ModeJoin::display() {
+    _join.display();
+    _join.updateStatus("Joining...");
+    if (_dot->getJoinMode() == mDot::MANUAL) {
+        _join.updateId(mts::Text::bin2hexString(_dot->getNetworkId()));
+        _join.updateKey(mts::Text::bin2hexString(_dot->getNetworkKey()));
+    } else {
+        _join.updateId(_dot->getNetworkName());
+        _join.updateKey(_dot->getNetworkPassphrase());
+    }
+    if (_band == mDot::FB_915) {
+        _sub_band = _dot->getFrequencySubBand();
+        _join.updateFsb(_sub_band);
+    }
+    // mDot::DataRateStr returns format SF_XX - we only want to display the XX part
+    _join.updateRate(_dot->DataRateStr(_data_rate).substr(3));
+    _join.updatePower(_power);
+    _join.updateAttempt(_lora->getJoinAttempts());
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Mode/ModeJoin.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,39 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __MODEJOIN_H__
+#define __MODEJOIN_H__
+
+#include "Mode.h"
+#include "LayoutJoin.h"
+
+class ModeJoin : public Mode {
+    public:
+        ModeJoin(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora, GPSPARSER* gps, SensorHandler* sensors);
+        ~ModeJoin();
+
+        bool start();
+
+    private:
+        void display();
+
+        LayoutJoin _join;
+        bool _joined;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Mode/ModeSingle.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,355 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "ModeSingle.h"
+#include "MTSLog.h"
+
+ModeSingle::ModeSingle(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora, GPSPARSER* gps, SensorHandler* sensors)
+  : Mode(lcd, buttons, dot, lora, gps, sensors),
+    _help(lcd),
+    _file(lcd),
+    _confirm(lcd),
+    _progress(lcd),
+    _success(lcd),
+    _failure(lcd)
+{}
+
+ModeSingle::~ModeSingle() {}
+
+bool ModeSingle::start() {
+    bool data_file = false;
+    bool send_link_check = false;
+    bool send_data = false;
+    bool no_channel_link_check = false;
+    bool no_channel_data = false;
+
+    // clear any stale signals
+    osSignalClear(_main_id, buttonSignal | loraSignal);
+
+    _initial_data_rate = _dot->getTxDataRate();
+    _initial_power = _dot->getTxPower();
+
+    // see if we're supposed to send the data packet after success
+    // that item is stored in the mDot::StartUpMode config field
+    _send_data = _dot->getStartUpMode();
+
+    // see if survey data file exists
+    std::vector<mDot::mdot_file> files = _dot->listUserFiles();
+    for (std::vector<mDot::mdot_file>::iterator it = files.begin(); it != files.end(); it++) {
+        if (strcmp(it->name, file_name) == 0) {
+            logInfo("found survey data file");
+            data_file = true;
+            break;
+        }
+    }
+    if (data_file) {
+        _state = check_file;
+        _file.display();
+    } else {
+        _state = show_help;
+        _index = 0;
+        displayHelp();
+    }
+
+    while (true) {
+        osEvent e = Thread::signal_wait(0, 250);
+        if (e.status == osEventSignal) {
+            if (e.value.signals & buttonSignal) {
+                _be = _buttons->getButtonEvent();
+
+                switch (_be) {
+                    case ButtonHandler::sw1_press:
+                        switch (_state) {
+                            case check_file:
+                                _state = show_help;
+                                _index = getIndex(single);
+                                displayHelp();
+                                break;
+                            case confirm:
+                                _state = check_file;
+                                _file.display();
+                                break;
+                            case show_help:
+                                incrementRatePower();
+                                _help.updateMsg(formatRatePower());
+                                break;
+                            case success:
+                                incrementRatePower();
+                                _success.updateInfo(formatRatePower());
+                                break;
+                            case failure:
+                                incrementRatePower();
+                                _failure.updateInfo(formatRatePower());
+                                break;
+                        }
+                        break;
+
+                    case ButtonHandler::sw2_press:
+                        switch (_state) {
+                            case check_file:
+                                _state = confirm;
+                                _confirm.display();
+                                break;
+                            case confirm:
+                                _state = show_help;
+                                logInfo("deleting survey data file");
+                                _dot->deleteUserFile(file_name);
+                                _index = 0;
+                                displayHelp();
+                                break;
+                            case show_help:
+                                _state = in_progress;
+                                _progress.display();
+                                if (_dot->getNextTxMs() > 0)
+                                    no_channel_link_check = true;
+                                else 
+                                    send_link_check = true;
+                                break;
+                            case success:
+                                _state = in_progress;
+                                _progress.display();
+                                if (_dot->getNextTxMs() > 0)
+                                    no_channel_link_check = true;
+                                else 
+                                    send_link_check = true;
+                                break;
+                            case failure:
+                                _state = in_progress;
+                                _progress.display();
+                                if (_dot->getNextTxMs() > 0)
+                                    no_channel_link_check = true;
+                                else 
+                                    send_link_check = true;
+                                break;
+                        }
+                        break;
+                    case ButtonHandler::sw1_hold:
+                        _dot->setTxDataRate(_initial_data_rate);
+                        _dot->setTxPower(_initial_power);
+                        return true;
+                }
+            }
+            if (e.value.signals & loraSignal) {
+                _ls = _lora->getStatus();
+                switch (_ls) {
+                    case LoRaHandler::link_check_success:
+                        switch (_state) {
+                            case in_progress:
+                                _link_check_result = _lora->getLinkCheckResults();
+                                displaySuccess();
+                                logInfo("link check successful\tMargin %ld\tRSSI %d dBm\tSNR %2.3f", _link_check_result.up.dBm, _link_check_result.down.rssi, (float)_link_check_result.down.snr / 10.0);
+                                updateData(_data, single, true);
+                                appendDataFile(_data);
+                                if (_send_data) {
+                                    _state = data;
+                                    if (_dot->getNextTxMs() > 0)
+                                        no_channel_data = true;
+                                    else
+                                        send_data = true;
+                                } else {
+                                    _state = success;
+                                    _success.updateSw1("  DR/PWR");
+                                    _success.updateSw2("Survey");
+                                }
+                                break;
+                        }
+                        break;
+
+                    case LoRaHandler::link_check_failure:
+                        switch (_state) {
+                            case in_progress:
+                                _state = failure;
+                                _failure.display();
+                                _failure.updateId(_index);
+                                // mDot::DataRateStr returns format SF_XX - we only want to display the XX part
+                                _failure.updateRate(_dot->DataRateStr(_data_rate).substr(3));
+                                updateData(_data, single, false);
+                                appendDataFile(_data);
+                                _failure.updatePower(_power);
+                                if (_gps_available && _gps->getLockStatus()) {
+                                    GPSPARSER::latitude lat = _gps->getLatitude();
+                                    GPSPARSER::longitude lon = _gps->getLongitude();
+                                    struct tm time = _gps->getTimestamp();
+                                    _failure.updateGpsLatitude(lat);
+                                    _failure.updateGpsLongitude(lon);
+                                    _failure.updateGpsTime(time);
+                                } else {
+                                    _failure.updateGpsLatitude("No GPS Lock");
+                                }
+                                _failure.updateSw1("  DR/PWR");
+                                _failure.updateSw2("Survey");
+                                logInfo("link check failed");
+                                break;
+                        }
+                        break;
+
+                    case LoRaHandler::send_success:
+                        switch (_state) {
+                            case data:
+                                _state = success;
+                                _success.updateInfo("                 ");
+                                _success.updateSw1("  DR/PWR");
+                                _success.updateSw2("Survey");
+                                // turn acks and receive windows back on
+                                _dot->setAck(1);
+                                _dot->setTxWait(true);
+                                logInfo("data send success");
+                                break;
+                        }
+                        break;
+
+                    case LoRaHandler::send_failure:
+                        switch (_state) {
+                            case data:
+                                _state = success;
+                                _success.updateInfo("                 ");
+                                _success.updateSw1("  DR/PWR");
+                                _success.updateSw2("Survey");
+                                // turn acks and receive windows back on
+                                _dot->setAck(1);
+                                _dot->setTxWait(true);
+                                logInfo("data send failed");
+                                break;
+                        }
+                        break;
+                }
+            }
+        }
+
+        if (no_channel_link_check) {
+            uint32_t t = _dot->getNextTxMs();
+            if (t > 0) {
+                logInfo("next tx %lu ms", t);
+                _progress.updateCountdown(t / 1000);
+            } else {
+                _progress.display();
+                no_channel_link_check = false;
+                send_link_check = true;
+            }
+        }
+        if (no_channel_data) {
+            uint32_t t = _dot->getNextTxMs();
+            if (t > 0) {
+                logInfo("next tx %lu ms", t);
+                _success.updateCountdown(t / 1000);
+            } else {
+                displaySuccess();
+                no_channel_data = false;
+                send_data = true;
+            }
+        }
+        if (send_link_check) {
+            logInfo("sending link check %s %d", _dot->DataRateStr(_data_rate).c_str(), _power);
+            send_link_check = false;
+            _dot->setTxDataRate(_data_rate);
+            _dot->setTxPower(_power);
+            _lora->linkCheck();
+            _index++;
+        }
+        if (send_data) {
+            std::vector<uint8_t> s_data = formatSurveyData(_data);
+            logInfo("sending data %s %d", _dot->DataRateStr(_data_rate).c_str(), _power);
+            send_data = false;
+            _success.updateInfo("Data Sending...");
+            _dot->setTxDataRate(_data_rate);
+            _dot->setTxPower(_power);
+            // we don't care if the server actually gets this packet or not
+            // we won't retry anyway
+            _dot->setAck(0);
+            _dot->setTxWait(false);
+            _lora->send(s_data);
+            osDelay(500);
+        }
+    }
+}
+
+void ModeSingle::displayHelp() {
+    _help.display();
+    _help.updateMode("Survey Single");
+    _help.updateSw1("  DR/PWR");
+    _help.updateSw2("Survey");
+    _help.updateMsg(formatRatePower());
+}
+
+void ModeSingle::displaySuccess() {
+    uint8_t fix = _gps->getFixStatus();
+    _success.display();
+    _success.updateId(_index);
+    // mDot::DataRateStr returns format SF_XX - we only want to display the XX part
+    _success.updateRate(_dot->DataRateStr(_data_rate).substr(3));
+    _success.updatePower(_power);
+    _success.updateStats(_link_check_result);
+    if (_gps_available && _gps->getLockStatus()) {
+        GPSPARSER::latitude lat = _gps->getLatitude();
+        GPSPARSER::longitude lon = _gps->getLongitude();
+        struct tm time = _gps->getTimestamp();
+        _success.updateGpsLatitude(lat);
+        _success.updateGpsLongitude(lon);
+        _success.updateGpsTime(time);
+    } else {
+        _success.updateGpsLatitude("No GPS Lock");
+    }
+}
+
+std::string ModeSingle::formatRatePower() {
+    std::string msg;
+    char buf[8];
+    size_t size;
+
+    msg += "DR=";
+    msg += _dot->DataRateStr(_data_rate).substr(3);
+    msg += " P=";
+    size = snprintf(buf, sizeof(buf), "%u", _power);
+    msg.append(buf, size);
+
+    return msg;
+}
+
+void ModeSingle::incrementRatePower() {
+    if (_power == 20) {
+        _power = 2;
+        switch (_data_rate) {
+            case mDot::SF_7:
+                _data_rate = mDot::SF_8;
+                break;
+            case mDot::SF_8:
+                _data_rate = mDot::SF_9;
+                break;
+            case mDot::SF_9:
+                _data_rate = mDot::SF_10;
+                break;
+            case mDot::SF_10:
+                if (_band == mDot::FB_915)
+                    _data_rate = mDot::SF_7;
+                else
+                    _data_rate = mDot::SF_11;
+                break;
+            case mDot::SF_11:
+                _data_rate = mDot::SF_12;
+                break;
+            case mDot::SF_12:
+                _data_rate = mDot::SF_7;
+                break;
+        }
+    } else {
+        _power += 3;
+    }
+
+    logInfo("new data rate %s, power %lu", mDot::DataRateStr(_data_rate).c_str(), _power);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Mode/ModeSingle.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,62 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __MODESINGLE_H__
+#define __MODESINGLE_H__
+
+#include "Mode.h"
+#include "LayoutHelp.h"
+#include "LayoutFile.h"
+#include "LayoutConfirm.h"
+#include "LayoutSurveyProgress.h"
+#include "LayoutSurveySuccess.h"
+#include "LayoutSurveyFailure.h"
+
+class ModeSingle : public Mode {
+    public:
+        ModeSingle(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora, GPSPARSER* gps, SensorHandler* sensors);
+        ~ModeSingle();
+
+        bool start();
+
+    private:
+        void displayHelp();
+        void displaySuccess();
+        std::string formatRatePower();
+        void incrementRatePower();
+
+        typedef enum {
+            check_file = 0,
+            confirm,
+            show_help,
+            in_progress,
+            success,
+            data,
+            failure
+        } state;
+
+        LayoutHelp _help;
+        LayoutFile _file;
+        LayoutConfirm _confirm;
+        LayoutSurveyProgress _progress;
+        LayoutSurveySuccess _success;
+        LayoutSurveyFailure _failure;
+        DataItem _data;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Mode/ModeSweep.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,405 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "ModeSweep.h"
+#include "MTSLog.h"
+
+ModeSweep::ModeSweep(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora, GPSPARSER* gps, SensorHandler* sensors)
+  : Mode(lcd, buttons, dot, lora, gps, sensors),
+    _help(lcd),
+    _file(lcd),
+    _confirm(lcd),
+    _progress(lcd),
+    _success(lcd),
+    _failure(lcd),
+    _complete(lcd)
+{}
+
+ModeSweep::~ModeSweep() {}
+
+bool ModeSweep::start() {
+    bool data_file = false;
+    bool send_link_check = false;
+    bool send_data = false;
+    bool no_channel_link_check = false;
+    bool no_channel_data = false;
+
+    // clear any stale signals
+    osSignalClear(_main_id, buttonSignal | loraSignal);
+
+    _initial_data_rate = _dot->getTxDataRate();
+    _initial_power = _dot->getTxPower();
+
+    // see if we're supposed to send the data packet after success
+    // that item is stored in the mDot::StartUpMode config field
+    _send_data = _dot->getStartUpMode();
+
+    // pull the minimum and maximum payload size out of config
+    // min payload size is wake interval
+    // max payload size is wake delay
+    _min_payload = _dot->getWakeInterval();
+    _max_payload = _dot->getWakeDelay();
+
+    // pull the minimum and maximum power out of config
+    // min power is wake timeout
+    // max power is wake mode
+    _min_power = _dot->getWakeTimeout();
+    _max_power = _dot->getWakeMode();
+    
+    // compute the total number of surveys we will do
+    _points = generatePoints();
+    _survey_total = _points.size();
+    _survey_current = 1;
+    _survey_success = 0;
+    _survey_failure = 0;
+
+    // see if survey data file exists
+    std::vector<mDot::mdot_file> files = _dot->listUserFiles();
+    for (std::vector<mDot::mdot_file>::iterator it = files.begin(); it != files.end(); it++) {
+        if (strcmp(it->name, file_name) == 0) {
+            logInfo("found survey data file");
+            data_file = true;
+            break;
+        }
+    }
+    if (data_file) {
+        _state = check_file;
+        _file.display();
+    } else {
+        _state = show_help;
+        _index = 1;
+        displayHelp();
+    }
+
+    _display_timer.reset();
+
+    while (true) {
+        osEvent e = Thread::signal_wait(0, 250);
+        if (e.status == osEventSignal) {
+            if (e.value.signals & buttonSignal) {
+                _be = _buttons->getButtonEvent();
+
+                switch (_be) {
+                    case ButtonHandler::sw1_press:
+                        switch (_state) {
+                            case check_file:
+                                _state = show_help;
+                                _index = getIndex(sweep) + 1;
+                                displayHelp();
+                                break;
+                            case confirm:
+                                _state = check_file;
+                                _file.display();
+                                break;
+                            case success:
+                                _state = complete;
+                                _display_timer.stop();
+                                _display_timer.reset();
+                                logInfo("sweep finished");
+                                _complete.display();
+                                _complete.updateId(_index++);
+                                _complete.updatePass(_survey_success);
+                                _complete.updateFail(_survey_failure);
+                                _survey_success = 0;
+                                _survey_failure = 0;
+                                break;
+                            case failure:
+                                _state = complete;
+                                _display_timer.stop();
+                                _display_timer.reset();
+                                logInfo("sweep finished");
+                                _complete.display();
+                                _complete.updateId(_index++);
+                                _complete.updatePass(_survey_success);
+                                _complete.updateFail(_survey_failure);
+                                _survey_success = 0;
+                                _survey_failure = 0;
+                                break;
+                        }
+                        break;
+
+                    case ButtonHandler::sw2_press:
+                        switch (_state) {
+                            case check_file:
+                                _state = confirm;
+                                _confirm.display();
+                                break;
+                            case confirm:
+                                _state = show_help;
+                                logInfo("deleting survey data file");
+                                _dot->deleteUserFile(file_name);
+                                _index = 1;
+                                displayHelp();
+                                break;
+                            case show_help:
+                                _state = in_progress;
+                                _progress.display();
+                                _progress.updateProgress(_survey_current, _survey_total);
+                                if (_dot->getNextTxMs() > 0)
+                                    no_channel_link_check = true;
+                                else
+                                    send_link_check = true;
+                                break;
+                            case complete:
+                                _state = in_progress;
+                                _survey_current = 1;
+                                _progress.display();
+                                _progress.updateProgress(_survey_current, _survey_total);
+                                if (_dot->getNextTxMs() > 0)
+                                    no_channel_link_check = true;
+                                else
+                                    send_link_check = true;
+                                break;
+                        }
+                        break;
+                    case ButtonHandler::sw1_hold:
+                        _dot->setTxDataRate(_initial_data_rate);
+                        _dot->setTxPower(_initial_power);
+                        return true;
+                }
+            }
+            if (e.value.signals & loraSignal) {
+                _ls = _lora->getStatus();
+                switch (_ls) {
+                    case LoRaHandler::link_check_success:
+                        switch (_state) {
+                            case in_progress:
+                                _survey_success++;
+                                _link_check_result = _lora->getLinkCheckResults();
+                                displaySuccess();
+                                logInfo("link check successful\tMargin %ld\tRSSI %d dBm\tSNR %2.3f", _link_check_result.up.dBm, _link_check_result.down.rssi, (float)_link_check_result.down.snr / 10.0);
+                                updateData(_data, sweep, true);
+                                appendDataFile(_data);
+                                if (_send_data) {
+                                    _state = data;
+                                    if (_dot->getNextTxMs() > 0)
+                                        no_channel_data = true;
+                                    else
+                                        send_data = true;
+                                } else {
+                                    _state = success;
+                                    _success.updateSw1("  Cancel");
+                                    _display_timer.start();
+                                }
+                                break;
+                        }
+                        break;
+
+                    case LoRaHandler::link_check_failure:
+                        switch (_state) {
+                            case in_progress:
+                                _survey_failure++;
+                                _state = failure;
+                                _failure.display();
+                                _failure.updateId(_index);
+                                // mDot::DataRateStr returns format SF_XX - we only want to display the XX part
+                                _failure.updateRate(_dot->DataRateStr(_data_rate).substr(3));
+                                _failure.updatePower(_power);
+                                if (_gps_available && _gps->getLockStatus()) {
+                                    GPSPARSER::latitude lat = _gps->getLatitude();
+                                    GPSPARSER::longitude lon = _gps->getLongitude();
+                                    _failure.updateGpsLatitude(lat);
+                                    _failure.updateGpsLongitude(lon);
+                                } else {
+                                    _failure.updateGpsLatitude("No GPS Lock");
+                                }
+                                _failure.updatePassFail(_survey_success, _survey_failure);
+                                _failure.updateSw1("  Cancel");
+                                updateData(_data, sweep, false);
+                                appendDataFile(_data);
+                                logInfo("link check failed");
+                                _display_timer.start();
+                                break;
+                        }
+                        break;
+
+                    case LoRaHandler::send_success:
+                        switch (_state) {
+                            case data:
+                                _state = success;
+                                _success.updateInfo("                 ");
+                                _success.updateSw1("  Cancel");
+                                logInfo("data send success");
+                                // turn acks and receive windows back on
+                                _dot->setAck(1);
+                                _dot->setTxWait(true);
+                                _display_timer.start();
+                                break;
+                        }
+                        break;
+
+                    case LoRaHandler::send_failure:
+                        switch (_state) {
+                            case data:
+                                _state = success;
+                                _success.updateInfo("                 ");
+                                _success.updateSw1("  Cancel");
+                                logInfo("data send failed");
+                                // turn acks and receive windows back on
+                                _dot->setAck(1);
+                                _dot->setTxWait(true);
+                                _display_timer.start();
+                                break;
+                        }
+                        break;
+                }
+            }
+        }
+
+        // wait 5s in EU mode to compensate for potential "no free channel" situations on server
+        if ((_band == mDot::FB_915 && _display_timer.read_ms() > 2000) || _display_timer.read_ms() > 5000) {
+            _display_timer.stop();
+            _display_timer.reset();
+            if (_survey_current == _survey_total) {
+                logInfo("sweep finished");
+                _state = complete;
+                _complete.display();
+                _complete.updateId(_index++);
+                _complete.updatePass(_survey_success);
+                _complete.updateFail(_survey_failure);
+                _survey_success = 0;
+                _survey_failure = 0;
+            } else {
+                logInfo("starting next link check");
+                _state = in_progress;
+                _survey_current++;
+                _progress.display();
+                _progress.updateProgress(_survey_current, _survey_total);
+                no_channel_link_check = true;
+            }
+        }
+
+        if (no_channel_link_check) {
+            uint32_t t = _dot->getNextTxMs();
+            if (t > 0) {
+                logInfo("next tx %lu ms", t);
+                _progress.updateCountdown(t / 1000);
+            } else {
+                _progress.display();
+                _progress.updateProgress(_survey_current, _survey_total);
+                no_channel_link_check = false;
+                send_link_check = true;
+            }
+        }
+        if (no_channel_data) {
+            uint32_t t = _dot->getNextTxMs();
+            if (t > 0) {
+                logInfo("next tx %lu ms", t);
+                _success.updateCountdown(t / 1000);
+            } else {
+                displaySuccess();
+                no_channel_data = false;
+                send_data = true;
+            }
+        }
+        if (send_link_check) {
+            point p = _points[_survey_current - 1];
+            _data_rate = p.first;
+            _power = p.second;
+            logInfo("sending link check %s %d", _dot->DataRateStr(_data_rate).c_str(), _power);
+            send_link_check = false;
+            _dot->setTxDataRate(_data_rate);
+            _dot->setTxPower(_power);
+            _lora->linkCheck();
+        }
+        if (send_data) {
+            std::vector<uint8_t> s_data = formatSurveyData(_data);
+            logInfo("sending data %s %d", _dot->DataRateStr(_data_rate).c_str(), _power);
+            send_data = false;
+            _success.updateInfo("Data Sending...");
+            _dot->setTxDataRate(_data_rate);
+            _dot->setTxPower(_power);
+            // we don't care if the server actually gets this packet or not
+            // we won't retry anyway
+            _dot->setAck(0);
+            _dot->setTxWait(false);
+            _lora->send(s_data);
+            osDelay(500);
+        }
+    }
+}
+
+void ModeSweep::displayHelp() {
+    _help.display();
+    _help.updateMode("Survey Sweep");
+    _help.updateSw2("Sweep");
+}
+
+void ModeSweep::displaySuccess() {
+    _success.display();
+    _success.updateId(_index);
+    // mDot::DataRateStr returns format SF_XX - we only want to display the XX part
+    _success.updateRate(_dot->DataRateStr(_data_rate).substr(3));
+    _success.updatePower(_power);
+    _success.updateStats(_link_check_result);
+    if (_gps_available && _gps->getLockStatus()) {
+        GPSPARSER::latitude lat = _gps->getLatitude();
+        GPSPARSER::longitude lon = _gps->getLongitude();
+        _success.updateGpsLatitude(lat);
+        _success.updateGpsLongitude(lon);
+    } else {
+        _success.updateGpsLatitude("No GPS Lock");
+    }
+    _success.updatePassFail(_survey_success, _survey_failure);
+}
+
+std::vector<point> ModeSweep::generatePoints() {
+    std::vector<point> p;
+    uint8_t min_rate;
+    uint8_t max_rate;
+
+    max_rate = payloadToRate(_min_payload);
+    min_rate = payloadToRate(_max_payload);
+
+    for (int rate = min_rate; rate >= max_rate; rate--) {
+        if (_max_power - _min_power < 4) {
+            for (uint32_t power = _min_power; power <= _max_power; power++)
+                p.push_back(std::make_pair(rate, power));
+        } else {
+            p.push_back(std::make_pair(rate, _min_power));
+            p.push_back(std::make_pair(rate, (uint32_t)ceil( (float(_max_power) - float(_min_power)) * 0.33 + float(_min_power))));
+            p.push_back(std::make_pair(rate, (uint32_t)ceil( (float(_max_power) - float(_min_power)) * 0.66 + float(_min_power))));
+            p.push_back(std::make_pair(rate, _max_power));
+        }
+    }
+
+    return p;
+}
+
+uint8_t ModeSweep::payloadToRate(uint8_t payload) {
+    if (_band == mDot::FB_915) {
+        if (payload <= mDot::MaxLengths_915[mDot::SF_10])
+            return mDot::SF_10;
+        else if (payload <= mDot::MaxLengths_915[mDot::SF_9])
+            return mDot::SF_9;
+        else if (payload <= mDot::MaxLengths_915[mDot::SF_8])
+            return mDot::SF_8;
+        else
+            return mDot::SF_7;
+    } else {
+        if (payload <= mDot::MaxLengths_868[mDot::SF_12])
+            return mDot::SF_12;
+        else if (payload <= mDot::MaxLengths_868[mDot::SF_9])
+            return mDot::SF_9;
+        else
+            return mDot::SF_7;
+    }
+
+    return mDot::SF_7;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Mode/ModeSweep.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,78 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __MODESWEEP_H__
+#define __MODESWEEP_H__
+
+#include "Mode.h"
+#include "LayoutHelp.h"
+#include "LayoutFile.h"
+#include "LayoutConfirm.h"
+#include "LayoutSweepProgress.h"
+#include "LayoutSurveySuccess.h"
+#include "LayoutSurveyFailure.h"
+#include "LayoutSweepComplete.h"
+
+typedef std::pair<uint8_t, uint32_t> point;
+
+class ModeSweep : public Mode {
+    public:
+        ModeSweep(DOGS102* lcd, ButtonHandler* buttons, mDot* dot, LoRaHandler* lora, GPSPARSER* gps, SensorHandler* sensors);
+        ~ModeSweep();
+
+        bool start();
+
+    private:
+        void displayHelp();
+        void displaySuccess();
+        std::vector<point> generatePoints();
+        uint8_t payloadToRate(uint8_t payload);
+
+        typedef enum {
+            check_file = 0,
+            confirm,
+            show_help,
+            in_progress,
+            success,
+            data,
+            failure,
+            complete
+        } state;
+
+        LayoutHelp _help;
+        LayoutFile _file;
+        LayoutConfirm _confirm;
+        LayoutSweepProgress _progress;
+        LayoutSurveySuccess _success;
+        LayoutSurveyFailure _failure;
+        LayoutSweepComplete _complete;
+        DataItem _data;
+
+        uint8_t _min_payload;
+        uint8_t _max_payload;
+        uint32_t _min_power;
+        uint32_t _max_power;
+        uint8_t _survey_current;
+        uint8_t _survey_total;
+        uint8_t _survey_success;
+        uint8_t _survey_failure;
+        std::vector<point> _points;
+        Timer _display_timer;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SensorHandler/SensorHandler.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,224 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file    SensorHandler.cpp
+ * @brief   Reads on board sensors... acceleration, pressure, light and temperture.
+ * @author  Leon Lindenfelser
+ * @version 1.0
+ *
+ */
+
+#include "SensorHandler.h"
+
+SensorHandler::SensorHandler()
+  : _getSensorThread(&SensorHandler::startSensorThread, this),
+    _mDoti2c(PC_9,PA_8),
+	_accelerometer(_mDoti2c,MMA845x::SA0_VSS),
+	_barometricSensor(_mDoti2c),
+	_lightSensor(_mDoti2c)
+{
+    SensorHandler::initSensors();
+    _getSensorThread.signal_set(START_THREAD);
+    return;
+}
+
+SensorHandler::~SensorHandler(void)
+{
+    _getSensorThread.terminate();
+}     
+
+void SensorHandler::initSensors(){
+    //  Setup the Accelerometer for 8g range, 14 bit resolution, Noise reduction off, sample rate 1.56 Hz
+    //  normal oversample mode, High pass filter off
+    _accelerometer.setCommonParameters(MMA845x::RANGE_8g,MMA845x::RES_MAX,MMA845x::LN_OFF,
+    						   MMA845x::DR_6_25,MMA845x::OS_NORMAL,MMA845x::HPF_OFF );
+	 
+    // Setup the Barometric sensor for post processed Ambient pressure, 4 samples per data acquisition.
+    //and a sample taken every second when in active mode
+    _barometricSensor.setParameters(MPL3115A2::DATA_NORMAL, MPL3115A2::DM_BAROMETER, MPL3115A2::OR_16,
+    					MPL3115A2::AT_1);
+    // Setup the Ambient Light Sensor for continuous Ambient Light Sensing, 16 bit resolution,
+    // and 16000 lux range
+    _lightSensor.setMode(ISL29011::ALS_CONT);
+    _lightSensor.setResolution(ISL29011::ADC_16BIT);
+    _lightSensor.setRange(ISL29011::RNG_16000);
+	 
+    // Set the accelerometer for active mode
+    _accelerometer.activeMode();
+	 
+    // Clear the min-max registers in the Barometric Sensor
+    _barometricSensor.clearMinMaxRegs();    
+}
+
+void SensorHandler::startSensorThread(void const *p)
+{
+    SensorHandler *instance = (SensorHandler*)p;
+    instance->readSensors();
+}
+
+void SensorHandler::readSensors()
+{
+    uint8_t result;
+    Timer timer;
+    timer.start();
+    
+    _getSensorThread.signal_wait(START_THREAD);
+    while(1){
+        // Test Accelerometer XYZ data ready bit to see if acquisition complete
+        timer.reset();
+        do {
+            osDelay(20);			 // allows other threads to process
+            result = _accelerometer.getStatus();
+            if((result & MMA845x::XYZDR) != 0 ){
+                // Retrieve accelerometer data
+                _mutex.lock();        
+                _accelerometerData = _accelerometer.getXYZ();
+                _mutex.unlock();
+            }
+        } while (((result & MMA845x::XYZDR) == 0 ) && (timer.read_ms() < 1000));
+
+	 
+        // Trigger a Pressure reading
+        _barometricSensor.setParameters(MPL3115A2::DATA_NORMAL, MPL3115A2::DM_BAROMETER, MPL3115A2::OR_16,
+									MPL3115A2::AT_1);
+        _barometricSensor.triggerOneShot();
+	 
+        // Test barometer device status to see if acquisition is complete
+        timer.reset();
+        do {
+            osDelay(20);			 // allows other threads to process
+            result = _barometricSensor.getStatus();
+            if((result & MPL3115A2::PTDR) != 0){
+                // Retrieve barometric pressure
+                _mutex.lock();        
+                _pressure = _barometricSensor.getBaroData() >> 12; // convert 32 bit signed to 20 bit unsigned value
+                _mutex.unlock();                
+            }
+        } while (((result & MPL3115A2::PTDR) == 0) && (timer.read_ms() < 100));
+
+        
+        // Trigger an Altitude reading
+        _barometricSensor.setParameters(MPL3115A2::DATA_NORMAL, MPL3115A2::DM_ALTIMETER, MPL3115A2::OR_16,
+        					MPL3115A2::AT_1);
+        _barometricSensor.triggerOneShot();
+	 
+        // Test barometer device status to see if acquisition is complete
+        timer.reset();
+        do {
+            osDelay(20);			 // allows other threads to process
+            result = _barometricSensor.getStatus();
+            if((result & MPL3115A2::PTDR) != 0 ){
+                // Retrieve temperature and altitude.
+                _mutex.lock();
+                _barometerData = _barometricSensor.getAllData(false);
+                _mutex.unlock();                 
+            }
+        } while (((result & MPL3115A2::PTDR) == 0 ) && (timer.read_ms() < 100));
+	 
+        // Retrieve light level
+        _mutex.lock();
+        _light = _lightSensor.getData();
+        _mutex.unlock();
+        osDelay(100);             // allows other threads to process
+    }
+}
+
+MMA845x_DATA SensorHandler::getAcceleration(){
+    MMA845x_DATA data;
+    _mutex.lock();
+    data = _accelerometerData;
+    _mutex.unlock();
+    return data;
+}
+
+float SensorHandler::getLight(){
+    float light;
+    uint16_t whole;
+    _mutex.lock();
+    whole = _light;
+    _mutex.unlock();
+    light = whole * 24 % 100;
+    light /= 100;
+    light = light + (whole * 24 / 100);       // 16000 lux full scale .24 lux per bit
+    return light; 
+}
+
+uint16_t SensorHandler::getLightRaw(){
+    uint16_t light;
+    _mutex.lock();
+    light = _light;
+    _mutex.unlock();
+    return light; 
+}
+
+float SensorHandler::getPressure(){
+    float pressure;
+    uint32_t whole;
+    _mutex.lock();
+    whole = _pressure;
+    _mutex.unlock();
+    pressure = (whole & 3) * .25;
+    pressure = pressure + (whole >> 2);
+    return pressure;    
+}
+
+uint32_t SensorHandler::getPressureRaw(){
+    uint32_t pressure;
+    _mutex.lock();
+    pressure = _pressure;
+    _mutex.unlock();
+    return pressure;    
+}
+
+float SensorHandler::getTemp(Scale scale){
+    float temperature;
+    uint16_t whole;
+    _mutex.lock();
+    whole = _barometerData._temp;    
+    _mutex.unlock();
+    temperature = whole & 0x0f;
+    temperature *= .0625;
+    temperature += (whole >> 4);
+    if(scale == FAHRENHEIT){
+        temperature = temperature * 1.8 + 32;
+    }
+    return temperature;
+}
+
+float SensorHandler::getAltitude(){
+    float altitude;
+    uint32_t whole;
+    _mutex.lock();
+    whole = _barometerData._baro;    
+    _mutex.unlock();
+    whole /= 4096;
+    altitude = (whole & 0x0f) * .0625;
+    whole /= 16;
+    altitude += whole;
+    return altitude;
+}
+
+MPL3115A2_DATA SensorHandler::getBarometer(){
+    MPL3115A2_DATA data;
+    _mutex.lock();
+    data = _barometerData;
+    _mutex.unlock();
+    return data;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SensorHandler/SensorHandler.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,71 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file    SensorHandler.h
+ * @brief   Reads on board sensors... acceleration, pressure, light and temperture.
+ * @author  Leon Lindenfelser
+ * @version 1.0
+ *
+ */
+
+#ifndef SENSORHANDLER_H
+#define SENSORHANDLER_H
+
+#include "mbed.h"
+#include "MMA845x.h"
+#include "MPL3115A2.h"
+#include "ISL29011.h"
+#include "DOGS102.h"
+#include "rtos.h"
+#include <string>
+#include <vector>
+#define START_THREAD 1
+
+class SensorHandler
+{
+public:
+    enum Scale{CELSIUS, FAHRENHEIT};
+    SensorHandler(void);
+    ~SensorHandler(void);
+    MMA845x_DATA getAcceleration(void);
+    float getLight(void);
+    uint16_t getLightRaw(void);
+    float getPressure(void);
+    uint32_t getPressureRaw(void);
+    float getTemp(Scale);
+    float getAltitude(void);
+    MPL3115A2_DATA getBarometer(void);
+		
+private:
+    Thread _getSensorThread;
+    static void startSensorThread (void const *p);	
+    void readSensors(void);
+    void initSensors(void);	
+    I2C _mDoti2c;
+    MMA845x _accelerometer;
+    MPL3115A2 _barometricSensor;
+    ISL29011 _lightSensor;
+    MMA845x_DATA _accelerometerData;
+    MPL3115A2_DATA _barometerData;
+    uint16_t _light;
+    uint32_t _pressure;
+    Mutex _mutex;	
+};
+	
+#endif //SENSORHANDLER_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/license.txt	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,18 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,202 @@
+/* Copyright (c) <2016> <MultiTech Systems>, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
+ * and associated documentation files (the "Software"), to deal in the Software without restriction, 
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or 
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+// mbed headers
+#include "mbed.h"
+#include "rtos.h"
+// MTS headers
+#include "mDot.h"
+#include "MTSLog.h"
+// display headers
+#include "DOGS102.h"
+#include "NCP5623B.h"
+#include "LayoutStartup.h"
+#include "LayoutScrollSelect.h"
+#include "LayoutConfig.h"
+#include "LayoutHelp.h"
+// button header
+#include "ButtonHandler.h"
+// LoRa header
+#include "LoRaHandler.h"
+// Sensor header
+#include "SensorHandler.h"
+// mode objects
+#include "ModeJoin.h"
+#include "ModeSingle.h"
+#include "ModeSweep.h"
+#include "ModeDemo.h"
+#include "ModeConfig.h"
+// misc heders
+#include "FileName.h"
+#include <string>
+
+// LCD and LED controllers
+SPI lcd_spi(SPI1_MOSI, SPI1_MISO, SPI1_SCK);
+I2C led_i2c(I2C_SDA, I2C_SCL);
+DigitalOut lcd_spi_cs(SPI1_CS, 1);
+DigitalOut lcd_cd(XBEE_ON_SLEEP, 1);
+DOGS102* lcd;
+NCP5623B* led_cont;
+
+// Thread informaiton
+osThreadId main_id;
+
+// Button controller
+ButtonHandler* buttons;
+
+// LoRa controller
+LoRaHandler* lora;
+mDot* dot;
+
+// GPS
+GPSPARSER* gps;
+MTSSerial gps_serial(XBEE_DOUT, XBEE_DIN, 256, 2048);
+
+// Sensors
+SensorHandler* sensors;
+
+// Modes
+ModeJoin* modeJoin;
+ModeSingle* modeSingle;
+ModeSweep* modeSweep;
+ModeDemo* modeDemo;
+ModeConfig* modeConfig;
+
+// Serial debug port
+Serial debug(USBTX, USBRX);
+
+// Survey Data File
+char* file_name;
+
+// Prototypes
+void mainMenu();
+
+int main() {
+    debug.baud(115200);
+    file_name = "SurveyData.txt";
+
+    lcd = new DOGS102(lcd_spi, lcd_spi_cs, lcd_cd);
+    // NCP5623B::LEDs 1 & 2 are the screen backlight - not used on default build
+    // NCP5623B::LED3 is EVB LED2
+    led_cont = new NCP5623B(led_i2c);
+
+    main_id = Thread::gettid();
+    buttons = new ButtonHandler(main_id);
+    dot = mDot::getInstance();
+    lora = new LoRaHandler(main_id);
+    gps = new GPSPARSER(&gps_serial, led_cont);
+    sensors = new SensorHandler();
+
+    led_cont->setLEDCurrent(16);
+
+    MTSLog::setLogLevel(MTSLog::TRACE_LEVEL);
+
+    modeJoin = new ModeJoin(lcd, buttons, dot, lora, gps, sensors);
+    modeSingle = new ModeSingle(lcd, buttons, dot, lora, gps, sensors);
+    modeSweep = new ModeSweep(lcd, buttons, dot, lora, gps, sensors);
+    modeDemo = new ModeDemo(lcd, buttons, dot, lora, gps, sensors);
+    modeConfig = new ModeConfig(lcd, buttons, dot, lora, gps, sensors);
+
+    osDelay(1000);
+    logInfo("%sGPS detected", gps->gpsDetected() ? "" : "no ");
+
+    // display startup screen for 3 seconds
+    LayoutStartup ls(lcd, dot);
+    ls.display();
+    ls.updateGPS(gps->gpsDetected());
+    osDelay(3000);
+
+    logInfo("displaying main menu");
+    mainMenu();
+
+    return 0;
+}
+
+void mainMenu() {
+    bool mode_selected = false;
+    std::string selected;
+    std::string product;
+    
+    typedef enum {
+        demo = 1,
+        config,
+        single,
+        sweep
+    } menu_items;
+
+    std::string menu_strings[] = {
+        "Select Mode",
+        "LoRa Demo",
+        "Configuration",
+        "Survey Single",
+        "Survey Sweep"
+    };
+
+    std::vector<std::string> items;
+    items.push_back(menu_strings[demo]);
+    items.push_back(menu_strings[config]);
+    items.push_back(menu_strings[single]);
+    items.push_back(menu_strings[sweep]);
+
+    while (true) {
+        product = "MTDOT-BOX/EVB ";
+        product += mDot::FrequencyBandStr(dot->getFrequencyBand()).substr(3);
+
+        // reset session between modes
+        dot->resetNetworkSession();
+        lora->resetActivityLed();
+        LayoutScrollSelect menu(lcd, items, product, menu_strings[0]);
+        menu.display();
+
+        while (! mode_selected) {
+            osEvent e = Thread::signal_wait(buttonSignal);
+            if (e.status == osEventSignal) {
+                ButtonHandler::ButtonEvent ev = buttons->getButtonEvent();
+                switch (ev) {
+                    case ButtonHandler::sw1_press:
+                        selected = menu.select();
+                        mode_selected = true;
+                        break;
+                    case ButtonHandler::sw2_press:
+                        menu.scroll();
+                        break;
+                    case ButtonHandler::sw1_hold:
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+
+        if (selected == menu_strings[demo]) {
+            if (modeJoin->start())
+                modeDemo->start();
+        } else if (selected == menu_strings[config]) {
+            modeConfig->start();
+        } else if (selected == menu_strings[single]) {
+            if (modeJoin->start())
+                modeSingle->start();
+        } else if (selected == menu_strings[sweep]) {
+            if (modeJoin->start())
+                modeSweep->start();
+        }
+
+        mode_selected = false;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/version.h	Thu Feb 04 12:36:36 2016 -0600
@@ -0,0 +1,6 @@
+#ifndef __VERSION_H__
+#define __VERSION_H__
+
+#define MTDOT_BOX_VERSION "2.0.0"
+
+#endif