Stable version of the mDot library for mbed 5. This version of the library is suitable for deployment scenarios. See lastest commit message for version of mbed-os library that has been tested against.

Dependents:   mdot_two_way unh-hackathon-example unh-hackathon-example-raw TelitSensorToCloud ... more

Fork of libmDot-dev-mbed5-deprecated by MultiTech

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

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.

FOTA

Full FOTA support is only available with mDot, xDot does not have the required external flash. xDot can use the FOTA example to dynamically join a multicast session only. After joining the multicast session the received Fragmentation packets could be handed to a host MCU for processing and at completion the firmware can be loaded into the xDot using the bootloader and y-modem. See xDot Developer Guide.

  • Add the following code to allow Fota to use the Dot instance

main.cpp

    // Initialize FOTA singleton
    Fota::getInstance(dot);
  • Add fragmentation handling the the PacketRx event

RadioEvent.h

    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, bool dupRx) {
        mDotEvent::PacketRx(port, payload, size, rssi, snr, ctrl, slot, retries, address, dupRx);

#if ACTIVE_EXAMPLE == FOTA_EXAMPLE
        if(port == 200 || port == 201 || port == 202) {
            Fota::getInstance()->processCmd(payload, port, size);
        }
#endif
    }

A definition is needed to enable Fragmentation support on mDot and save fragments to flash. This should not be defined for xDot and will result in a compiler error.

mbed_app.json

{
    "macros": [
        "FOTA=1"
    ]
}

The FOTA implementation has a few differences from the LoRaWAN Protocol

  • Fragmentation Indexing starts at 0
  • McKEKey is 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
  • Start Time is a count-down in seconds to start of session

Files at this revision

API Documentation at this revision

Comitter:
Mike Fiore
Date:
Thu Aug 04 15:11:24 2016 -0500
Parent:
15:ea598f178cce
Child:
17:306ffaa5d79b
Commit message:
update from libmDot-2.0.1-ARMCC.tar.gz

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
MTS-Utils/MTSCircularBuffer.h Show diff for this revision Revisions of this file
MTS-Utils/MTSLog.h Show diff for this revision Revisions of this file
MTS-Utils/MTSText.h Show diff for this revision Revisions of this file
MTS-Utils/Utils.h 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
libmDot.ar 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Lora.h	Thu Aug 04 15:11:24 2016 -0500
@@ -0,0 +1,707 @@
+/**   __  ___     ____  _    ______        __     ____         __                  ____
+ *   /  |/  /_ __/ / /_(_)__/_  __/__ ____/ /    / __/_ _____ / /____ __ _  ___   /  _/__  ____
+ *  / /|_/ / // / / __/ /___// / / -_) __/ _ \  _\ \/ // (_-</ __/ -_)  ' \(_-<  _/ // _ \/ __/  __
+ * /_/  /_/\_,_/_/\__/_/    /_/  \__/\__/_//_/ /___/\_, /___/\__/\__/_/_/_/___/ /___/_//_/\__/  /_/
+ * 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_MAX_PAYLOAD_EXCEEDED
+    };
+
+    /**
+     * 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
+    };
+
+    /**
+     * 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
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MTS-Lora/vendor/multitech/MTS-Utils/MTSCircularBuffer.h	Thu Aug 04 15:11:24 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 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MTS-Lora/vendor/multitech/MTS-Utils/MTSLog.h	Thu Aug 04 15:11:24 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MTS-Lora/vendor/multitech/MTS-Utils/MTSText.h	Thu Aug 04 15:11:24 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MTS-Lora/vendor/multitech/MTS-Utils/Utils.h	Thu Aug 04 15:11:24 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/MTS-Utils/MTSCircularBuffer.h	Tue Mar 29 10:25:31 2016 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,158 +0,0 @@
-#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-Utils/MTSLog.h	Tue Mar 29 10:25:31 2016 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,108 +0,0 @@
-#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-Utils/MTSText.h	Tue Mar 29 10:25:31 2016 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-#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-Utils/Utils.h	Tue Mar 29 10:25:31 2016 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-#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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MacEvents.h	Thu Aug 04 15:11:24 2016 -0500
@@ -0,0 +1,51 @@
+/**   __  ___     ____  _    ______        __     ____         __                  ____
+ *   /  |/  /_ __/ / /_(_)__/_  __/__ ____/ /    / __/_ _____ / /____ __ _  ___   /  _/__  ____
+ *  / /|_/ / // / / __/ /___// / / -_) __/ _ \  _\ \/ // (_-</ __/ -_)  ' \(_-<  _/ // _ \/ __/ __
+ * /_/  /_/\_,_/_/\__/_/    /_/  \__/\__/_//_/ /___/\_, /___/\__/\__/_/_/_/___/ /___/_//_/\__/ /_/
+ * 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 uint8_t MeasureBattery() = 0;
+
+        private:
+
+
+    };
+
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Mote.h	Thu Aug 04 15:11:24 2016 -0500
@@ -0,0 +1,256 @@
+/**   __  ___     ____  _    ______        __     ____         __                  ____
+ *   /  |/  /_ __/ / /_(_)__/_  __/__ ____/ /    / __/_ _____ / /____ __ _  ___   /  _/__  ____
+ *  / /|_/ / // / / __/ /___// / / -_) __/ _ \  _\ \/ // (_-</ __/ -_)  ' \(_-<  _/ // _ \/ __/ __
+ * /_/  /_/\_,_/_/\__/_/    /_/  \__/\__/_//_/ /___/\_, /___/\__/\__/_/_/_/___/ /___/_//_/\__/ /_/
+ * 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();
+    };
+
+    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 libmDot.ar has changed
--- a/mDot.h	Tue Mar 29 10:25:31 2016 -0500
+++ b/mDot.h	Thu Aug 04 15:11:24 2016 -0500
@@ -5,17 +5,16 @@
 
 #include "mbed.h"
 #include "rtos.h"
+#include "Mote.h"
 #include <vector>
 #include <map>
 #include <string>
 
 class mDotEvent;
-class LoRaMacEvent;
 class LoRaConfig;
-class LoRaMac;
-class MdotRadio;
 
 class mDot {
+        friend class mDotEvent;
 
     private:
 
@@ -27,6 +26,8 @@
                 __WFI();
         }
 
+        void initLora();
+
         void setLastError(const std::string& str);
 
         static bool validateBaudRate(const uint32_t& baud);
@@ -61,10 +62,11 @@
 
         static mDot* _instance;
 
-        LoRaMac* _mac;
-        MdotRadio* _radio;
-        LoRaMacEvent* _events;
+        lora::Mote _mote;
         LoRaConfig* _config;
+        lora::Settings _settings;
+        mDotEvent* _events;
+
         Thread _idle_thread;
         std::string _last_error;
         static const uint32_t _baud_rates[];
@@ -114,7 +116,7 @@
         } mdot_ret_code;
 
         enum JoinMode {
-            MANUAL,
+            MANUAL = 0,
             OTA,
             AUTO_OTA,
             PEER_TO_PEER
@@ -158,8 +160,11 @@
         };
 
         enum FrequencyBands {
-            FB_868, // EU868
-            FB_915  // US915
+            FB_868 = 0,
+            FB_915 = 1,
+            FB_EU868 = 0, // EU868
+            FB_US915 = 1,  // US915
+            FB_AU915 = 2
         };
 
         enum FrequencySubBands {
@@ -200,7 +205,7 @@
 
         typedef struct {
                 int16_t fd;
-                char name[30];
+                char name[33];
                 uint32_t size;
         } mdot_file;
 
@@ -210,6 +215,7 @@
                 uint32_t Joins;
                 uint32_t JoinFails;
                 uint32_t MissedAcks;
+                uint32_t CRCErrors;
         } mdot_stats;
 
         typedef struct {
@@ -332,6 +338,10 @@
          */
         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
          */
@@ -680,6 +690,42 @@
          */
         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
@@ -712,11 +758,22 @@
          */
         bool getDataPending();
 
-        /** Get transmitting
+        /** 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
@@ -734,7 +791,6 @@
          */
         uint32_t getRadioRandom();
 
-
         /** Get data rate spreading factor and bandwidth
          * EU868 Datarates
          * ---------------
@@ -795,6 +851,10 @@
          */
         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
          */
@@ -869,6 +929,24 @@
          */
         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()
@@ -1104,7 +1182,6 @@
         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
@@ -1113,8 +1190,26 @@
 
         // 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 sendContinuous();
+        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();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mDotEvent.h	Thu Aug 04 15:11:24 2016 -0500
@@ -0,0 +1,297 @@
+#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;
+
+            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 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.TxAckReceived = 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__