Bleeding edge development version of the xDot library for mbed 5. This version of the library is not guaranteed to be stable or well tested and should not be used in production or deployment scenarios.

Dependents:   Dot-Examples Dot-AT-Firmware Dot-Examples TEST_FF1705 ... more

The Dot library provides a LoRaWan certified stack for LoRa communication using MultiTech mDot and xDot devices. The stack is compatible with mbed 5.

Dot Library Version 3 Updates

Dot Library versions 3.x.x require a channel plan to be injected into the stack. Channel plans are included with the 3.x.x Dot Library releases. The following code snippet demonstrates how to create a channel plan and inject it into the stack.

#include "mDot.h"
#include "channel_plans.h"

int main() {
    ChannelPlan* plan = new lora::ChannelPlan_US915();
    assert(plan);
    mDot* dot = mDot::getInstance(plan);
    assert(dot);

    // ...
}

Dot devices must not be deployed with software using a different channel plan than the Dot's default plan! This functionality is for development and testing only!

Multicast Sessions

Multicast sessions and packet rx events in library. When in Class C mode Multicast downlinks can be received. Recieved packets should be filtered on address, counter value will be maintained in the session or can be set explicitly depending on Application support to share Multicast Address, Keys and Counters.

mDot.h

        /**
         * Add a multicast session address and keys
         * Downlink counter is set to 0
         * Up to 3 MULTICAST_SESSIONS can be set
         */
        int32_t setMulticastSession(uint8_t index, uint32_t addr, const uint8_t* nsk, const uint8_t* dsk);
 
        /**
         * Set a multicast session counter
         * Up to 3 MULTICAST_SESSIONS can be set
         */
        int32_t setMulticastDownlinkCounter(uint8_t index, uint32_t count);

mDotEvent.h

The address field was added to PacketRx event.

        virtual void PacketRx(uint8_t port, uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr, lora::DownlinkControl ctrl, uint8_t slot, uint8_t retries, uint32_t address);

The name of the repository can be used to determine which device the stack was compiled for and if it's a development or production-ready build:

A changelog for the Dot library can be found here.

The Dot library version and the version of mbed-os it was compiled against can both be found in the commit message for that revision of the Dot library. Building your application with the same version of mbed-os as what was used to build the Dot library is highly recommended!

The Dot-Examples repository demonstrates how to use the Dot library in a custom application.

The mDot and xDot platform pages have lots of platform specific information and document potential issues, gotchas, etc, and provide instructions for getting started with development. Please take a look at the platform page before starting development as they should answer many questions you will have.

Files at this revision

API Documentation at this revision

Comitter:
Jenkins@KEILDM1.dc.multitech.prv
Date:
Thu Sep 22 16:29:07 2016 -0500
Parent:
1:f195464cece7
Child:
3:8758ed4bd7bd
Commit message:
update from git revision 2.0.12

Changed in this revision

Lora.h Show annotated file Show diff for this revision Revisions of this file
MTS-Lora/vendor/multitech/MTS-Utils/MTSCircularBuffer.h Show annotated file Show diff for this revision Revisions of this file
MTS-Lora/vendor/multitech/MTS-Utils/MTSLog.h Show annotated file Show diff for this revision Revisions of this file
MTS-Lora/vendor/multitech/MTS-Utils/MTSText.h Show annotated file Show diff for this revision Revisions of this file
MTS-Lora/vendor/multitech/MTS-Utils/Utils.h Show annotated file Show diff for this revision Revisions of this file
MacEvents.h Show annotated file Show diff for this revision Revisions of this file
Mote.h Show annotated file Show diff for this revision Revisions of this file
libxDot-ARMCC.ar Show annotated file Show diff for this revision Revisions of this file
libxDot-GCC_ARM.a Show annotated file Show diff for this revision Revisions of this file
mDot.h Show annotated file Show diff for this revision Revisions of this file
mDotEvent.h Show annotated file Show diff for this revision Revisions of this file
--- a/Lora.h	Thu Sep 22 15:06:54 2016 -0500
+++ b/Lora.h	Thu Sep 22 16:29:07 2016 -0500
@@ -0,0 +1,709 @@
+/**   __  ___     ____  _    ______        __     ____         __                  ____
+ *   /  |/  /_ __/ / /_(_)__/_  __/__ ____/ /    / __/_ _____ / /____ __ _  ___   /  _/__  ____
+ *  / /|_/ / // / / __/ /___// / / -_) __/ _ \  _\ \/ // (_-</ __/ -_)  ' \(_-<  _/ // _ \/ __/  __
+ * /_/  /_/\_,_/_/\__/_/    /_/  \__/\__/_//_/ /___/\_, /___/\__/\__/_/_/_/___/ /___/_//_/\__/  /_/
+ * Copyright (C) 2015 by Multi-Tech Systems        /___/
+ *
+ *
+ * @author Jason Reiss
+ * @date   10-31-2015
+ * @brief  lora namespace defines global settings, structures and enums for the lora library
+ *
+ * @details
+ *
+ *
+ *
+ */
+
+#ifndef __LORA_H__
+#define __LORA_H__
+
+#include "mbed.h"
+#include <assert.h>
+#include "MTSLog.h"
+//#include <cstring>
+#include <inttypes.h>
+
+namespace lora {
+
+    /**
+     * Frequency bandwidth of a Datarate, higher bandwidth gives higher datarate
+     */
+    enum Bandwidth {
+        BW_125,
+        BW_250,
+        BW_500,
+        BW_FSK = 50
+    };
+
+    /**
+     * Spreading factor of a Datarate, lower spreading factor gives higher datarate
+     */
+    enum SpreadingFactors {
+        SF_6 = 6,
+        SF_7,
+        SF_8,
+        SF_9,
+        SF_10,
+        SF_11,
+        SF_12,
+        SF_FSK,
+        SF_INVALID
+    };
+
+    /**
+     * Datarates for use with ChannelPlan
+     */
+    enum Datarates {
+        DR_0 = 0,
+        DR_1,
+        DR_2,
+        DR_3,
+        DR_4,
+        DR_5,
+        DR_6,
+        DR_7,
+        DR_8,
+        DR_9,
+        DR_10,
+        DR_11,
+        DR_12,
+        DR_13,
+        DR_14,
+        DR_15
+    };
+
+    const uint8_t MIN_DATARATE = (uint8_t) DR_0;             //!< Minimum datarate
+
+
+    const uint8_t MAX_PHY_PACKET_SIZE = 255;                    //!< Maximum size for a packet
+    const uint8_t MAX_APPS = 8;                                 //!< Maximum number of apps sessions to save
+    const uint8_t MAX_MULTICAST_SESSIONS = 8;                   //!< Maximum number of multicast sessions to save
+    const uint8_t EUI_SIZE = 8;                                 //!< Number of bytes in an EUI
+    const uint8_t KEY_SIZE = 16;                                //!< Number of bytes in an AES key
+
+    const uint8_t DEFAULT_NUM_CHANNELS = 16;                    //!< Default number of channels in a plan
+    const uint8_t DEFAULT_RX1_DR_OFFSET = 0;                    //!< Default datarate offset for first rx window
+    const uint8_t DEFAULT_RX2_DATARATE = 0;                     //!< Default datarate for second rx window
+    const uint8_t DEFAULT_TX_POWER = 14;                        //!< Default transmit power
+    const uint8_t DEFAULT_CODE_RATE = 1;                        //!< Default coding rate 1:4/5, 2:4/6, 3:4/7, 4:4/8
+    const uint8_t DEFAULT_PREAMBLE_LEN = 8;                     //!< Default preamble length
+
+    const int32_t MAX_FCNT_GAP = 16384;                         //!< Maximum allowed gap in sequence numbers before roll-over
+
+    const uint16_t PRIVATE_JOIN_DELAY = 1000;                   //!< Default join delay used for private network
+    const uint16_t PUBLIC_JOIN_DELAY = 5000;                    //!< Default join delay used for public network
+    const uint16_t DEFAULT_JOIN_DELAY = PRIVATE_JOIN_DELAY;     //!< Default join delay1
+    const uint16_t DEFAULT_RX_DELAY = 1000;                     //!< Default delay for first receive window
+    const uint16_t DEFAULT_RX_TIMEOUT = 3000;                   //!< Default timeout for receive windows
+
+    const uint8_t HI_DR_SYMBOL_TIMEOUT = 12;                    //!< Symbol timeout for receive at datarate with SF < 11
+    const uint8_t LO_DR_SYMBOL_TIMEOUT = 8;                     //!< Symbol timeout for receive at datarate with SF > 10
+
+    const uint16_t RX2_DELAY_OFFSET = 1000;                     //!< Delay between first and second window
+    const uint16_t RXC_OFFSET = 50;                             //!< Time between end of RXC after TX and RX1
+
+    const uint8_t US915_125K_NUM_CHANS = 64;                    //!< Number of 125k channels in US915 channel plan
+    const uint8_t US915_500K_NUM_CHANS = 8;                     //!< Number of 500k channels in US915 channel plan
+
+    const uint32_t US915_125K_FREQ_BASE = 902300000;            //!< Frequency base for 125k US915 uplink channels
+    const uint32_t US915_125K_FREQ_STEP = 200000;               //!< Frequency step for 125k US915 uplink channels
+
+    const uint32_t US915_500K_FREQ_BASE = 903000000;            //!< Frequency base for 500k US915 uplink channels
+    const uint32_t US915_500K_FREQ_STEP = 1600000;              //!< Frequency step for 500k US915 uplink channels
+
+    const uint32_t US915_500K_DBASE = 923300000;                //!< Frequency base for 500k US915 downlink channels
+    const uint32_t US915_500K_DSTEP = 600000;                   //!< Frequency step for 500k US915 downlink channels
+
+    const uint32_t US915_FREQ_MIN = 902000000;
+    const uint32_t US915_FREQ_MAX = 928000000;
+
+    const uint8_t US915_MIN_DATARATE = (uint8_t) DR_0;       //!< Minimum transmit datarate for US915
+    const uint8_t US915_MAX_DATARATE = (uint8_t) DR_4;       //!< Maximum transmit datarate for US915
+
+    const uint8_t US915_MIN_DATARATE_OFFSET = (uint8_t) 0;       //!< Minimum transmit datarate for US915
+    const uint8_t US915_MAX_DATARATE_OFFSET = (uint8_t) 3;       //!< Maximum transmit datarate for US915
+
+    const uint8_t AU915_125K_NUM_CHANS = 64;                    //!< Number of 125k channels in AU915 channel plan
+    const uint8_t AU915_500K_NUM_CHANS = 8;                     //!< Number of 500k channels in AU915 channel plan
+
+    const uint32_t AU915_125K_FREQ_BASE = 915200000;            //!< Frequency base for 125k AU915 uplink channels
+    const uint32_t AU915_125K_FREQ_STEP = 200000;               //!< Frequency step for 125k AU915 uplink channels
+
+    const uint32_t AU915_500K_FREQ_BASE = 915900000;            //!< Frequency base for 500k AU915 uplink channels
+    const uint32_t AU915_500K_FREQ_STEP = 1600000;              //!< Frequency step for 500k AU915 uplink channels
+
+    const uint32_t AU915_500K_DBASE = 923300000;                //!< Frequency base for 500k AU915 downlink channels
+    const uint32_t AU915_500K_DSTEP = 600000;                   //!< Frequency step for 500k AU915 downlink channels
+
+    const uint32_t AU915_FREQ_MIN = 915000000;
+    const uint32_t AU915_FREQ_MAX = 928000000;
+
+    const uint8_t AU915_MIN_DATARATE = (uint8_t) DR_0;       //!< Minimum transmit datarate for AU915
+    const uint8_t AU915_MAX_DATARATE = (uint8_t) DR_4;       //!< Maximum transmit datarate for AU915
+
+    const uint8_t AU915_MIN_DATARATE_OFFSET = (uint8_t) 0;       //!< Minimum transmit datarate for AU915
+    const uint8_t AU915_MAX_DATARATE_OFFSET = (uint8_t) 3;       //!< Maximum transmit datarate for AU915
+
+    const uint8_t EU868_125K_NUM_CHANS = 16;                    //!< Number of 125k channels in EU868 channel plan
+    const uint8_t EU868_DEFAULT_NUM_CHANS = 3;                  //!< Number of defualt channels in EU868 channel plan
+    const uint32_t EU868_125K_FREQ_BASE = 868100000;            //!< Frequency base for 125k EU868 uplink channels
+    const uint32_t EU868_125K_FREQ_STEP = 200000;               //!< Frequency step for 125k EU868 uplink channels
+    const uint32_t EU868_RX2_FREQ = 869525000;                  //!< Frequency default for second rx window in EU868
+
+    const uint8_t EU868_TX_POWER_MAX = 14;                      //!< Max power for EU868 channel plan
+
+    // 0.1% duty cycle 863-868
+    // Limiting to 865-868 allows for 1% duty cycle
+    const uint32_t EU868_MILLI_FREQ_MIN = 865000000;
+    const uint32_t EU868_MILLI_FREQ_MAX = 868000000;
+
+    const uint32_t EU868_MILLI_1_FREQ_MIN = 868700000;
+    const uint32_t EU868_MILLI_1_FREQ_MAX = 869200000;
+
+    // 1% duty cycle
+    const uint32_t EU868_CENTI_FREQ_MIN = 868000000;
+    const uint32_t EU868_CENTI_FREQ_MAX = 868600000;
+
+    // 10% duty cycle
+    const uint32_t EU868_DECI_FREQ_MIN = 869400000;
+    const uint32_t EU868_DECI_FREQ_MAX = 869650000;
+
+    // Below 7dBm there is no duty cycle for these frequencies
+    // Up to 14dBm there is 1% duty cycle
+    const uint32_t EU868_VAR_FREQ_MIN = 869700000;
+    const uint32_t EU868_VAR_FREQ_MAX = 870000000;
+
+    const uint32_t EU868_FREQ_MIN = 863000000;
+    const uint32_t EU868_FREQ_MAX = 870000000;
+
+    const uint8_t EU868_MIN_DATARATE = (uint8_t) DR_0;       //!< Minimum transmit datarate for EU868
+    const uint8_t EU868_MAX_DATARATE = (uint8_t) DR_7;       //!< Maximum transmit datarate for EU868
+
+    const uint8_t EU868_MIN_DATARATE_OFFSET = (uint8_t) 0;       //!< Minimum transmit datarate for US915
+    const uint8_t EU868_MAX_DATARATE_OFFSET = (uint8_t) 5;       //!< Maximum transmit datarate for US915
+
+    const int16_t DEFAULT_FREE_CHAN_RSSI_THRESHOLD = -90;       //!< Threshold for channel activity detection (CAD) dBm
+
+    const uint8_t CHAN_MASK_SIZE = 16;                          //!< Number of bits in a channel mask
+    const uint8_t COMMANDS_BUFFER_SIZE = 15;                    //!< Size of Mac Command buffer
+
+    const uint8_t PKT_HEADER = 0;                               //!< Index to packet mHdr field
+    const uint8_t PKT_ADDRESS = 1;                              //!< Index to first byte of packet address field
+    const uint8_t PKT_FRAME_CONTROL = PKT_ADDRESS + 4;          //!< Index to packet fCtrl field @see UplinkControl
+    const uint8_t PKT_FRAME_COUNTER = PKT_FRAME_CONTROL + 1;    //!< Index to packet frame counter field
+    const uint8_t PKT_OPTIONS_START = PKT_FRAME_COUNTER + 2;    //!< Index to start of optional mac commands
+
+    const uint8_t PKT_JOIN_APP_NONCE = 1;                       //!< Index to application nonce in Join Accept message
+    const uint8_t PKT_JOIN_NETWORK_ID = 4;                      //!< Index to network id in Join Accept message
+    const uint8_t PKT_JOIN_NETWORK_ADDRESS = 7;                 //!< Index to network address in Join Accept message
+    const uint8_t PKT_JOIN_DL_SETTINGS = 11;                    //!< Index to downlink settings in Join Accept message
+    const uint8_t PKT_JOIN_RX_DELAY = 12;                       //!< Index to rx delay in Join Accept message
+
+    const uint8_t ADR_ACK_LIMIT = 64;                           //!< Number of packets without ADR ACK Request
+    const uint8_t ADR_ACK_DELAY = 32;                           //!< Number of packets to expect ADR ACK Response within
+
+    const uint16_t ACK_TIMEOUT = 2000;                          //!< Base millisecond timeout to resend after missed ACK
+    const uint16_t ACK_TIMEOUT_RND = 1000;                      //!< Random millisecond adjustment to resend after missed ACK
+
+    const uint8_t FRAME_OVERHEAD = 13;                          //!< Bytes of network info overhead in a frame
+
+    /**
+     * Settings to choose ChannelPlan
+     */
+    enum FrequencyBand {
+        EU868,      //!< EU 863-870 16 channel uplink
+        US915,      //!< US 902-928 64-125k/8-500k uplink and 8-500k downlink channels
+        AU915,      //!< US 915-928 64-125k/8-500k uplink and 8-500k downlink channels
+        CN779,      //!<
+        CN470,      //!<
+        EU433,      //!<
+    };
+
+    /**
+     * Settings for type of network
+     * PUBLIC - defaults to 5/6 second join windows and 0x34 sync word
+     * PRIVATE - defaults to 1/2 second join windows and 0x12 sync word
+     */
+    enum NetworkType {
+        PRIVATE = 0,
+        PUBLIC = 1,
+        PEER_TO_PEER = 4
+    };
+
+    /**
+     * Enum for on/off settings
+     */
+    enum Enabled {
+        OFF = 0,
+        ON = 1
+    };
+
+    /**
+     * Return status of mac functions
+     */
+    enum MacStatus {
+        LORA_OK = 0,
+        LORA_ERROR = 1,
+        LORA_JOIN_ERROR = 2,
+        LORA_SEND_ERROR = 3,
+        LORA_MIC_ERROR = 4,
+        LORA_ADDRESS_ERROR = 5,
+        LORA_NO_CHANS_ENABLED = 6,
+        LORA_COMMAND_BUFFER_FULL = 7,
+        LORA_UNKNOWN_MAC_COMMAND = 8,
+        LORA_ADR_OFF = 9,
+        LORA_BUSY = 10,
+        LORA_LINK_BUSY = 11,
+        LORA_RADIO_BUSY = 12,
+        LORA_BUFFER_FULL = 13,
+        LORA_JOIN_BACKOFF = 14,
+        LORA_NO_FREE_CHAN = 15,
+        LORA_AGGREGATED_DUTY_CYCLE = 16,
+        LORA_MAC_COMMAND_ERROR = 17,
+        LORA_MAX_PAYLOAD_EXCEEDED = 18
+    };
+
+    /**
+     * State for Link
+     */
+    enum LinkState {
+        LINK_IDLE = 0,  //!< Link ready to send or receive
+        LINK_TX,        //!< Link is busy sending
+        LINK_ACK_TX,    //!< Link is busy resending after missed ACK
+        LINK_REP_TX,    //!< Link is busy repeating
+        LINK_RX,        //!< Link has receive window open
+        LINK_RX1,       //!< Link has first received window open
+        LINK_RX2,       //!< Link has second received window open
+        LINK_RXC,       //!< Link has class C received window open
+        LINK_P2P,       //!< Link is busy sending
+    };
+
+    /**
+     * State for MAC
+     */
+    enum MacState {
+        MAC_IDLE,
+        MAC_RX1,
+        MAC_RX2,
+        MAC_RXC,
+        MAC_TX,
+        MAC_JOIN
+    };
+
+    /**
+     * Operation class for device
+     */
+    enum MoteClass {
+        CLASS_A = 0x00, //!< Device can only receive in windows opened after a transmit
+        CLASS_B = 0x01, //!< Device can receive in windows sychronized with gateway beacon
+        CLASS_C = 0x02  //!< Device can receive any time when not transmitting
+    };
+
+    /**
+     * Direction of a packet
+     */
+    enum Direction {
+        DIR_UP = 0,     //!< Packet is sent from mote to gateway
+        DIR_DOWN = 1,   //!< Packet was received from gateway
+        DIR_PEER = 2    //!< Packet was received from peer
+    };
+
+
+    /**
+     * Received window used by Link
+     */
+    enum ReceiveWindows {
+        RX_1 = 1,           //!< First receive window
+        RX_2,               //!< Second receive window
+        RX_BEACON,          //!< Beacon receive window
+        RX_SLOT,             //!< Beacon Slot receive window
+        RX_TEST
+    };
+
+    /**
+     * Datarate range for a Channel
+     */
+    typedef union {
+            int8_t Value;
+            struct {
+                    int8_t Min :4;
+                    int8_t Max :4;
+            } Fields;
+    } DatarateRange;
+
+    /**
+     * Datarate used for transmitting and receiving
+     */
+    typedef struct Datarate {
+            uint8_t Index;
+            uint8_t Bandwidth;
+            uint8_t Coderate;
+            uint8_t PreambleLength;
+            uint8_t SpreadingFactor;
+            uint8_t Crc;
+            uint8_t TxIQ;
+            uint8_t RxIQ;
+            uint8_t SymbolTimeout();
+            Datarate();
+    } Datarate;
+
+    /**
+     * Channel used for transmitting
+     */
+    typedef struct {
+            uint8_t Index;
+            uint32_t Frequency;
+            DatarateRange DrRange;
+    } Channel;
+
+    /**
+     * Receive window
+     */
+    typedef struct {
+            uint8_t Index;
+            uint32_t Frequency;
+            uint8_t DatarateIndex;
+    } RxWindow;
+
+    /**
+     * Duty band for limiting time-on-air for regional regulations
+     */
+    typedef struct {
+            uint8_t Index;
+            uint32_t FrequencyMin;
+            uint32_t FrequencyMax;
+            uint8_t PowerMax;
+            uint16_t DutyCycle;          //!< Multiplier of time on air, 0:100%, 1:50%, 2:33%, 10:10%, 100:1%, 1000,0.1%
+            uint32_t TimeOffEnd;         //!< Timestamp when this band will be available
+    } DutyBand;
+
+    /**
+     * Device configuration
+     */
+    typedef struct {
+            uint8_t FrequencyBand;      //!< Used to choose ChannelPlan
+            uint8_t EUI[8];             //!< Unique identifier assigned to device
+    } DeviceConfig;
+
+    /**
+     * Network configuration
+     */
+    typedef struct {
+            uint8_t Mode;               //!< PUBLIC, PRIVATE or PEER_TO_PEER network mode
+            uint8_t Class;              //!< Operating class of device
+            uint8_t EUI[8];             //!< Network ID or AppEUI
+            uint8_t Key[16];            //!< Network Key or AppKey
+            uint8_t JoinDelay;          //!< Number of seconds to wait before 1st RX Window
+            uint8_t RxDelay;            //!< Number of seconds to wait before 1st RX Window
+            uint8_t ChannelGroup;       //!< ChannelGroup used for US915 hybrid operation 0:72 channels, 1:1-8 channels ...
+            uint8_t AckAttempts;        //!< Number of attempts to send packet and receive an ACK from server
+            uint8_t Retries;            //!< Number of times to resend a packet without receiving an ACK, redundancy
+            uint8_t ADREnabled;         //!< Enable adaptive datarate
+            uint8_t CADEnabled;         //!< Enable listen before talk/channel activity detection
+            uint8_t RepeaterMode;       //!< Limit payloads to repeater compatible sizes
+            uint8_t TxPower;            //!< Default radio output power in dBm
+            uint8_t TxPowerMax;         //!< Max transmit power
+            uint8_t TxDatarate;         //!< Datarate for P2P transmit
+            uint32_t TxFrequency;       //!< Frequency for P2P transmit
+            int8_t AntennaGain;         //!< Antenna Gain
+            uint8_t DisableEncryption;  //!< Disable Encryption
+            uint8_t DisableCRC;        //!< Disable CRC on uplink packets
+            uint16_t P2PACKTimeout;
+            uint16_t P2PACKBackoff;
+            uint8_t JoinRx1DatarateOffset;  //!< Offset for datarate for first window
+            uint32_t JoinRx2Frequency;      //!< Frequency used in second window
+            uint8_t JoinRx2DatarateIndex;   //!< Datarate for second window
+    } NetworkConfig;
+
+    /**
+     * Network session info
+     * Some settings are acquired in join message and others may be changed through Mac Commands from server
+     */
+    typedef struct {
+            uint8_t Joined;                     //!< State of session
+            uint8_t Rx1DatarateOffset;          //!< Offset for datarate for first window
+            uint32_t Rx2Frequency;              //!< Frequency used in second window
+            uint8_t Rx2DatarateIndex;           //!< Datarate for second window
+            uint8_t TxPower;                    //!< Current total radiated output power in dBm
+            uint8_t TxDatarate;                 //!< Current datarate can be changed when ADR is enabled
+            uint32_t Address;                   //!< Network address
+            uint32_t NetworkID;                 //!< Network ID 24-bits
+            uint8_t NetworkSessionKey[16];      //!< Network session key
+            uint8_t ApplicationSessionKey[16];  //!< Data session key
+            uint16_t ChannelMask[4];            //!< Current channel mask
+            uint16_t ChannelMask500k;           //!< Current channel mask for 500k channels
+            uint32_t DownlinkCounter;           //!< Downlink counter of last packet received from server
+            uint32_t UplinkCounter;             //!< Uplink counter of last packet received from server
+            uint8_t Redundancy;                 //!< Number of time to repeat an uplink
+            uint8_t MaxDutyCycle;               //!< Current Max Duty Cycle value
+            uint32_t JoinTimeOnAir;              //!< Balance of time on air used during join attempts
+            uint32_t JoinTimeOffEnd;            //!< RTC time of next join attempt
+            uint32_t JoinFirstAttempt;          //!< RTC time of first failed join attempt
+            uint32_t AggregatedTimeOffEnd;      //!< Time off air expiration for aggregate duty cycle
+            uint16_t AggregateDutyCycle;        //!< Used for enforcing time-on-air
+            uint8_t AckCounter;                 //!< Current number of packets sent without ACK from server
+            uint8_t AdrCounter;                 //!< Current number of packets received without downlink from server
+            uint8_t RxDelay;                    //!< Number of seconds to wait before 1st RX Window
+            uint8_t CommandBuffer[COMMANDS_BUFFER_SIZE]; //!< Buffer to hold Mac Commands and parameters to be sent in next packet
+            uint8_t CommandBufferIndex;         //!< Index to place next Mac Command, also current size of Command Buffer
+            bool SrvRequestedAck;               //!< Indicator of ACK requested by server in last packet received
+            bool DataPending;                   //!< Indicator of data pending at server
+            uint8_t RxTimingSetupReqReceived;   //!< Indicator that RxTimingSetupAns should be included in uplink
+            uint8_t RxParamSetupReqAnswer;      //!< Indicator that RxParamSetupAns should be included in uplink
+    } NetworkSession;
+
+    /**
+     * Multicast session info
+     */
+    typedef struct {
+            uint32_t Address;               //!< Network address
+            uint8_t NetworkSessionKey[16];  //!< Network session key
+            uint8_t DataSessionKey[16];     //!< Data session key
+            uint32_t DownlinkCounter;       //!< Downlink counter of last packet received from server
+    } MulticastSession;
+
+    /**
+     * Application configuration
+     */
+    typedef struct {
+            uint8_t Port;                   //!< Port used by application
+            uint8_t AppEUI;                 //!< Application ID
+            uint8_t AppKey[16];             //!< Application Key
+    } ApplicationConfig;
+
+    /**
+     * Statistics of current network session
+     */
+    typedef struct Statistics {
+            uint32_t Up;                    //!< Number of uplink packets sent
+            uint32_t Down;                  //!< Number of downlink packets received
+            uint32_t Joins;                 //!< Number of join requests sent
+            uint32_t JoinFails;             //!< Number of join requests without response or invalid response
+            uint32_t MissedAcks;            //!< Number of missed acknowledgement attempts of confirmed packets
+            uint32_t CRCErrors;             //!< Number of CRC errors in received packets
+            int32_t AvgCount;              //!< Number of packets used to compute rolling average of RSSI and SNR
+            int16_t Rssi;                   //!< RSSI of last packet received
+            int16_t RssiMin;                //!< Minimum RSSI of last AvgCount packets
+            int16_t RssiMax;                //!< Maximum RSSI of last AvgCount packets
+            int16_t RssiAvg;                //!< Rolling average RSSI of last AvgCount packets
+            int16_t Snr;                     //!< SNR of last packet received
+            int16_t SnrMin;                  //!< Minimum SNR of last AvgCount packets
+            int16_t SnrMax;                  //!< Maximum SNR of last AvgCount packets
+            int16_t SnrAvg;                  //!< Rolling average SNR of last AvgCount packets
+    } Statistics;
+
+    /**
+     *  Testing settings
+     */
+    typedef struct {
+            uint8_t TestMode;
+            uint8_t SkipMICCheck;
+            uint8_t DisableDutyCycle;
+            uint8_t DisableRx1;
+            uint8_t DisableRx2;
+            uint8_t FixedUplinkCounter;
+            uint8_t DisableRandomJoinDatarate;
+    } Testing;
+
+    /**
+     * Combination of device, network, testing settings and statistics
+     */
+    typedef struct {
+            DeviceConfig Device;
+            NetworkConfig Network;
+            NetworkSession Session;
+            ApplicationConfig Applications[MAX_APPS];
+            MulticastSession Multicast[MAX_MULTICAST_SESSIONS];
+            Statistics Stats;
+            Testing Test;
+    } Settings;
+
+    /**
+     * Downlink settings sent in Join Accept message
+     */
+    typedef union {
+            uint8_t Value;
+            struct {
+                    uint8_t Rx2Datarate :4;
+                    uint8_t Rx1Offset :3;
+                    uint8_t RFU :1;
+            };
+    } DownlinkSettings;
+
+    /**
+     * Frame structure for Join Request
+     */
+    typedef struct {
+            uint8_t Type;
+            uint8_t AppEUI[8];
+            uint8_t DevEUI[8];
+            uint8_t Nonce[2];
+            uint8_t MIC[4];
+    } JoinRequestFrame;
+
+    /**
+     * Mac header of uplink and downlink packets
+     */
+    typedef union {
+            uint8_t Value;
+            struct {
+                    uint8_t Major :2;
+                    uint8_t RFU :3;
+                    uint8_t MType :3;
+            } Bits;
+    } MacHeader;
+
+    /**
+     * Frame control field of uplink packets
+     */
+    typedef union {
+            uint8_t Value;
+            struct {
+                    uint8_t OptionsLength :4;
+                    uint8_t ClassB :1;
+                    uint8_t Ack :1;
+                    uint8_t AdrAckReq :1;
+                    uint8_t Adr :1;
+            } Bits;
+    } UplinkControl;
+
+    /**
+     * Frame control field of downlink packets
+     */
+    typedef union {
+            uint8_t Value;
+            struct {
+                    uint8_t OptionsLength :4;
+                    uint8_t FPending :1;
+                    uint8_t Ack :1;
+                    uint8_t RFU :1;
+                    uint8_t Adr :1;
+            } Bits;
+    } DownlinkControl;
+
+    /**
+     * Frame type of packet
+     */
+    typedef enum {
+        FRAME_TYPE_JOIN_REQ = 0x00,
+        FRAME_TYPE_JOIN_ACCEPT = 0x01,
+        FRAME_TYPE_DATA_UNCONFIRMED_UP = 0x02,
+        FRAME_TYPE_DATA_UNCONFIRMED_DOWN = 0x03,
+        FRAME_TYPE_DATA_CONFIRMED_UP = 0x04,
+        FRAME_TYPE_DATA_CONFIRMED_DOWN = 0x05,
+        FRAME_TYPE_RFU = 0x06,
+        FRAME_TYPE_PROPRIETARY = 0x07,
+    } FrameType;
+
+    /**
+     * LoRaWAN mote MAC commands
+     */
+    typedef enum {
+        /* Class A */
+        MOTE_MAC_LINK_CHECK_REQ = 0x02,
+        MOTE_MAC_LINK_ADR_ANS = 0x03,
+        MOTE_MAC_DUTY_CYCLE_ANS = 0x04,
+        MOTE_MAC_RX_PARAM_SETUP_ANS = 0x05,
+        MOTE_MAC_DEV_STATUS_ANS = 0x06,
+        MOTE_MAC_NEW_CHANNEL_ANS = 0x07,
+        MOTE_MAC_RX_TIMING_SETUP_ANS = 0x08,
+
+        /* Class B */
+        MOTE_MAC_PING_SLOT_INFO_REQ = 0x09,
+        MOTE_MAC_PING_SLOT_FREQ_ANS = 0x0a,
+        MOTE_MAC_PING_SLOT_CHANNEL_ANS = 0x0a,
+        MOTE_MAC_BEACON_TIMING_REQ = 0x0b,
+        MOTE_MAC_BEACON_FREQ_ANS = 0x0c,
+
+        /* Multitech */
+        MOTE_MAC_PING_REQ = 0x80,
+        MOTE_MAC_CHANGE_CLASS = 0x81,
+        MOTE_MAC_MULTIPART_START_REQ = 0x82,
+        MOTE_MAC_MULTIPART_START_ANS = 0x83,
+        MOTE_MAC_MULTIPART_CHUNK = 0x84,
+        MOTE_MAC_MULTIPART_END_REQ = 0x85,
+        MOTE_MAC_MULTIPART_END_ANS = 0x86
+    } MoteCommand;
+
+    /*!
+     * LoRaWAN server MAC commands
+     */
+    typedef enum {
+        /* Class A */
+        SRV_MAC_LINK_CHECK_ANS = 0x02,
+        SRV_MAC_LINK_ADR_REQ = 0x03,
+        SRV_MAC_DUTY_CYCLE_REQ = 0x04,
+        SRV_MAC_RX_PARAM_SETUP_REQ = 0x05,
+        SRV_MAC_DEV_STATUS_REQ = 0x06,
+        SRV_MAC_NEW_CHANNEL_REQ = 0x07,
+        SRV_MAC_RX_TIMING_SETUP_REQ = 0x08,
+
+        /* Class B */
+        SRV_MAC_PING_SLOT_INFO_ANS = 0x09,
+        SRV_MAC_PING_SLOT_FREQ_REQ = 0x0a,
+        SRV_MAC_PING_SLOT_CHANNEL_REQ = 0x0a,
+        SRV_MAC_BEACON_TIMING_ANS = 0x0b,
+        SRV_MAC_BEACON_FREQ_REQ = 0x0c,
+
+        /* Multitech */
+        SRV_MAC_PING_ANS = 0x80,
+        SRV_MAC_CHANGE_CLASS = 0x81,
+        SRV_MAC_MULTIPART_START_REQ = 0x82,
+        SRV_MAC_MULTIPART_START_ANS = 0x83,
+        SRV_MAC_MULTIPART_CHUNK = 0x84,
+        SRV_MAC_MULTIPART_END_REQ = 0x85,
+        SRV_MAC_MULTIPART_END_ANS = 0x86
+    } ServerCommand;
+
+    /**
+     * Random seed for software RNG
+     */
+    void srand(uint32_t seed);
+
+    /**
+     * Software RNG for consistent results across differing hardware
+     */
+    int rand(void);
+
+    /**
+     * Generate random number bounded by min and max
+     */
+    int32_t rand_r(int32_t min, int32_t max);
+
+    uint8_t CountBits(uint16_t mask);
+
+    /**
+     * Copy 3-bytes network order from array into LSB of integer value
+     */
+    void CopyNetIDtoInt(const uint8_t* arr, uint32_t& val);
+
+    /**
+     * Copy LSB 3-bytes from integer value into array network order
+     */
+    void CopyNetIDtoArray(uint32_t val, uint8_t* arr);
+
+    /**
+     * Copy 4-bytes network order from array in to integer value
+     */
+    void CopyAddrtoInt(const uint8_t* arr, uint32_t& val);
+
+    /**
+     * Copy 4-bytes from integer in to array network order
+     */
+    void CopyAddrtoArray(uint32_t val, uint8_t* arr);
+
+    /**
+     * Copy 3-bytes network order from array into integer value and multiply by 100
+     */
+    void CopyFreqtoInt(const uint8_t* arr, uint32_t& freq);
+
+    /**
+     * Reverse memory copy
+     */
+    void memcpy_r(uint8_t *dst, const uint8_t *src, size_t n);
+
+}
+
+#endif
+
--- a/MTS-Lora/vendor/multitech/MTS-Utils/MTSCircularBuffer.h	Thu Sep 22 15:06:54 2016 -0500
+++ b/MTS-Lora/vendor/multitech/MTS-Utils/MTSCircularBuffer.h	Thu Sep 22 16:29:07 2016 -0500
@@ -0,0 +1,158 @@
+#ifndef MTSCIRCULARBUFFER_H
+#define MTSCIRCULARBUFFER_H
+
+#include "Utils.h"
+
+namespace mts
+{
+
+/** This class provides a circular byte buffer meant for temporary storage
+* during IO transactions.  It contains many of the common methods you
+* would expect from a circular buffer like read, write, and various
+* methods for checking the size or status.  It should be noted that
+* this class does not include any special code for thread safety like
+* a lock.  In most cases this is not problematic, but is something
+* to be aware of.
+*/
+class MTSCircularBuffer
+{
+public:
+    /** Creates an MTSCircularBuffer object with the specified static size.
+    *
+    * @prarm bufferSize size of the buffer in bytes.
+    */
+    MTSCircularBuffer(int bufferSize);
+
+    /** Destructs an MTSCircularBuffer object and frees all related resources.
+    */
+    ~MTSCircularBuffer();
+
+    /** This method enables bulk reads from the buffer.  If more data is
+    * requested then available it simply returns all remaining data within the
+    * buffer.
+    *
+    * @param data the buffer where data read will be added to.
+    * @param length the amount of data in bytes to be read into the buffer.
+    * @returns the total number of bytes that were read.
+    */
+    int read(char* data, int length);
+
+    /** This method reads a single byte from the buffer.
+    *
+    * @param data char where the read byte will be stored.
+    * @returns 1 if byte is read or 0 if no bytes available.
+    */
+    int read(char& data);
+
+    /** This method enables bulk writes to the buffer. If more data
+    * is requested to be written then space available the method writes
+    * as much data as possible and returns the actual amount written.
+    *
+    * @param data the byte array to be written.
+    * @param length the length of data to be written from the data paramter.
+    * @returns the number of bytes written to the buffer, which is 0 if
+    * the buffer is full.
+    */
+    int write(const char* data, int length);
+
+    /** This method writes a signle byte as a char to the buffer.
+    *
+    * @param data the byte to be written as a char.
+    * @returns 1 if the byte was written or 0 if the buffer was full.
+    */
+    int write(char data);
+
+    /** This method is used to setup a callback funtion when the buffer reaches
+    * a certain threshold. The threshold condition is checked after every read
+    * and write call is completed. The condition is made up of both a threshold
+    * value and operator. An example that would trigger a callback is if the
+    * threshold was 10, the operator GREATER, and there were 12 bytes added to an
+    * empty buffer.
+    *
+    * @param tptr a pointer to the object to be called when the condition is met.
+    * @param mptr a pointer to the function within the object to be called when
+    * the condition is met.
+    * @param threshold the value in bytes to be used as part of the condition.
+    * @param op the operator to be used in conjunction with the threshold
+    * as part of the condition.
+    */
+    template<typename T>
+    void attach(T *tptr, void( T::*mptr)(void), int threshold, RelationalOperator op) {
+        _threshold = threshold;
+        _op = op;
+        notify.attach(tptr, mptr);
+    }
+
+    /** This method is used to setup a callback funtion when the buffer reaches
+    * a certain threshold. The threshold condition is checked after every read
+    * and write call is completed. The condition is made up of both a threshold
+    * value and operator. An example that would trigger a callback is if the
+    * threshold was 10, the operator GREATER, and there were 12 bytes added to an
+    * empty buffer.
+    *
+    * @param fptr a pointer to the static function to be called when the condition
+    * is met.
+    * @param threshold the value in bytes to be used as part of the condition.
+    * @param op the operator to be used in conjunction with the threshold
+    * as part of the condition.
+    */
+    void attach(void(*fptr)(void), int threshold, RelationalOperator op) {
+        _threshold = threshold;
+        _op = op;
+        notify.attach(fptr);
+    }
+
+    /** This method returns the size of the storage space currently allocated for
+    * the buffer. This value is equivalent to the one passed into the constructor.
+    * This value is equal or greater than the size() of the buffer.
+    *
+    * @returns the allocated size of the buffer in bytes.
+    */
+    int capacity();
+
+    /** This method returns the amount of space left for writing.
+    *
+    * @returns numbers of unused bytes in buffer.
+    */
+    int remaining();
+
+    /** This method returns the number of bytes available for reading.
+    *
+    * @returns number of bytes currently in buffer.
+    */
+    int size();
+
+    /** This method returns whether the buffer is full.
+    *
+    * @returns true if full, otherwise false.
+    */
+    bool isFull();
+
+    /** This method returns whether the buffer is empty.
+    *
+    * @returns true if empty, otherwise false.
+    */
+    bool isEmpty();
+
+    /** This method clears the buffer. This is done through
+    * setting the internal read and write indexes to the same
+    * value and is therefore not an expensive operation.
+    */
+    void clear();
+
+
+private:
+    int bufferSize; // total size of the buffer
+    char* buffer; // internal byte buffer as a character buffer
+    int readIndex; // read index for circular buffer
+    int writeIndex; // write index for circular buffer
+    int bytes; // available data
+    FunctionPointer notify; // function pointer used for the internal callback notification
+    int _threshold; // threshold for the notification
+    RelationalOperator _op; // operator that determines the direction of the threshold
+    void checkThreshold(); // private function that checks thresholds and processes notifications
+};
+
+}
+
+#endif /* MTSCIRCULARBUFFER_H */
--- a/MTS-Lora/vendor/multitech/MTS-Utils/MTSLog.h	Thu Sep 22 15:06:54 2016 -0500
+++ b/MTS-Lora/vendor/multitech/MTS-Utils/MTSLog.h	Thu Sep 22 16:29:07 2016 -0500
@@ -0,0 +1,108 @@
+#ifndef MTSLOG_H
+#define MTSLOG_H
+
+#include <string>
+
+inline const char* className(const std::string& prettyFunction)
+{
+    size_t colons = prettyFunction.find_last_of("::");
+    if (colons == std::string::npos)
+        return "";
+    size_t begin = prettyFunction.substr(0,colons).rfind(" ") + 1;
+    size_t end = colons - begin;
+
+    return prettyFunction.substr(begin,end).c_str();
+}
+
+#define __CLASSNAME__ className(__PRETTY_FUNCTION__)
+
+
+#ifdef MTS_DEBUG
+#define logFatal(format, ...) \
+    mts::MTSLog::printMessage(mts::MTSLog::FATAL_LEVEL, "%s:%s:%d| [%s] " format "\r\n", __CLASSNAME__, __func__, __LINE__, mts::MTSLog::FATAL_LABEL, ##__VA_ARGS__)
+#define logError(format, ...) \
+    mts::MTSLog::printMessage(mts::MTSLog::ERROR_LEVEL, "%s:%s:%d| [%s] " format "\r\n", __CLASSNAME__, __func__, __LINE__, mts::MTSLog::ERROR_LABEL, ##__VA_ARGS__)
+#define logWarning(format, ...) \
+    mts::MTSLog::printMessage(mts::MTSLog::WARNING_LEVEL, "%s:%s:%d| [%s] " format "\r\n", __CLASSNAME__, __func__, __LINE__, mts::MTSLog::WARNING_LABEL, ##__VA_ARGS__)
+#define logInfo(format, ...) \
+    mts::MTSLog::printMessage(mts::MTSLog::INFO_LEVEL, "%s:%s:%d| [%s] " format "\r\n", __CLASSNAME__, __func__, __LINE__, mts::MTSLog::INFO_LABEL, ##__VA_ARGS__)
+#define logDebug(format, ...) \
+    mts::MTSLog::printMessage(mts::MTSLog::DEBUG_LEVEL, "%s:%s:%d| [%s] " format "\r\n", __CLASSNAME__, __func__, __LINE__, mts::MTSLog::DEBUG_LABEL, ##__VA_ARGS__)
+#define logTrace(format, ...) \
+    mts::MTSLog::printMessage(mts::MTSLog::TRACE_LEVEL, "%s:%s:%d| [%s] " format "\r\n", __CLASSNAME__, __func__, __LINE__, mts::MTSLog::TRACE_LABEL, ##__VA_ARGS__)
+#else
+#define logFatal(format, ...) \
+    mts::MTSLog::printMessage(mts::MTSLog::FATAL_LEVEL, "[%s] " format "\r\n", mts::MTSLog::FATAL_LABEL, ##__VA_ARGS__)
+#define logError(format, ...) \
+    mts::MTSLog::printMessage(mts::MTSLog::ERROR_LEVEL, "[%s] " format "\r\n", mts::MTSLog::ERROR_LABEL, ##__VA_ARGS__)
+#define logWarning(format, ...) \
+    mts::MTSLog::printMessage(mts::MTSLog::WARNING_LEVEL, "[%s] " format "\r\n", mts::MTSLog::WARNING_LABEL, ##__VA_ARGS__)
+#define logInfo(format, ...) \
+    mts::MTSLog::printMessage(mts::MTSLog::INFO_LEVEL, "[%s] " format "\r\n", mts::MTSLog::INFO_LABEL, ##__VA_ARGS__)
+#define logDebug(format, ...) \
+    mts::MTSLog::printMessage(mts::MTSLog::DEBUG_LEVEL, "[%s] " format "\r\n", mts::MTSLog::DEBUG_LABEL, ##__VA_ARGS__)
+#define logTrace(format, ...) \
+    mts::MTSLog::printMessage(mts::MTSLog::TRACE_LEVEL, "[%s] " format "\r\n", mts::MTSLog::TRACE_LABEL, ##__VA_ARGS__)
+#endif
+
+namespace mts {
+
+class MTSLog
+{
+public:
+
+    /** Enum of log levels.
+     */
+    enum logLevel {
+        NONE_LEVEL = 0,
+        FATAL_LEVEL = 1,
+        ERROR_LEVEL = 2,
+        WARNING_LEVEL = 3,
+        INFO_LEVEL = 4,
+        DEBUG_LEVEL = 5,
+        TRACE_LEVEL = 6
+    };
+
+    /** Print log message.
+     */
+    static void printMessage(int level, const char* format, ...);
+
+    /** Determine if the given level is currently printable.
+     */
+    static bool printable(int level);
+
+    /** Set log level
+     * Messages with lower priority than the current level will not be printed.
+     * If the level is set to NONE, no messages will print.
+     */
+    static void setLogLevel(int level);
+
+    /** Get the current log level.
+     */
+    static int getLogLevel();
+
+    /** Get string representation of the current log level.
+     */
+    static const char* getLogLevelString();
+
+    static const char* NONE_LABEL;
+    static const char* FATAL_LABEL;
+    static const char* ERROR_LABEL;
+    static const char* WARNING_LABEL;
+    static const char* INFO_LABEL;
+    static const char* DEBUG_LABEL;
+    static const char* TRACE_LABEL;
+
+private:
+
+    /** Constructor
+     */
+    MTSLog();
+
+    static int currentLevel;
+
+};
+
+}
+
+#endif
--- a/MTS-Lora/vendor/multitech/MTS-Utils/MTSText.h	Thu Sep 22 15:06:54 2016 -0500
+++ b/MTS-Lora/vendor/multitech/MTS-Utils/MTSText.h	Thu Sep 22 16:29:07 2016 -0500
@@ -0,0 +1,83 @@
+#ifndef MTSTEXT_H
+#define MTSTEXT_H
+
+#include <string>
+#include <vector>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+namespace mts
+{
+
+/** This class contains a number of static methods for manipulating strings and other
+* text data.
+*/
+class Text
+{
+public:
+    /** This static method can be used to pull out a string at the next line break. A
+    * break can either be a newline '\n', carriage return '\r' or both.
+    *
+    * @param source the source string to look for the line break on.
+    * @param start the start postion within the string to begin looking for the line
+    * break.
+    * @param cursor this value will be updated with the index for the next available character
+    * after the line break. If a line break is not found returns -1.
+    * @returns the string beginning with the start index up to including the line breaks.
+    */
+    static std::string getLine(const std::string& source, const size_t& start, size_t& cursor);
+
+    /** This is a static method for splitting strings using a delimeter value.
+    *
+    * @param str the string to try and split.
+    * @param delimiter the delimeter value to split on as a character.
+    * @param limit the maximum number of splits. If equal to 0 it splits as amny times as possible.
+    * The default is 0.
+    * @returns an ordered vector of strings conatining the splits of the original string.
+    */
+    static std::vector<std::string> split(const std::string& str, char delimiter, int limit = 0);
+
+    /** This is a static method for splitting strings using a delimeter value.
+    *
+    * @param str the string to try and split.
+    * @param delimiter the delimeter value to split on as a string.
+    * @param limit the maximum number of splits. If equal to 0 it splits as amny times as possible.
+    * The default is 0.
+    * @returns an ordered vector of strings conatining the splits of the original string.
+    */
+    static std::vector<std::string> split(const std::string& str, const std::string& delimiter, int limit = 0);
+    
+    static std::string readString(char* index, int length);
+
+    static std::string toUpper(const std::string str);
+
+    static std::string float2String(double val, int precision);
+
+    static std::string bin2hexString(const std::vector<uint8_t>& data, const char* delim = "", bool leadingZeros = false, bool bytePadding = true);
+
+    static std::string bin2hexString(const uint8_t* data, const uint32_t len, const char* delim = "", bool leadingZeros = false, bool bytePadding = true);
+
+    static std::string bin2base64(const std::vector<uint8_t>& data);
+
+    static std::string bin2base64(const uint8_t* data, size_t size);
+
+    static bool base642bin(const std::string in, std::vector<uint8_t>& out);
+
+    static void ltrim(std::string& str, const char* args);
+
+    static void rtrim(std::string& str, const char* args);
+
+    static void trim(std::string& str, const char* args);
+
+private:
+    // Safety for class with only static methods
+    Text();
+    Text(const Text& other);
+    Text& operator=(const Text& other);
+};
+
+}
+
+#endif
--- a/MTS-Lora/vendor/multitech/MTS-Utils/Utils.h	Thu Sep 22 15:06:54 2016 -0500
+++ b/MTS-Lora/vendor/multitech/MTS-Utils/Utils.h	Thu Sep 22 16:29:07 2016 -0500
@@ -0,0 +1,41 @@
+#ifndef UTILS_H
+#define UTILS_H
+
+#include <string>
+
+//Defines a max function that can be used.
+inline int mts_max(int a, int b) { return a > b ? a : b; }
+
+//Defines a min function that can be used.
+inline int mts_min(int a, int b) { return a < b ? a : b; }
+
+///An enumeration for relational operators
+enum RelationalOperator {
+    GREATER, LESS, EQUAL, GREATER_EQUAL, LESS_EQUAL
+};
+
+/** A static method for getting a string representation for the RelationalOperator
+* enumeration.
+*
+* @param relationalOperator a RelationalOperator enumeration.
+* @returns the enumeration name as a string.
+*/
+static inline std::string getRelationalOperatorNames(RelationalOperator relationalOperator)
+{
+    switch(relationalOperator) {
+        case GREATER:
+            return "GREATER";
+        case LESS:
+            return "LESS";
+        case EQUAL:
+            return "EQUAL";
+        case GREATER_EQUAL:
+            return "GREATER_EQUAL";
+        case LESS_EQUAL:
+            return "LESS_EQUAL";
+        default:
+            return "UNKNOWN ENUM";
+    }
+}
+
+#endif
--- a/MacEvents.h	Thu Sep 22 15:06:54 2016 -0500
+++ b/MacEvents.h	Thu Sep 22 16:29:07 2016 -0500
@@ -0,0 +1,53 @@
+/**   __  ___     ____  _    ______        __     ____         __                  ____
+ *   /  |/  /_ __/ / /_(_)__/_  __/__ ____/ /    / __/_ _____ / /____ __ _  ___   /  _/__  ____
+ *  / /|_/ / // / / __/ /___// / / -_) __/ _ \  _\ \/ // (_-</ __/ -_)  ' \(_-<  _/ // _ \/ __/ __
+ * /_/  /_/\_,_/_/\__/_/    /_/  \__/\__/_//_/ /___/\_, /___/\__/\__/_/_/_/___/ /___/_//_/\__/ /_/
+ * Copyright (C) 2015 by Multi-Tech Systems        /___/
+ *
+ *
+ * @author Jason Reiss
+ * @date   10-31-2015
+ * @brief  lora::MacEvents provides an interface for events from the Mac layer
+ *
+ * @details
+ *
+ */
+
+#ifndef __LORA_MAC_EVENTS_H__
+#define __LORA_MAC_EVENTS_H__
+
+#include "Lora.h"
+
+namespace lora {
+
+    class MacEvents {
+
+        public:
+            virtual ~MacEvents() {};
+
+            virtual void TxDone(uint8_t dr) = 0;
+            virtual void TxTimeout(void) = 0;
+
+            virtual void JoinAccept(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr) = 0;
+            virtual void JoinFailed(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr) = 0;
+            virtual void PacketRx(uint8_t port, uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr, lora::DownlinkControl ctrl, uint8_t slot, uint8_t retries=0) = 0;
+            virtual void RxDone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr, lora::DownlinkControl ctrl, uint8_t slot) = 0;
+
+            virtual void Pong(int16_t m_rssi, int8_t m_snr, int16_t s_rssi, int8_t s_snr) = 0;
+            virtual void NetworkLinkCheck(int16_t m_rssi, int8_t m_snr, int8_t s_snr, uint8_t s_gateways) = 0;
+
+            virtual void RxTimeout(uint8_t slot) = 0;
+            virtual void RxError(uint8_t slot) = 0;
+
+            virtual void MissedAck(uint8_t retries) = 0;
+
+            virtual uint8_t MeasureBattery() = 0;
+
+        private:
+
+
+    };
+
+}
+
+#endif
--- a/Mote.h	Thu Sep 22 15:06:54 2016 -0500
+++ b/Mote.h	Thu Sep 22 16:29:07 2016 -0500
@@ -0,0 +1,262 @@
+/**   __  ___     ____  _    ______        __     ____         __                  ____
+ *   /  |/  /_ __/ / /_(_)__/_  __/__ ____/ /    / __/_ _____ / /____ __ _  ___   /  _/__  ____
+ *  / /|_/ / // / / __/ /___// / / -_) __/ _ \  _\ \/ // (_-</ __/ -_)  ' \(_-<  _/ // _ \/ __/ __
+ * /_/  /_/\_,_/_/\__/_/    /_/  \__/\__/_//_/ /___/\_, /___/\__/\__/_/_/_/___/ /___/_//_/\__/ /_/
+ * Copyright (C) 2015 by Multi-Tech Systems        /___/
+ *
+ *
+ * @author Jason Reiss
+ * @date   10-31-2015
+ * @brief  lora::Mote provides a user level class that abstracts the complexity of the Mac layer
+ *
+ * @details
+ *
+ */
+
+#ifndef __LORA_MOTE_H__
+#define __LORA_MOTE_H__
+
+#include "rtos.h"
+#include "MacEvents.h"
+#include <vector>
+
+class SxRadio;
+class SxRadio1272;
+
+namespace lora {
+
+    class Mac;
+    class ChannelPlan;
+
+    class MoteEvents: public MacEvents {
+
+            /**
+             * Fired at end of TX
+             * @param dr datarate used for TX
+             */
+            virtual void TxDone(uint8_t dr);
+
+            /**
+             * Fired if TX timed out
+             */
+            virtual void TxTimeout(void);
+
+            /**
+             * Fired when JoinAccept message is received and MIC is validated
+             * @param payload received bytes
+             * @param size number of received bytes
+             * @param rssi of received packet
+             * @param snr of received packet
+             */
+            virtual void JoinAccept(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr);
+
+            /**
+             * Fired when JoinAccept message is received and MIC is not valid
+             * @param payload received bytes
+             * @param size number of received bytes
+             * @param rssi of received packet
+             * @param snr of received packet
+             */
+            virtual void JoinFailed(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr);
+
+            /**
+             * Fired when non duplicate packet is received and MIC is valid
+             * @param port of packet
+             * @param payload received bytes
+             * @param size number of received bytes
+             * @param rssi of received packet
+             * @param snr of received packet
+             * @param ctrl Downlink control field of packet
+             * @param slot rx window packet was received
+             * @param retries number of attempts before ack was received
+             */
+            virtual void PacketRx(uint8_t port, uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr, lora::DownlinkControl ctrl, uint8_t slot, uint8_t retries = 0);
+
+            /**
+             * Fired when radio has received a packet, packet is not validated
+             * @param payload received bytes
+             * @param size number of received bytes
+             * @param rssi of received packet
+             * @param snr of received packet
+             * @param ctrl Downlink control field of packet
+             * @param slot rx window packet was received
+             */
+            virtual void RxDone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr, lora::DownlinkControl ctrl, uint8_t slot);
+
+            /**
+             * Fired if rx window times out
+             * @param slot rx window that timed out
+             */
+            virtual void RxTimeout(uint8_t slot);
+
+            /**
+             * Fired if rx CRC error
+             * @param slot rx window that errored
+             */
+            virtual void RxError(uint8_t slot);
+
+            /**
+             * Fired if pong packet is received
+             * @param m_rssi of received packet at mote
+             * @param m_snr of received packet at mote
+             * @param s_rssi of received packet at server
+             * @param s_snr of received packet at server
+             */
+            virtual void Pong(int16_t m_rssi, int8_t m_snr, int16_t s_rssi, int8_t s_snr);
+
+            /**
+             * Fired if network link check answer is received
+             * @param m_rssi of received packet at mote
+             * @param m_snr of received packet at mote
+             * @param s_snr margin of received packet at server
+             * @param s_gateways number of gateways reporting the packet
+             */
+            virtual void NetworkLinkCheck(int16_t m_rssi, int8_t m_snr, int8_t s_snr, uint8_t s_gateways);
+
+            /**
+             * Callback to for device to measure the battery level and report to server
+             * @return battery level 0-255, 0 - external power, 1-254 level min-max, 255 device unable to measure battery
+             */
+            virtual uint8_t MeasureBattery();
+
+            /**
+             * Fired when ack attempts are exhausted and RxTimeout or RxError occur
+             * @param retries number of attempts to resend the packet
+             */
+            virtual void MissedAck(uint8_t retries);
+    };
+
+    class Mote {
+        public:
+            Mote(Settings* settings);
+            virtual ~Mote();
+
+            /**
+             * Indicator for network session join status
+             * @return true if joined to network
+             */
+            bool Joined();
+
+            /**
+             * Send join request
+             * @return LORA_OK if request was sent
+             */
+            uint8_t Join();
+
+            /**
+             * Send a packet
+             * @param port to send packet
+             * @param payload of packet
+             * @param size in bytes
+             * @return LORA_OK if successful
+             * @return LORA_MAX_PAYLOAD_EXCEEDED if payload size exceeds datarate maximum
+             * @return LORA_NO_CHANS_ENABLED if there is not an available channel that supports the current datarate
+             * @return LORA_LINK_BUSY if link was busy
+             * @return LORA_RADIO_BUSY if radio was busy
+             * @return LORA_BUFFER_FULL if mac commands filled the packet, client should resend the packet
+             */
+            uint8_t Send(uint8_t port, const uint8_t* payload, uint8_t size);
+
+            /**
+             * Configure the channel plan
+             * @param freqBand EU868, US915, AU915
+             * @return LORA_OK
+             */
+            uint8_t SetChannelPlan(uint8_t freqBand);
+
+            /**
+             * Get the channel mask of currently enabled channels
+             * @return vector containing channel bit masks
+             */
+            std::vector<uint16_t> GetChannelMask();
+
+            /**
+             * Set a 16 bit channel mask with index
+             * @param index of mask to set 0:0-15, 1:16-31 ...
+             * @param mask 16 bit mask of enabled channels
+             * @return true
+             */
+            virtual uint8_t SetChannelMask(uint8_t index, uint16_t mask);
+
+            /**
+             * Set the current channel group for hybrid operation 1-8 else 0 for 64 channel operation
+             * @param group 0-8
+             */
+            uint8_t SetChannelGroup(uint8_t group);
+
+            /**
+             * Get the current channel group
+             * @return group 0-8
+             */
+            uint8_t GetChannelGroup();
+
+            /**
+             * Add a channel to the channel plan
+             * EU868 allows additional channels to be added
+             * Channels 0-2 are fixed default channels
+             *
+             * @param index of the channel
+             * @param frequency of the channel or 0 to remove channel
+             * @param range of datarates allowed by the channel
+             * @return LORA_OK if channel was added
+             */
+            uint8_t AddChannel(uint8_t index, uint32_t frequency, lora::DatarateRange range);
+
+            /**
+             * Set network mode
+             * Choose Public LoRaWAN mode or Private Multitech mode
+             *
+             * Public mode uses 0x34 sync word with 5/6 second join windows
+             * Private mode uses 0x12 sync word with 1/2 second join windows
+             *  US915/AU915 Rx1 and Rx2 are fixed per Channel Group setting
+             *
+             * @param mode public or private
+             * @return LORA_OK
+             */
+            uint8_t SetNetworkMode(uint8_t mode);
+
+            /**
+             * Get a pointer to the mac layer
+             * @return Mac mac
+             */
+            Mac* GetMac();
+
+            /**
+             * Get a pointer to the radio
+             * Can be used to read radio registers or get a random value based on RSSI
+             *
+             * @return SxRadio pointer
+             */
+            SxRadio* GetRadio();
+
+            /**
+             * Get the current statistics for the device
+             * @return Statistics
+             */
+            Statistics& GetStats();
+
+            /**
+             * Get time on air with current settings for provided payload bytes
+             * 13 overhead bytes will be added to payload
+             * @param bytes of payload data
+             * @return time-on-air in ms
+             */
+            uint32_t GetTimeOnAir(uint8_t bytes);
+
+            /**
+             * Call before setting device in sleep mode to place radio in sleep
+             */
+            void Sleep();
+
+        protected:
+            SxRadio1272* _radio;
+            Settings* _settings;
+            Mac* _mac;
+
+        private:
+            ChannelPlan* _plan;
+            MoteEvents _events;
+    };
+
+}
+#endif
Binary file libxDot-ARMCC.ar has changed
Binary file libxDot-GCC_ARM.a has changed
--- a/mDot.h	Thu Sep 22 15:06:54 2016 -0500
+++ b/mDot.h	Thu Sep 22 16:29:07 2016 -0500
@@ -0,0 +1,1321 @@
+// TODO: add license header
+
+#ifndef MDOT_H
+#define MDOT_H
+
+#include "mbed.h"
+#include "rtos.h"
+#include "Mote.h"
+#include <vector>
+#include <map>
+#include <string>
+
+class mDotEvent;
+class LoRaConfig;
+
+class mDot {
+        friend class mDotEvent;
+
+    private:
+
+        mDot();
+        ~mDot();
+
+        void initLora();
+
+        void setLastError(const std::string& str);
+
+        static bool validateBaudRate(const uint32_t& baud);
+        static bool validateFrequencySubBand(const uint8_t& band);
+        bool validateDataRate(const uint8_t& dr);
+
+        int32_t joinBase(const uint32_t& retries);
+        int32_t sendBase(const std::vector<uint8_t>& data, const bool& confirmed = false, const bool& blocking = true, const bool& highBw = false);
+        void waitForPacket();
+        void waitForLinkCheck();
+
+        void setActivityLedState(const uint8_t& state);
+        uint8_t getActivityLedState();
+
+        void blinkActivityLed(void) {
+            if (_activity_led) {
+                int val = _activity_led->read();
+                _activity_led->write(!val);
+            }
+        }
+
+        mDot(const mDot&);
+        mDot& operator=(const mDot&);
+
+        uint32_t RTC_ReadBackupRegister(uint32_t RTC_BKP_DR);
+        void RTC_WriteBackupRegister(uint32_t RTC_BKP_DR, uint32_t Data);
+
+        void wakeup();
+
+        void enterStopMode(const uint32_t& interval, const uint8_t& wakeup_mode = RTC_ALARM);
+        void enterStandbyMode(const uint32_t& interval, const uint8_t& wakeup_mode = RTC_ALARM);
+
+        static mDot* _instance;
+
+        lora::Mote _mote;
+        LoRaConfig* _config;
+        lora::Settings _settings;
+        mDotEvent* _events;
+
+        std::string _last_error;
+        static const uint32_t _baud_rates[];
+        uint8_t _activity_led_state;
+        Ticker _tick;
+        DigitalOut* _activity_led;
+        bool _activity_led_enable;
+        PinName _activity_led_pin;
+        bool _activity_led_external;
+        uint8_t _linkFailCount;
+        uint8_t _class;
+        InterruptIn* _wakeup;
+        PinName _wakeup_pin;
+
+        typedef enum {
+            OFF,
+            ON,
+            BLINK,
+        } state;
+
+    public:
+
+#if defined(TARGET_MTS_MDOT_F411RE)
+        typedef enum {
+            FM_APPEND = (1 << 0),
+            FM_TRUNC = (1 << 1),
+            FM_CREAT = (1 << 2),
+            FM_RDONLY = (1 << 3),
+            FM_WRONLY = (1 << 4),
+            FM_RDWR = (FM_RDONLY | FM_WRONLY),
+            FM_DIRECT = (1 << 5)
+        } FileMode;
+#endif /* TARGET_MTS_MDOT_F411RE */
+
+        typedef enum {
+            MDOT_OK = 0,
+            MDOT_INVALID_PARAM = -1,
+            MDOT_TX_ERROR = -2,
+            MDOT_RX_ERROR = -3,
+            MDOT_JOIN_ERROR = -4,
+            MDOT_TIMEOUT = -5,
+            MDOT_NOT_JOINED = -6,
+            MDOT_ENCRYPTION_DISABLED = -7,
+            MDOT_NO_FREE_CHAN = -8,
+            MDOT_TEST_MODE = -9,
+            MDOT_NO_ENABLED_CHAN = -10,
+            MDOT_AGGREGATED_DUTY_CYCLE = -11,
+            MDOT_MAX_PAYLOAD_EXCEEDED = -12,
+            MDOT_ERROR = -1024,
+        } mdot_ret_code;
+
+        enum JoinMode {
+            MANUAL = 0,
+            OTA,
+            AUTO_OTA,
+            PEER_TO_PEER
+        };
+
+        enum Mode {
+            COMMAND_MODE,
+            SERIAL_MODE
+        };
+
+        enum RX_Output {
+            HEXADECIMAL,
+            BINARY
+        };
+
+        enum DataRates {
+            DR0,
+            DR1,
+            DR2,
+            DR3,
+            DR4,
+            DR5,
+            DR6,
+            DR7,
+            DR8,
+            DR9,
+            DR10,
+            DR11,
+            DR12,
+            DR13,
+            DR14,
+            DR15,
+            SF_12 = 16,
+            SF_11,
+            SF_10,
+            SF_9,
+            SF_8,
+            SF_7,
+            SF_7H,
+            SF_FSK
+        };
+
+        enum FrequencyBands {
+            FB_868 = 0,
+            FB_915 = 1,
+            FB_EU868 = 0, // EU868
+            FB_US915 = 1,  // US915
+            FB_AU915 = 2
+        };
+
+        enum FrequencySubBands {
+            FSB_ALL,
+            FSB_1,
+            FSB_2,
+            FSB_3,
+            FSB_4,
+            FSB_5,
+            FSB_6,
+            FSB_7,
+            FSB_8
+        };
+
+        enum JoinByteOrder {
+            LSB,
+            MSB
+        };
+
+        enum wakeup_mode {
+            RTC_ALARM,
+            INTERRUPT,
+            RTC_ALARM_OR_INTERRUPT
+        };
+
+        enum UserBackupRegs {
+            UBR0,
+            UBR1,
+            UBR2,
+            UBR3,
+            UBR4,
+            UBR5,
+            UBR6,
+            UBR7,
+            UBR8,
+            UBR9
+#if defined (TARGET_XDOT_L151CC)
+           ,UBR10,
+            UBR11,
+            UBR12,
+            UBR13,
+            UBR14,
+            UBR15,
+            UBR16,
+            UBR17,
+            UBR18,
+            UBR19,
+            UBR20,
+            UBR21
+#endif /* TARGET_XDOT_L151CC */
+        };
+
+#if defined(TARGET_MTS_MDOT_F411RE)
+        typedef struct {
+                int16_t fd;
+                char name[33];
+                uint32_t size;
+        } mdot_file;
+#endif /* TARGET_MTS_MDOT_F411RE */
+
+        typedef struct {
+                uint32_t Up;
+                uint32_t Down;
+                uint32_t Joins;
+                uint32_t JoinFails;
+                uint32_t MissedAcks;
+                uint32_t CRCErrors;
+        } mdot_stats;
+
+        typedef struct {
+                int16_t last;
+                int16_t min;
+                int16_t max;
+                int16_t avg;
+        } rssi_stats;
+
+        typedef struct {
+                int16_t last;
+                int16_t min;
+                int16_t max;
+                int16_t avg;
+        } snr_stats;
+
+        typedef struct {
+                bool status;
+                int32_t dBm;
+                uint32_t gateways;
+                std::vector<uint8_t> payload;
+        } link_check;
+
+        typedef struct {
+                int32_t status;
+                int16_t rssi;
+                int16_t snr;
+        } ping_response;
+
+        static const uint8_t MaxLengths_915[];
+        static const uint8_t MaxLengths_868[];
+
+        static std::string JoinModeStr(uint8_t mode);
+        static std::string ModeStr(uint8_t mode);
+        static std::string RxOutputStr(uint8_t format);
+        static std::string DataRateStr(uint8_t rate);
+        static std::string FrequencyBandStr(uint8_t band);
+        static std::string FrequencySubBandStr(uint8_t band);
+
+#if defined(TARGET_MTS_MDOT_F411RE)
+        uint32_t UserRegisters[10];
+#else
+        uint32_t UserRegisters[22];
+#endif /* TARGET_MTS_MDOT_F411RE */
+
+        /** Get a handle to the singleton object
+         * @returns pointer to mDot object
+         */
+        static mDot* getInstance();
+
+        void setEvents(mDotEvent* events);
+
+        /** Get library version information
+         * @returns string containing library version information
+         */
+        std::string getId();
+
+        /** Perform a soft reset of the system
+         */
+        void resetCpu();
+
+        /** Reset config to factory default
+         */
+        void resetConfig();
+
+        /** Save config data to non volatile memory
+         * @returns true if success, false if failure
+         */
+        bool saveConfig();
+
+        /** Set the log level for the library
+         * options are:
+         *  NONE_LEVEL - logging is off at this level
+         *  FATAL_LEVEL - only critical errors will be reported
+         *  ERROR_LEVEL
+         *  WARNING_LEVEL
+         *  INFO_LEVEL
+         *  DEBUG_LEVEL
+         *  TRACE_LEVEL - every detail will be reported
+         * @param level the level to log at
+         * @returns MDOT_OK if success
+         */
+        int32_t setLogLevel(const uint8_t& level);
+
+        /** Get the current log level for the library
+         * @returns current log level
+         */
+        uint8_t getLogLevel();
+
+        /** Seed pseudo RNG in LoRaMac layer, uses random value from radio RSSI reading by default
+         * @param seed for RNG
+         */
+        void seedRandom(uint32_t seed);
+
+        /** Enable or disable the activity LED.
+         * @param enable true to enable the LED, false to disable
+         */
+        void setActivityLedEnable(const bool& enable);
+
+        /** Find out if the activity LED is enabled
+         * @returns true if activity LED is enabled, false if disabled
+         */
+        bool getActivityLedEnable();
+
+        /** Use a different pin for the activity LED.
+         * The default is XBEE_RSSI.
+         * @param pin the new pin to use
+         */
+        void setActivityLedPin(const PinName& pin);
+
+        /** Use an external DigitalOut object for the activity LED.
+         * The pointer must stay valid!
+         * @param pin the DigitalOut object to use
+         */
+        void setActivityLedPin(DigitalOut* pin);
+
+        /** Find out what pin the activity LED is on
+         * @returns the pin the activity LED is using
+         */
+        PinName getActivityLedPin();
+
+        /** Returns boolean indicative of start-up from standby mode
+         * @returns true if dot woke from standby
+         */
+        bool getStandbyFlag();
+
+        std::vector<uint16_t> getChannelMask();
+
+        int32_t setChannelMask(uint8_t offset, uint16_t mask);
+
+        /** Add a channel frequencies currently in use
+         * @returns MDOT_OK
+         */
+        int32_t addChannel(uint8_t index, uint32_t frequency, uint8_t datarateRange);
+
+        /** Get list of channel frequencies currently in use
+         * @returns vector of channels currently in use
+         */
+        std::vector<uint32_t> getChannels();
+
+        /** Get list of channel datarate ranges currently in use
+         * @returns vector of datarate ranges currently in use
+         */
+        std::vector<uint8_t> getChannelRanges();
+
+        /** Get list of channel frequencies in config file to be used as session defaults
+         * @returns vector of channels in config file
+         */
+        std::vector<uint32_t> getConfigChannels();
+
+        /** Get list of channel datarate ranges in config file to be used as session defaults
+         * @returns vector of datarate ranges in config file
+         */
+        std::vector<uint8_t> getConfigChannelRanges();
+
+        /** Get frequency band
+         * @returns FB_915 if configured for United States, FB_868 if configured for Europe
+         */
+        uint8_t getFrequencyBand();
+
+        /** Set frequency sub band
+         * only applicable if frequency band is set for United States (FB_915)
+         * sub band 0 will allow the radio to use all 64 channels
+         * sub band 1 - 8 will allow the radio to use the 8 channels in that sub band
+         * for use with Conduit gateway and MTAC_LORA, use sub bands 1 - 8, not sub band 0
+         * @param band the sub band to use (0 - 8)
+         * @returns MDOT_OK if success
+         */
+        int32_t setFrequencySubBand(const uint8_t& band);
+
+        /** Get frequency sub band
+         * @returns frequency sub band currently in use
+         */
+        uint8_t getFrequencySubBand();
+
+        /** Get the datarate currently in use within the MAC layer
+         * returns 0-15
+         */
+        uint8_t getSessionDataRate();
+
+        /** Enable/disable public network mode
+         * JoinDelay will be set to (public: 5s, private: 1s) and
+         * RxDelay will be set to 1s both can be adjusted afterwards
+         * @param on should be true to enable public network mode
+         * @returns MDOT_OK if success
+         */
+        int32_t setPublicNetwork(const bool& on);
+
+        /** Get public network mode
+         * @returns true if public network mode is enabled
+         */
+        bool getPublicNetwork();
+
+        /** Get the device ID
+         * @returns vector containing the device ID (size 8)
+         */
+        std::vector<uint8_t> getDeviceId();
+
+        /** Get the device port to be used for lora application data (1-223)
+         *  @returns port
+         */
+        uint8_t getAppPort();
+
+        /** Set the device port to be used for lora application data (1-223)
+         *  @returns MDOT_OK if success
+         */
+        int32_t setAppPort(uint8_t port);
+
+        /** Set the device class A, B or C
+         *  @returns MDOT_OK if success
+         */
+        int32_t setClass(std::string newClass);
+
+        /** Get the device class A, B or C
+         *  @returns MDOT_OK if success
+         */
+        std::string getClass();
+
+        /** Get the max packet length with current settings
+         * @returns max packet length
+         */
+        uint8_t getMaxPacketLength();
+
+        /** Set network address
+         * for use with MANUAL network join mode, will be assigned in OTA & AUTO_OTA modes
+         * @param addr a vector of 4 bytes
+         * @returns MDOT_OK if success
+         */
+        int32_t setNetworkAddress(const std::vector<uint8_t>& addr);
+
+        /** Get network address
+         * @returns vector containing network address (size 4)
+         */
+        std::vector<uint8_t> getNetworkAddress();
+
+        /** Set network session key
+         * for use with MANUAL network join mode, will be assigned in OTA & AUTO_OTA modes
+         * @param key a vector of 16 bytes
+         * @returns MDOT_OK if success
+         */
+        int32_t setNetworkSessionKey(const std::vector<uint8_t>& key);
+
+        /** Get network session key
+         * @returns vector containing network session key (size 16)
+         */
+        std::vector<uint8_t> getNetworkSessionKey();
+
+        /** Set data session key
+         * for use with MANUAL network join mode, will be assigned in OTA & AUTO_OTA modes
+         * @param key a vector of 16 bytes
+         * @returns MDOT_OK if success
+         */
+        int32_t setDataSessionKey(const std::vector<uint8_t>& key);
+
+        /** Get data session key
+         * @returns vector containing data session key (size 16)
+         */
+        std::vector<uint8_t> getDataSessionKey();
+
+        /** Set network name
+         * for use with OTA & AUTO_OTA network join modes
+         * generates network ID (crc64 of name) automatically
+         * @param name a string of of at least 8 bytes and no more than 128 bytes
+         * @return MDOT_OK if success
+         */
+        int32_t setNetworkName(const std::string& name);
+
+        /** Get network name
+         * @return string containing network name (size 8 to 128)
+         */
+        std::string getNetworkName();
+
+        /** Set network ID
+         * for use with OTA & AUTO_OTA network join modes
+         * setting network ID via this function sets network name to empty
+         * @param id a vector of 8 bytes
+         * @returns MDOT_OK if success
+         */
+        int32_t setNetworkId(const std::vector<uint8_t>& id);
+
+        /** Get network ID
+         * @returns vector containing network ID (size 8)
+         */
+        std::vector<uint8_t> getNetworkId();
+
+        /** Set network passphrase
+         * for use with OTA & AUTO_OTA network join modes
+         * generates network key (cmac of passphrase) automatically
+         * @param name a string of of at least 8 bytes and no more than 128 bytes
+         * @return MDOT_OK if success
+         */
+        int32_t setNetworkPassphrase(const std::string& passphrase);
+
+        /** Get network passphrase
+         * @return string containing network passphrase (size 8 to 128)
+         */
+        std::string getNetworkPassphrase();
+
+        /** Set network key
+         * for use with OTA & AUTO_OTA network join modes
+         * setting network key via this function sets network passphrase to empty
+         * @param id a vector of 16 bytes
+         * @returns MDOT_OK if success
+         */
+        int32_t setNetworkKey(const std::vector<uint8_t>& id);
+
+        /** Get network key
+         * @returns a vector containing network key (size 16)
+         */
+        std::vector<uint8_t> getNetworkKey();
+
+        /** Set join byte order
+         * @param order 0:LSB 1:MSB
+         */
+        uint32_t setJoinByteOrder(uint8_t order);
+
+        /** Get join byte order
+         * @returns byte order to use in joins 0:LSB 1:MSB
+         */
+        uint8_t getJoinByteOrder();
+
+        /** Attempt to join network
+         * each attempt will be made with a random datarate up to the configured datarate
+         * JoinRequest backoff between tries is enforced to 1% for 1st hour, 0.1% for 1-10 hours and 0.01% after 10 hours
+         * Check getNextTxMs() for time until next join attempt can be made
+         * @returns MDOT_OK if success
+         */
+        int32_t joinNetwork();
+
+        /** Attempts to join network once
+         * @returns MDOT_OK if success
+         */
+        int32_t joinNetworkOnce();
+
+        /** Resets current network session, essentially disconnecting from the network
+         * has no effect for MANUAL network join mode
+         */
+        void resetNetworkSession();
+
+        /** Restore saved network session from flash
+         * has no effect for MANUAL network join mode
+         */
+        void restoreNetworkSession();
+
+        /** Save current network session to flash
+         * has no effect for MANUAL network join mode
+         */
+        void saveNetworkSession();
+
+        /** Set number of times joining will retry each sub-band before changing
+         * to the next subband in US915 and AU915
+         * @param retries must be between 0 - 255
+         * @returns MDOT_OK if success
+         */
+        int32_t setJoinRetries(const uint8_t& retries);
+
+        /** Get number of times joining will retry each sub-band
+         * @returns join retries (0 - 255)
+         */
+        uint8_t getJoinRetries();
+
+        /** Set network join mode
+         * MANUAL: set network address and session keys manually
+         * OTA: User sets network name and passphrase, then attempts to join
+         * AUTO_OTA: same as OTA, but network sessions can be saved and restored
+         * @param mode MANUAL, OTA, or AUTO_OTA
+         * @returns MDOT_OK if success
+         */
+        int32_t setJoinMode(const uint8_t& mode);
+
+        /** Get network join mode
+         * @returns MANUAL, OTA, or AUTO_OTA
+         */
+        uint8_t getJoinMode();
+
+        /** Get network join status
+         * @returns true if currently joined to network
+         */
+        bool getNetworkJoinStatus();
+
+        /** Do a network link check
+         * application data may be returned in response to a network link check command
+         * @returns link_check structure containing success, dBm above noise floor, gateways in range, and packet payload
+         */
+        link_check networkLinkCheck();
+
+        /** Set network link check count to perform automatic link checks every count packets
+         * only applicable if ACKs are disabled
+         * @param count must be between 0 - 255
+         * @returns MDOT_OK if success
+         */
+        int32_t setLinkCheckCount(const uint8_t& count);
+
+        /** Get network link check count
+         * @returns count (0 - 255)
+         */
+        uint8_t getLinkCheckCount();
+
+        /** Set network link check threshold, number of link check failures or missed acks to tolerate
+         * before considering network connection lost
+         * @pararm count must be between 0 - 255
+         * @returns MDOT_OK if success
+         */
+        int32_t setLinkCheckThreshold(const uint8_t& count);
+
+        /** Get network link check threshold
+         * @returns threshold (0 - 255)
+         */
+        uint8_t getLinkCheckThreshold();
+
+        /** Get/set number of failed link checks in the current session
+         * @returns count (0 - 255)
+         */
+        uint8_t getLinkFailCount();
+        int32_t setLinkFailCount(uint8_t count);
+
+        /** Set UpLinkCounter number of packets sent to the gateway during this network session (sequence number)
+         * @returns MDOT_OK
+         */
+        int32_t setUpLinkCounter(uint32_t count);
+
+        /** Get UpLinkCounter
+         * @returns number of packets sent to the gateway during this network session (sequence number)
+         */
+        uint32_t getUpLinkCounter();
+
+        /** Set UpLinkCounter number of packets sent by the gateway during this network session (sequence number)
+         * @returns MDOT_OK
+         */
+        int32_t setDownLinkCounter(uint32_t count);
+
+        /** Get DownLinkCounter
+         * @returns number of packets sent by the gateway during this network session (sequence number)
+         */
+        uint32_t getDownLinkCounter();
+
+        /** Enable/disable AES encryption
+         * AES encryption must be enabled for use with Conduit gateway and MTAC_LORA card
+         * @param on true for AES encryption to be enabled
+         * @returns MDOT_OK if success
+         */
+        int32_t setAesEncryption(const bool& on);
+
+        /** Get AES encryption
+         * @returns true if AES encryption is enabled
+         */
+        bool getAesEncryption();
+
+        /** Get RSSI stats
+         * @returns rssi_stats struct containing last, min, max, and avg RSSI in dB
+         */
+        rssi_stats getRssiStats();
+
+        /** Get SNR stats
+         * @returns snr_stats struct containing last, min, max, and avg SNR in cB
+         */
+        snr_stats getSnrStats();
+
+        /** Get ms until next free channel
+         * only applicable for European models, US models return 0
+         * @returns time (ms) until a channel is free to use for transmitting
+         */
+        uint32_t getNextTxMs();
+
+        /** Get join delay in seconds
+         *  Public network defaults to 5 seconds
+         *  Private network defaults to 1 second
+         *  @returns number of seconds before join accept message is expected
+         */
+        uint8_t getJoinDelay();
+
+        /** Set join delay in seconds
+         *  Public network defaults to 5 seconds
+         *  Private network defaults to 1 second
+         *  @param delay number of seconds before join accept message is expected
+         *  @return MDOT_OK if success
+         */
+        uint32_t setJoinDelay(uint8_t delay);
+
+        /** Get join Rx1 datarate offset
+         *  defaults to 0
+         *  @returns offset
+         */
+        uint8_t getJoinRx1DataRateOffset();
+
+        /** Set join Rx1 datarate offset
+         *  @param offset for datarate
+         *  @return MDOT_OK if success
+         */
+        uint32_t setJoinRx1DataRateOffset(uint8_t offset);
+
+        /** Get join Rx2 datarate
+         *  defaults to US:DR8, AU:DR8, EU:DR0
+         *  @returns datarate
+         */
+        uint8_t getJoinRx2DataRate();
+
+        /** Set join Rx2 datarate
+         *  @param datarate
+         *  @return MDOT_OK if success
+         */
+        uint32_t setJoinRx2DataRate(uint8_t datarate);
+
+        /** Get join Rx2 frequency
+         *  defaults US:923.3, AU:923.3, EU:869.525
+         *  @returns frequency
+         */
+        uint32_t getJoinRx2Frequency();
+
+        /** Set join Rx2 frequency
+         *  @param frequency
+         *  @return MDOT_OK if success
+         */
+        uint32_t setJoinRx2Frequency(uint32_t frequency);
+
+        /** Get rx delay in seconds
+         *  Defaults to 1 second
+         *  @returns number of seconds before response message is expected
+         */
+        uint8_t getRxDelay();
+
+        /** Set rx delay in seconds
+         *  Defaults to 1 second
+         *  @param delay number of seconds before response message is expected
+         *  @return MDOT_OK if success
+         */
+        uint32_t setRxDelay(uint8_t delay);
+
+        /** Get  preserve session to save network session info through reset or power down in AUTO_OTA mode
+         *  Defaults to off
+         *  @returns true if enabled
+         */
+        bool getPreserveSession();
+
+        /** Set preserve session to save network session info through reset or power down in AUTO_OTA mode
+         *  Defaults to off
+         *  @param enable
+         *  @return MDOT_OK if success
+         */
+        uint32_t setPreserveSession(bool enable);
+
+        /** Get data pending
+         * only valid after sending data to the gateway
+         * @returns true if server has available packet(s)
+         */
+        bool getDataPending();
+
+        /** Get ack requested
+         * only valid after sending data to the gateway
+         * @returns true if server has requested ack
+         */
+        bool getAckRequested();
+
+        /** Get is transmitting indicator
+         * @returns true if currently transmitting
+         */
+        bool getIsTransmitting();
+
+        /** Get is idle indicator
+         * @returns true if not currently transmitting, waiting or receiving
+         */
+        bool getIsIdle();
+
+        /** Set TX data rate
+         * data rates affect maximum payload size
+         * @param dr SF_7 - SF_12|DR0-DR7 for Europe, SF_7 - SF_10 | DR0-DR4 for United States
+         * @returns MDOT_OK if success
+         */
+        int32_t setTxDataRate(const uint8_t& dr);
+
+        /** Get TX data rate
+         * @returns current TX data rate (DR0-DR15)
+         */
+        uint8_t getTxDataRate();
+
+        /** Get a random value from the radio based on RSSI
+         *  @returns randome value
+         */
+        uint32_t getRadioRandom();
+
+        /** Get data rate spreading factor and bandwidth
+         * EU868 Datarates
+         * ---------------
+         * DR0 - SF12BW125
+         * DR1 - SF11BW125
+         * DR2 - SF10BW125
+         * DR3 - SF9BW125
+         * DR4 - SF8BW125
+         * DR5 - SF7BW125
+         * DR6 - SF7BW250
+         * DR7 - FSK
+         *
+         * US915 Datarates
+         * ---------------
+         * DR0 - SF10BW125
+         * DR1 - SF9BW125
+         * DR2 - SF8BW125
+         * DR3 - SF7BW125
+         * DR4 - SF8BW500
+         *
+         * AU915 Datarates
+         * ---------------
+         * DR0 - SF10BW125
+         * DR1 - SF9BW125
+         * DR2 - SF8BW125
+         * DR3 - SF7BW125
+         * DR4 - SF8BW500
+         *
+         * @returns spreading factor and bandwidth
+         */
+        std::string getDateRateDetails(uint8_t rate);
+
+        /** Set TX power output of radio before antenna gain, default: 14 dBm
+         * actual output power may be limited by local regulations for the chosen frequency
+         * power affects maximum range
+         * @param power 2 dBm - 20 dBm
+         * @returns MDOT_OK if success
+         */
+        int32_t setTxPower(const uint32_t& power);
+
+        /** Get TX power
+         * @returns TX power (2 dBm - 20 dBm)
+         */
+        uint32_t getTxPower();
+
+        /** Get configured gain of installed antenna, default: +3 dBi
+         * @returns gain of antenna in dBi
+         */
+        int8_t getAntennaGain();
+
+        /** Set configured gain of installed antenna, default: +3 dBi
+         * @param gain -127 dBi - 128 dBi
+         * @returns MDOT_OK if success
+         */
+        int32_t setAntennaGain(int8_t gain);
+
+        /** Enable/disable TX waiting for rx windows
+         * when enabled, send calls will block until a packet is received or RX timeout
+         * @param enable set to true if expecting responses to transmitted packets
+         * @returns MDOT_OK if success
+         */
+        int32_t setTxWait(const bool& enable);
+
+        /** Get TX wait
+         * @returns true if TX wait is enabled
+         */
+        bool getTxWait();
+
+        /** Cancel pending rx windows
+         */
+        void cancelRxWindow();
+
+        /** Get time on air
+         * @returns the amount of time (in ms) it would take to send bytes bytes based on current configuration
+         */
+        uint32_t getTimeOnAir(uint8_t bytes);
+
+        /** Get min frequency
+         * @returns minimum frequency based on current configuration
+         */
+        uint32_t getMinFrequency();
+
+        /** Get max frequency
+         * @returns maximum frequency based on current configuration
+         */
+        uint32_t getMaxFrequency();
+
+        // get/set adaptive data rate
+        // configure data rates and power levels based on signal to noise of packets received at gateway
+        // true == adaptive data rate is on
+        // set function returns MDOT_OK if success
+        int32_t setAdr(const bool& on);
+        bool getAdr();
+
+        /** Set forward error correction bytes
+         * @param bytes 1 - 4 bytes
+         * @returns MDOT_OK if success
+         */
+        int32_t setFec(const uint8_t& bytes);
+
+        /** Get forward error correction bytes
+         * @returns bytes (1 - 4)
+         */
+        uint8_t getFec();
+
+        /** Enable/disable CRC checking of packets
+         * CRC checking must be enabled for use with Conduit gateway and MTAC_LORA card
+         * @param on set to true to enable CRC checking
+         * @returns MDOT_OK if success
+         */
+        int32_t setCrc(const bool& on);
+
+        /** Get CRC checking
+         * @returns true if CRC checking is enabled
+         */
+        bool getCrc();
+
+        /** Set ack
+         * @param retries 0 to disable acks, otherwise 1 - 8
+         * @returns MDOT_OK if success
+         */
+        int32_t setAck(const uint8_t& retries);
+
+        /** Get ack
+         * @returns 0 if acks are disabled, otherwise retries (1 - 8)
+         */
+        uint8_t getAck();
+
+        /** Set number of packet repeats for unconfirmed frames
+         * @param repeat 0 or 1 for no repeats, otherwise 2-15
+         * @returns MDOT_OK if success
+         */
+        int32_t setRepeat(const uint8_t& repeat);
+
+        /** Get number of packet repeats for unconfirmed frames
+         * @returns 0 or 1 if no repeats, otherwise 2-15
+         */
+        uint8_t getRepeat();
+
+        /** Send data to the gateway
+         * validates data size (based on spreading factor)
+         * @param data a vector of up to 242 bytes (may be less based on spreading factor)
+         * @returns MDOT_OK if packet was sent successfully (ACKs disabled), or if an ACK was received (ACKs enabled)
+         */
+        int32_t send(const std::vector<uint8_t>& data, const bool& blocking = true, const bool& highBw = false);
+
+        /** Inject mac command
+         * @param data a vector containing mac commands
+         * @returns MDOT_OK
+         */
+        int32_t injectMacCommand(const std::vector<uint8_t>& data);
+
+        /**
+         * Clear MAC command buffer to be sent in next uplink
+         * @returns MDOT_OK
+         */
+        int32_t clearMacCommands();
+
+        /**
+         * Get MAC command buffer to be sent in next uplink
+         * @returns command bytes
+         */
+        std::vector<uint8_t> getMacCommands();
+
+        /** Fetch data received from the gateway
+         * this function only checks to see if a packet has been received - it does not open a receive window
+         * send() must be called before recv()
+         * @param data a vector to put the received data into
+         * @returns MDOT_OK if packet was successfully received
+         */
+        int32_t recv(std::vector<uint8_t>& data);
+
+        /** Ping
+         * status will be MDOT_OK if ping succeeded
+         * @returns ping_response struct containing status, RSSI, and SNR
+         */
+        ping_response ping();
+
+        /** Get return code string
+         * @returns string containing a description of the given error code
+         */
+        static std::string getReturnCodeString(const int32_t& code);
+
+        /** Get last error
+         * @returns string explaining the last error that occured
+         */
+        std::string getLastError();
+
+        /** Go to sleep
+         * @param interval the number of seconds to sleep before waking up if wakeup_mode == RTC_ALARM or RTC_ALARM_OR_INTERRUPT, else ignored
+         * @param wakeup_mode RTC_ALARM, INTERRUPT, RTC_ALARM_OR_INTERRUPT
+         *      if RTC_ALARM the real time clock is configured to wake the device up after the specified interval
+         *      if INTERRUPT the device will wake up on the rising edge of the interrupt pin
+         *      if RTC_ALARM_OR_INTERRUPT the device will wake on the first event to occur
+         * @param deepsleep if true go into deep sleep mode (lowest power, all memory and registers are lost, peripherals turned off)
+         *                  else go into sleep mode (low power, memory and registers are maintained, peripherals stay on)
+         *
+         * For the MDOT
+         *      in sleep mode, the device can be woken up on an XBEE_DI (2-8) pin or by the RTC alarm
+         *      in deepsleep mode, the device can only be woken up using the WKUP pin (PA0, XBEE_DIO7) or by the RTC alarm
+         * For the XDOT
+         *      in sleep mode, the device can be woken up on GPIO (0-3), UART1_RX, WAKE or by the RTC alarm
+         *      in deepsleep mode, the device can only be woken up using the WKUP pin (PA0, WAKE) or by the RTC alarm
+         */
+        void sleep(const uint32_t& interval, const uint8_t& wakeup_mode = RTC_ALARM, const bool& deepsleep = true);
+
+        /** Set wake pin
+         * @param pin the pin to use to wake the device from sleep mode
+         *      For MDOT, XBEE_DI (2-8)
+         *      For XDOT, GPIO (0-3), UART1_RX, or WAKE
+         */
+        void setWakePin(const PinName& pin);
+
+        /** Get wake pin
+         * @returns the pin to use to wake the device from sleep mode
+         *      For MDOT, XBEE_DI (2-8)
+         *      For XDOT, GPIO (0-3), UART1_RX, or WAKE
+         */
+        PinName getWakePin();
+
+        /** Write data in a user backup register
+         * @param register one of UBR0 through UBR9 for MDOT, one of UBR0 through UBR21 for XDOT
+         * @param data user data to back up
+         * @returns true if success
+         */
+        bool writeUserBackupRegister(uint32_t reg, uint32_t data);
+
+        /** Read data in a user backup register
+         * @param register one of UBR0 through UBR9 for MDOT, one of UBR0 through UBR21 for XDOT
+         * @param data gets set to content of register
+         * @returns true if success
+         */
+        bool readUserBackupRegister(uint32_t reg, uint32_t& data);
+
+#if defined(TARGET_MTS_MDOT_F411RE)
+        ///////////////////////////////////////////////////////////////////
+        // Filesystem (Non Volatile Memory) Operation Functions for mDot //
+        ///////////////////////////////////////////////////////////////////
+
+        // Save user file data to flash
+        // file - name of file max 30 chars
+        // data - data of file
+        // size - size of file
+        // returns true if successful
+        bool saveUserFile(const char* file, void* data, uint32_t size);
+
+        // Append user file data to flash
+        // file - name of file max 30 chars
+        // data - data of file
+        // size - size of file
+        // returns true if successful
+        bool appendUserFile(const char* file, void* data, uint32_t size);
+
+        // Read user file data from flash
+        // file - name of file max 30 chars
+        // data - data of file
+        // size - size of file
+        // returns true if successful
+        bool readUserFile(const char* file, void* data, uint32_t size);
+
+        // Move a user file in flash
+        // file     - name of file
+        // new_name - new name of file
+        // returns true if successful
+        bool moveUserFile(const char* file, const char* new_name);
+
+        // Delete user file data from flash
+        // file - name of file max 30 chars
+        // returns true if successful
+        bool deleteUserFile(const char* file);
+
+        // Open user file in flash, max of 4 files open concurrently
+        // file - name of file max 30 chars
+        // mode - combination of FM_APPEND | FM_TRUNC | FM_CREAT |
+        //                       FM_RDONLY | FM_WRONLY | FM_RDWR | FM_DIRECT
+        // returns - mdot_file struct, fd field will be a negative value if file could not be opened
+        mDot::mdot_file openUserFile(const char* file, int mode);
+
+        // Seek an open file
+        // file - mdot file struct
+        // offset - offset in bytes
+        // whence - where offset is based SEEK_SET, SEEK_CUR, SEEK_END
+        // returns true if successful
+        bool seekUserFile(mDot::mdot_file& file, size_t offset, int whence);
+
+        // Read bytes from open file
+        // file - mdot file struct
+        // data - mem location to store data
+        // length - number of bytes to read
+        // returns - number of bytes read, negative if error
+        int readUserFile(mDot::mdot_file& file, void* data, size_t length);
+
+        // Write bytes to open file
+        // file - mdot file struct
+        // data - data to write
+        // length - number of bytes to write
+        // returns - number of bytes written, negative if error
+        int writeUserFile(mDot::mdot_file& file, void* data, size_t length);
+
+        // Close open file
+        // file - mdot file struct
+        // returns true if successful
+        bool closeUserFile(mDot::mdot_file& file);
+
+        // List user files stored in flash
+        std::vector<mDot::mdot_file> listUserFiles();
+
+        // Move file into the firmware upgrade path to be flashed on next boot
+        // file - name of file
+        // returns true if successful
+        bool moveUserFileToFirmwareUpgrade(const char* file);
+#else
+        ///////////////////////////////////////////////////////////////
+        // EEPROM (Non Volatile Memory) Operation Functions for xDot //
+        ///////////////////////////////////////////////////////////////
+        
+        // Write to EEPROM
+        // addr - address to write to (0 - 0x17FF)
+        // data - data to write
+        // size - size of data
+        // returns true if successful
+        bool nvmWrite(uint16_t addr, void* data, uint16_t size);
+
+        // Read from EEPROM
+        // addr - address to read from (0 - 0x17FF)
+        // data - buffer for data
+        // size - size of buffer
+        // returns true if successful
+        bool nvmRead(uint16_t addr, void* data, uint16_t size);
+#endif /* TARGET_MTS_MDOT_F411RE */
+
+        // get current statistics
+        // Join Attempts, Join Fails, Up Packets, Down Packets, Missed Acks
+        mdot_stats getStats();
+
+        // reset statistics
+        // Join Attempts, Join Fails, Up Packets, Down Packets, Missed Acks
+        void resetStats();
+
+        // Convert pin number 2-8 to pin name DIO2-DI8
+        static PinName pinNum2Name(uint8_t num);
+
+        // Convert pin name DIO2-DI8 to pin number 2-8
+        static uint8_t pinName2Num(PinName name);
+
+        // Convert pin name DIO2-DI8 to string
+        static std::string pinName2Str(PinName name);
+
+        uint64_t crc64(uint64_t crc, const unsigned char *s, uint64_t l);
+
+        /*************************************************************************
+         * The following functions are only used by the AT command application and
+         * should not be used by standard applications consuming the mDot library
+         ************************************************************************/
+
+        // set/get configured baud rate for command port
+        // only for use in conjunction with AT interface
+        // set function returns MDOT_OK if success
+        int32_t setBaud(const uint32_t& baud);
+        uint32_t getBaud();
+
+        // set/get baud rate for debug port
+        // set function returns MDOT_OK if success
+        int32_t setDebugBaud(const uint32_t& baud);
+        uint32_t getDebugBaud();
+
+        // set/get command terminal echo
+        // set function returns MDOT_OK if success
+        int32_t setEcho(const bool& on);
+        bool getEcho();
+
+        // set/get command terminal verbose mode
+        // set function returns MDOT_OK if success
+        int32_t setVerbose(const bool& on);
+        bool getVerbose();
+
+        // set/get startup mode
+        // COMMAND_MODE (default), starts up ready to accept AT commands
+        // SERIAL_MODE, read serial data and send it as LoRa packets
+        // set function returns MDOT_OK if success
+        int32_t setStartUpMode(const uint8_t& mode);
+        uint8_t getStartUpMode();
+
+        int32_t setRxDataRate(const uint8_t& dr);
+        uint8_t getRxDataRate();
+
+        // get/set TX/RX frequency
+        // if frequency band == FB_868 (Europe), must be between 863000000 - 870000000
+        // if frequency band == FB_915 (United States), must be between 902000000-928000000
+        // if set to 0, device will hop frequencies
+        // set function returns MDOT_OK if success
+        int32_t setTxFrequency(const uint32_t& freq);
+        uint32_t getTxFrequency();
+        int32_t setRxFrequency(const uint32_t& freq);
+        uint32_t getRxFrequency();
+
+        // get/set TX/RX inverted
+        // true == signal is inverted
+        // set function returns MDOT_OK if success
+        int32_t setTxInverted(const bool& on);
+        bool getTxInverted();
+        int32_t setRxInverted(const bool& on);
+        bool getRxInverted();
+
+        // get/set RX output mode
+        // valid options are HEXADECIMAL and BINARY
+        // set function returns MDOT_OK if success
+        int32_t setRxOutput(const uint8_t& mode);
+        uint8_t getRxOutput();
+
+        // get/set serial wake interval
+        // valid values are 2 s - INT_MAX (2147483647) s
+        // set function returns MDOT_OK if success
+        int32_t setWakeInterval(const uint32_t& interval);
+        uint32_t getWakeInterval();
+
+        // get/set serial wake delay
+        // valid values are 2 ms - INT_MAX (2147483647) ms
+        // set function returns MDOT_OK if success
+        int32_t setWakeDelay(const uint32_t& delay);
+        uint32_t getWakeDelay();
+
+        // get/set serial receive timeout
+        // valid values are 0 ms - 65000 ms
+        // set function returns MDOT_OK if success
+        int32_t setWakeTimeout(const uint16_t& timeout);
+        uint16_t getWakeTimeout();
+
+        // get/set serial wake mode
+        // valid values are INTERRUPT or RTC_ALARM
+        // set function returns MDOT_OK if success
+        int32_t setWakeMode(const uint8_t& delay);
+        uint8_t getWakeMode();
+
+        // get/set serial flow control enabled
+        // set function returns MDOT_OK if success
+        int32_t setFlowControl(const bool& on);
+        bool getFlowControl();
+
+        // get/set serial clear on error
+        // if enabled the data read from the serial port will be discarded if it cannot be sent or if the send fails
+        // set function returns MDOT_OK if success
+        int32_t setSerialClearOnError(const bool& on);
+        bool getSerialClearOnError();
+
+        // MTS_RADIO_DEBUG_COMMANDS
+
+        /** Disable Duty cycle
+         * enables or disables the duty cycle limitations
+         * **** ONLY TO BE USED FOR TESTINGS PURPOSES ****
+         * **** ALL DEPLOYABLE CODE MUST ADHERE TO LOCAL REGULATIONS ****
+         * **** THIS SETTING WILL NOT BE SAVED TO CONFIGURATION *****
+         * @param val true to disable duty-cycle (default:false)
+         */
+        int32_t setDisableDutyCycle(bool val);
+
+        /** Disable Duty cycle
+         * **** ONLY TO BE USED FOR TESTINGS PURPOSES ****
+         * **** ALL DEPLOYABLE CODE MUST ADHERE TO LOCAL REGULATIONS ****
+         * **** THIS SETTING WILL NOT BE SAVED TO CONFIGURATION *****
+         * @return true if duty-cycle is disabled (default:false)
+         */
+        uint8_t getDisableDutyCycle();
+
+        void openRxWindow(uint32_t timeout, uint8_t bandwidth = 0);
+        void closeRxWindow();
+        void sendContinuous(bool enable=true);
+        int32_t setDeviceId(const std::vector<uint8_t>& id);
+        int32_t setFrequencyBand(const uint8_t& band);
+        bool saveProtectedConfig();
+        void resetRadio();
+        int32_t setRadioMode(const uint8_t& mode);
+        std::map<uint8_t, uint8_t> dumpRegisters();
+        void eraseFlash();
+
+        // deprecated - use setWakeInterval
+        int32_t setSerialWakeInterval(const uint32_t& interval);
+        // deprecated - use getWakeInterval
+        uint32_t getSerialWakeInterval();
+
+        // deprecated - use setWakeDelay
+        int32_t setSerialWakeDelay(const uint32_t& delay);
+        // deprecated - use setWakeDelay
+        uint32_t getSerialWakeDelay();
+
+        // deprecated - use setWakeTimeout
+        int32_t setSerialReceiveTimeout(const uint16_t& timeout);
+        // deprecated - use getWakeTimeout
+        uint16_t getSerialReceiveTimeout();
+
+        void setWakeupCallback(void (*function)(void));
+
+        template<typename T>
+        void setWakeupCallback(T *object, void (T::*member)(void)) {
+            _wakeup_callback.attach(object, member);
+        }
+
+    private:
+        mdot_stats _stats;
+
+        FunctionPointer _wakeup_callback;
+
+        bool _standbyFlag;
+        bool _testMode;
+        uint8_t _savedPort;
+        void handleTestModePacket();
+
+};
+
+#endif
--- a/mDotEvent.h	Thu Sep 22 15:06:54 2016 -0500
+++ b/mDotEvent.h	Thu Sep 22 16:29:07 2016 -0500
@@ -0,0 +1,304 @@
+#ifndef MDOT_EVENT_H
+#define MDOT_EVENT_H
+
+#include "mDot.h"
+#include "MacEvents.h"
+#include "MTSLog.h"
+#include "MTSText.h"
+
+typedef union {
+        uint8_t Value;
+        struct {
+                uint8_t :1;
+                uint8_t Tx :1;
+                uint8_t Rx :1;
+                uint8_t RxData :1;
+                uint8_t RxSlot :2;
+                uint8_t LinkCheck :1;
+                uint8_t JoinAccept :1;
+        } Bits;
+} LoRaMacEventFlags;
+
+typedef enum {
+    LORAMAC_EVENT_INFO_STATUS_OK = 0,
+    LORAMAC_EVENT_INFO_STATUS_ERROR,
+    LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT,
+    LORAMAC_EVENT_INFO_STATUS_RX_TIMEOUT,
+    LORAMAC_EVENT_INFO_STATUS_RX_ERROR,
+    LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL,
+    LORAMAC_EVENT_INFO_STATUS_DOWNLINK_FAIL,
+    LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL,
+    LORAMAC_EVENT_INFO_STATUS_MIC_FAIL,
+} LoRaMacEventInfoStatus;
+
+/*!
+ * LoRaMAC event information
+ */
+typedef struct {
+        LoRaMacEventInfoStatus Status;
+        lora::DownlinkControl Ctrl;
+        bool TxAckReceived;
+        uint8_t TxNbRetries;
+        uint8_t TxDatarate;
+        uint8_t RxPort;
+        uint8_t *RxBuffer;
+        uint8_t RxBufferSize;
+        int16_t RxRssi;
+        uint8_t RxSnr;
+        uint16_t Energy;
+        uint8_t DemodMargin;
+        uint8_t NbGateways;
+} LoRaMacEventInfo;
+
+class mDotEvent: public lora::MacEvents {
+    public:
+
+        mDotEvent()
+        :
+          LinkCheckAnsReceived(false),
+          DemodMargin(0),
+          NbGateways(0),
+          PacketReceived(false),
+          RxPort(0),
+          RxPayloadSize(0),
+          PongReceived(false),
+          PongRssi(0),
+          PongSnr(0),
+          AckReceived(false),
+          TxNbRetries(0)
+        {
+            memset(&_flags, 0, sizeof(LoRaMacEventFlags));
+            memset(&_info, 0, sizeof(LoRaMacEventInfo));
+        }
+
+        virtual ~mDotEvent() {
+        }
+
+        virtual void MacEvent(LoRaMacEventFlags *flags, LoRaMacEventInfo *info) {
+            if (mts::MTSLog::getLogLevel() == mts::MTSLog::TRACE_LEVEL) {
+                std::string msg = "OK";
+                switch (info->Status) {
+                    case LORAMAC_EVENT_INFO_STATUS_ERROR:
+                        msg = "ERROR";
+                        break;
+                    case LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT:
+                        msg = "TX_TIMEOUT";
+                        break;
+                    case LORAMAC_EVENT_INFO_STATUS_RX_TIMEOUT:
+                        msg = "RX_TIMEOUT";
+                        break;
+                    case LORAMAC_EVENT_INFO_STATUS_RX_ERROR:
+                        msg = "RX_ERROR";
+                        break;
+                    case LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL:
+                        msg = "JOIN_FAIL";
+                        break;
+                    case LORAMAC_EVENT_INFO_STATUS_DOWNLINK_FAIL:
+                        msg = "DOWNLINK_FAIL";
+                        break;
+                    case LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL:
+                        msg = "ADDRESS_FAIL";
+                        break;
+                    case LORAMAC_EVENT_INFO_STATUS_MIC_FAIL:
+                        msg = "MIC_FAIL";
+                        break;
+                    default:
+                        break;
+                }
+                logTrace("Event: %s", msg.c_str());
+
+                logTrace("Flags Tx: %d Rx: %d RxData: %d RxSlot: %d LinkCheck: %d JoinAccept: %d",
+                         flags->Bits.Tx, flags->Bits.Rx, flags->Bits.RxData, flags->Bits.RxSlot, flags->Bits.LinkCheck, flags->Bits.JoinAccept);
+                logTrace("Info: Status: %d ACK: %d Retries: %d TxDR: %d RxPort: %d RxSize: %d RSSI: %d SNR: %d Energy: %d Margin: %d Gateways: %d",
+                         info->Status, info->TxAckReceived, info->TxNbRetries, info->TxDatarate, info->RxPort, info->RxBufferSize,
+                         info->RxRssi, info->RxSnr, info->Energy, info->DemodMargin, info->NbGateways);
+            }
+        }
+
+        virtual void TxDone(uint8_t dr) {
+            RxPayloadSize = 0;
+            LinkCheckAnsReceived = false;
+            PacketReceived = false;
+            AckReceived = false;
+            PongReceived = false;
+            TxNbRetries = 0;
+
+            logDebug("mDotEvent - TxDone");
+            memset(&_flags, 0, sizeof(LoRaMacEventFlags));
+            memset(&_info, 0, sizeof(LoRaMacEventInfo));
+
+            _flags.Bits.Tx = 1;
+            _info.TxDatarate = dr;
+            _info.Status = LORAMAC_EVENT_INFO_STATUS_OK;
+            Notify();
+        }
+
+        void Notify() {
+            MacEvent(&_flags, &_info);
+        }
+
+        virtual void TxTimeout(void) {
+            logDebug("mDotEvent - TxTimeout");
+
+            _flags.Bits.Tx = 1;
+            _info.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
+            Notify();
+        }
+
+        virtual void JoinAccept(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr) {
+            logDebug("mDotEvent - JoinAccept");
+
+            _flags.Bits.Tx = 0;
+            _flags.Bits.JoinAccept = 1;
+            _info.Status = LORAMAC_EVENT_INFO_STATUS_OK;
+            Notify();
+        }
+
+        virtual void JoinFailed(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr) {
+            logDebug("mDotEvent - JoinFailed");
+
+            _flags.Bits.Tx = 0;
+            _flags.Bits.JoinAccept = 1;
+            _info.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
+            Notify();
+        }
+
+        virtual void MissedAck(uint8_t retries) {
+            logDebug("mDotEvent - MissedAck : retries %u", retries);
+            TxNbRetries = retries;
+            _info.TxNbRetries = retries;
+        }
+
+        virtual void PacketRx(uint8_t port, uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr, lora::DownlinkControl ctrl, uint8_t slot, uint8_t retries = 0) {
+            logDebug("mDotEvent - PacketRx");
+            RxPort = port;
+            PacketReceived = true;
+
+            memcpy(RxPayload, payload, size);
+            RxPayloadSize = size;
+
+            if (ctrl.Bits.Ack) {
+                AckReceived = true;
+            }
+
+            if (mts::MTSLog::getLogLevel() == mts::MTSLog::TRACE_LEVEL) {
+                std::string packet = mts::Text::bin2hexString(RxPayload, size);
+                logTrace("Payload: %s", packet.c_str());
+            }
+
+            _flags.Bits.Tx = 0;
+            _flags.Bits.Rx = 1;
+            _flags.Bits.RxData = size > 0;
+            _flags.Bits.RxSlot = slot;
+            _info.RxBuffer = payload;
+            _info.RxBufferSize = size;
+            _info.RxPort = port;
+            _info.RxRssi = rssi;
+            _info.RxSnr = snr;
+            _info.TxAckReceived = AckReceived;
+            _info.TxNbRetries = retries;
+            _info.Status = LORAMAC_EVENT_INFO_STATUS_OK;
+            Notify();
+        }
+
+        virtual void RxDone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr, lora::DownlinkControl ctrl, uint8_t slot) {
+            logDebug("mDotEvent - RxDone");
+        }
+
+        virtual void Pong(int16_t m_rssi, int8_t m_snr, int16_t s_rssi, int8_t s_snr) {
+            logDebug("mDotEvent - Pong");
+            PongReceived = true;
+            PongRssi = s_rssi;
+            PongSnr = s_snr;
+        }
+
+        virtual void NetworkLinkCheck(int16_t m_rssi, int8_t m_snr, int8_t s_snr, uint8_t s_gateways) {
+            logDebug("mDotEvent - NetworkLinkCheck");
+            LinkCheckAnsReceived = true;
+            DemodMargin = s_snr;
+            NbGateways = s_gateways;
+
+            _flags.Bits.Tx = 0;
+            _flags.Bits.LinkCheck = 1;
+            _info.RxRssi = m_rssi;
+            _info.RxSnr = m_snr;
+            _info.DemodMargin = s_snr;
+            _info.NbGateways = s_gateways;
+            _info.Status = LORAMAC_EVENT_INFO_STATUS_OK;
+            Notify();
+        }
+
+        virtual void RxTimeout(uint8_t slot) {
+            // logDebug("mDotEvent - RxTimeout");
+
+            _flags.Bits.Tx = 0;
+            _flags.Bits.RxSlot = slot;
+            _info.Status = LORAMAC_EVENT_INFO_STATUS_RX_TIMEOUT;
+            Notify();
+        }
+
+        virtual void RxError(uint8_t slot) {
+            logDebug("mDotEvent - RxError");
+
+            memset(&_flags, 0, sizeof(LoRaMacEventFlags));
+            memset(&_info, 0, sizeof(LoRaMacEventInfo));
+
+            _flags.Bits.RxSlot = slot;
+            _info.Status = LORAMAC_EVENT_INFO_STATUS_RX_ERROR;
+            Notify();
+        }
+
+        virtual uint8_t MeasureBattery(void) {
+            return 255;
+        }
+
+        bool LinkCheckAnsReceived;
+        uint8_t DemodMargin;
+        uint8_t NbGateways;
+
+        bool PacketReceived;
+        uint8_t RxPort;
+        uint8_t RxPayload[255];
+        uint8_t RxPayloadSize;
+
+        bool PongReceived;
+        int16_t PongRssi;
+        int16_t PongSnr;
+
+        bool AckReceived;
+        uint8_t TxNbRetries;
+
+        LoRaMacEventFlags& Flags() {
+            return _flags;
+        }
+        LoRaMacEventInfo& Info() {
+            return _info;
+        }
+
+    private:
+
+        LoRaMacEventFlags _flags;
+        LoRaMacEventInfo _info;
+
+//
+//        /*!
+//         * MAC layer event callback prototype.
+//         *
+//         * \param [IN] flags Bit field indicating the MAC events occurred
+//         * \param [IN] info  Details about MAC events occurred
+//         */
+//        virtual void MacEvent(LoRaMacEventFlags *flags, LoRaMacEventInfo *info) {
+//            logDebug("mDotEvent");
+//
+//            if (flags->Bits.Rx) {
+//                logDebug("Rx");
+//
+//                // Event Object must delete RxBuffer
+//                delete[] info->RxBuffer;
+//            }
+//        }
+//
+
+};
+
+#endif // __MDOT_EVENT_H__