fota lib for mdot

Dependents:   UQ_LoraWAN

mdot/Lora/Mac.h

Committer:
Jenkins@KEILDM1.dc.multitech.prv
Date:
2018-09-14
Revision:
3:63d10f2375ea

File content as of revision 3:63d10f2375ea:

/**   __  ___     ____  _    ______        __     ____         __                  ____
 *   /  |/  /_ __/ / /_(_)__/_  __/__ ____/ /    / __/_ _____ / /____ __ _  ___   /  _/__  ____
 *  / /|_/ / // / / __/ /___// / / -_) __/ _ \  _\ \/ // (_-</ __/ -_)  ' \(_-<  _/ // _ \/ __/  __
 * /_/  /_/\_,_/_/\__/_/    /_/  \__/\__/_//_/ /___/\_, /___/\__/\__/_/_/_/___/ /___/_//_/\__/  /_/
 * Copyright (C) 2015 by Multi-Tech Systems        /___/
 *
 *
 * @author Jason Reiss
 * @date   10-31-2015
 * @brief  lora::Mac implements the Mac layer providing mote addressing and packet encryption
 *
 * @details
 *
 */

#ifndef __LORA_MAC_H__
#define __LORA_MAC_H__

#include "Lora.h"
#include "ChannelPlan.h"
#include "SxRadio.h"
#include "SxRadio1272.h"
#include "SxRadioEvents.h"
#include "MacEvents.h"
#include "Crypto.h"
#include "Link.h"

namespace lora {

    class Mac: public SxRadioEvents, public Crypto {
        public:

            virtual ~Mac();

            Mac(SxRadio& radio, MacEvents* events, ChannelPlan* plan, Settings& settings);

            /**
             * Send a Join Request packet
             * @param devEUI
             * @param appEUI
             * @param appKey
             * @return LORA_OK if successful
             * @return LORA_LINK_BUSY
             * @return LORA_RADIO_BUSY
             */
            uint8_t Join(const uint8_t* devEUI, const uint8_t* appEUI, const uint8_t* appKey);

            /**
             * Send a packet
             * @param port app port to send with payload
             * @param payload data to send
             * @param size of payload
             * @param attempts number of attempts to receive an ACK
             * @param repeats number of times to repeat packet
             * @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, uint16_t size, uint8_t attempts = 0, uint8_t repeats = 0);

            /**
             * Prepare frame to be sent over link
             * @param port to send data to
             * @param payload to send
             * @param size of payload
             * @param attempts 0:Unconfirmed, 1-8:Confirmed
             * @return LORA_OK
             */
            uint8_t PrepareFrame(uint8_t port, const uint8_t* payload, uint8_t size, uint8_t attempts);

            /**
             * Reset the mac commands buffer
             */
            void ResetMacCommands();

            /**
             * Add a mac command to be sent with next packet
             * @param cmd id of command
             * @param pc number of parameters
             * @param pv array of parameters
             * @return LORA_OK if successful
             * @return LORA_COMMAND_BUFFER_FULL
             * @return LORA_UNKNOWN_MAC_COMMAND
             */
            uint8_t AddMacCommand(uint8_t cmd, uint8_t pc, uint8_t* pv);

            /**
             * Handle mac command received from server
             * @param payload received on radio
             * @param index of mac command id
             * @param size of mac command list
             */
            uint8_t HandleMacCommands(uint8_t* payload, uint8_t index, uint8_t size);

            /**
             * Handle Join Accept packet
             * @param payload received
             * @param size of payload
             * @return LORA_OK if successful
             * @return LORA_JOIN_ERROR if already joined or MIC fails
             */
            uint8_t HandleJoinAccept(uint8_t* payload, uint8_t size);

            /**
             * Handle Packet receipt
             * Verifies Address and MIC, checks the Frame Control bits for ACK
             * Then decrypts the payload and handles any Mac Commands
             * @param payload received
             * @param size of payload
             * @param[out] port data was received on
             * @param[out] length of user data in payload
             */
            uint8_t HandleDownlinkPacket(uint8_t* payload, uint8_t size, uint8_t& port, uint8_t& length);

            /**
             * Check for ACK from server in received packet and notifies Link if present
             * @param fCtrl frame control byte of packet
             * @return LORA_OK
             */
            uint8_t CheckFrameControl(DownlinkControl fCtrl);

            /**
             * Verify that packet address is intended for mote or in list of multicast addresses
             * @param payload received
             * @param size of payload
             * @param[out] address found in header of packet
             * @param[out] networkSessionKey associated with address
             * @param[out] dataSessionKey associated with address
             * @return LORA_OK if successful
             * @return LORA_ADDRESS_ERROR if address is not found
             */
            uint8_t VerifyAddress(uint8_t* payload, uint8_t size, uint32_t& address, uint8_t* networkSessionKey, uint8_t* dataSessionKey);

            /**
             * Verify that MIC can be computed with network session key
             * Frame counter is checked for reset and rollover
             * @param payload received
             * @param size of payload
             * @param address found in header of packet
             * @param networkSessionKey
             * @return LORA_OK if successful
             * @return LORA_MIC_ERROR
             */
            uint8_t VerifyMIC(uint8_t* payload, uint8_t size, uint32_t address, uint8_t* networkSessionKey);

            /**
             * Event called by Link on start of any tx
             */
            virtual void TxStart(void);

            /**
             * Event called by Link on tx done
             */
            virtual void TxDone(void);

            /**
             * Event called by Link on tx timeout
             */
            virtual void TxTimeout(void);

            /**
             * Event called by Link on rx done
             * @param payload of received packet
             * @param size of received packet in bytes
             * @param rssi of received packet in dBm
             * @param snr of received packet two's complement in 1/4 dB
             */
            virtual void RxDone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr);

            /**
             * Event called by Link on rx timeout
             */
            virtual void RxTimeout(void);

            /**
             * Event called by Link on rx error
             */
            virtual void RxError(void);

            virtual void LinkIdle(void);

            /**
             * Current join status
             * @return true if joined to lora network
             * @return false if not joined
             */
            bool IsJoined();

            /**
             * Set the dev nonce
             * The dev nonce is used for deriving session keys and part of the data send on a join request
             */
            void SetDeviceNonce(uint16_t nonce);

            /**
             * Get the dev nonce
             * The dev nonce is used for deriving session keys and part of the data send on a join request
             */
            uint16_t GetDeviceNonce();

            void SetLoraClass(MoteClass cls);

            /**
             * Get the current device MoteClass
             */
            MoteClass GetLoraClass();

            /**
             * Get the SNR of the last received packet
             * @returns snr in dB
             */
            int8_t GetSNR();

            /**
             * Get the RSSI of the last received packet
             * @returns rssi in dB
             */
            int16_t GetRSSI();

            /**
             * Update the statistics with the last received RSSI and SNR
             * The avg, min and max RSSI and SNR will also be updated
             */
            void UpdateStats(int16_t rssi, int16_t snr);

            /**
             * Get the number of mac command bytes ready to be sent in the next packet
             * @return size of buffer in bytes
             */
            uint8_t GetMacCommandBufferSize();

            /**
             * Get the buffer for mac command bytes ready to be sent in the next packet
             * @return pointer to command buffer
             */
            const uint8_t* GetMacCommandBuffer();

            /**
             * Clear the buffer for mac command bytes to be sent in the next packet
             */
            void ClearMacCommandBuffer();

            /**
             * Get the size of the bytes ready to be sent in the next packet
             * @returns size of buffer in bytes
             */
            uint8_t GetTxBufferSize();

            /**
             * Get the buffer of bytes  ready to be sent in the next packet
             * @return pointer to buffer
             */
            const uint8_t* GetTxBuffer();

            /**
             * Get the max duty cycle currently set for device
             * Aggregated duty cycle = 1 / 2 ^ MaxDutyCycle
             * Value of 255 should silence device
             * @return duty cycle 0-15 or 255
             */
            uint8_t GetMaxDutyCycle();

            /**
             * Get the Rx delay value currently used by the Link
             * @return rxDelay in seconds
             */
            uint8_t GetRxDelay();

            /**
             * Get the MCU sleep time between tx done and the Rx1 window opening
             * @return Time MCU sleeps between tx done and rx1 open in milliseconds
             */
            uint32_t GetRx1SleepTime();

            /**
             * Get the MCU sleep time between Rx1 window opening and the Rx2 window opening
             * @return Time MCU sleeps between rx1 open and rx2 open in milliseconds
             */
            uint32_t GetRx2SleepTime();

            /**
             * Get pong received indicator
             * @return true if pong was received
             */
            bool GetPongReceived();

            /**
             * Get the RSSI of the last received pong
             * The RSSI will be the strength of the signal received at the gateway
             * @return rssi in dB
             */
            int16_t GetPongRssi();

            /**
             * Get the SNR of the last received pong
             * The SNR will be the strength of the signal received at the gateway
             * @return snr in dB
             */
            int16_t GetPongSnr();

            /**
             * Get the current statistics for the device
             * @return Statistics
             */
            Statistics& GetStats();

            /**
             * Reset the current statistics for the device
             */
            void ResetStats();

            /**
             * Set the current channel plan
             */
            void SetChannelPlan(ChannelPlan* plan);

            /**
             * Set the delay for Rx1 window
             * @param sec time to delay after end of tx, minimum 1 second
             */
            uint8_t SetRxDelay(uint8_t sec);

            /**
             * Set the MCU sleep time between tx done and the Rx1 window opening
             * @param ms time MCU sleeps between tx done and rx1 open
             */
            void SetRx1SleepTime(uint32_t ms);

            /**
             * Set the MCU sleep time between Rx1 window opening and the Rx2 window opening
             * @param ms time MCU sleeps between rx1 open and rx2 open
             */
            void SetRx2SleepTime(uint32_t ms);

            /**
             * Set the network mode
             * @param mode PRIVATE, PUBLIC or PEER_TO_PEER
             */
            uint8_t SetNetworkMode(uint8_t mode);

            /**
             * Get the current state of the MAC layer
             * @return MAC_IDLE, MAC_TX, MAC_RX
             */
            MacState GetState();

            /**
             * Get the time off air for the current datarate
             * @return time off air before next TX in ms
             */
            uint32_t GetTimeOffAir();

            /**
             * Open an RX Window
             * @param timeout time in ms to hold window open, 0 for continuous
             * @param freq frequency to listen on
             * @param datarate to listen for
             * @return LORA_OK
             */
            uint8_t OpenRxWindow(uint32_t timeout, uint32_t freq, uint8_t datarate);
            uint8_t OpenRxWindow(uint32_t timeout, bool continuous);

            /**
             * Close the open window
             * @return LORA_OK
             */
            uint8_t CloseRxWindow();

            /**
             * Cancel pending rx windows
             * @return LORA_OK
             */
            uint8_t CancelRxWindows();

            /**
             * Get datarate properties of given index for current channel plan
             * @param index of datarate
             */
            Datarate GetDatarate(uint8_t index);

            /**
             * Get the max payload size available of current datarate for channel plan
             * @return bytes that can be sent
             */
            uint8_t GetMaxPayloadSize();

            /**
             * Call to wakeup mac layer
             */
            void Wakeup();

            /**
             * Set the event object to report to
             * @param events object inheriting from MacEvents
             */
            void SetEventHandler(MacEvents* events);

            /**
             * Get the channels in use by current channel plan
             * @return channel frequencies
             */
            std::vector<uint32_t> GetChannels();

            /**
             * Get the downlink channels in use by current channel plan
             * @return channel frequencies
             */
            std::vector<uint32_t> GetDownlinkChannels();

            /**
             * Get the channel datarate ranges in use by current channel plan
             * @return channel datarate ranges
             */
            std::vector<uint8_t> GetChannelRanges();

            /**
             * Enable the default channels of the channel plan
             */
            void EnableDefaultChannels();

            /**
             * Get the number of duty bands in the current channel plan
             * @return number of bands
             */
            uint8_t GetNumDutyBands();

            /**
             * Get the time off air for the given duty band
             * @param band index
             * @return time off air in ms
             */
            uint32_t GetDutyBandTimeOff(uint8_t band);

            /**
             * Set the time off air for the given duty band
             * @param band index
             * @param time off air in ms
             */
            void SetDutyBandTimeOff(uint8_t band, uint32_t timeoff);

            /**
             * Reset internal mac state if timeout or unforeseen error occurs
             */
            void ResetState();

            /**
             * Enable TX CW
             * return LORA_OK
             */
            uint8_t SendContinuous(bool enable);

        private:
            /**
             * Helper for clearing MAC commands which can be cleared upon successful uplink
             */
            void PostTxMacPrune();

            Link _link;                                 //!< Link used to manage radio
            ChannelPlan* _plan;                         //!< Injected ChannelPlan used by Link to define parameters for tx/rx of packets
            SxRadio& _radio;                            //!< Injected SxRadio object
            MacEvents* _events;                         //!< Injected MaxEvents object for event notification to client
            Settings& _settings;                        //!< Settings used to configure the Mac

            bool _isMulticastPacket;                    //!< Indicator of multicast packet recieved
            uint8_t _multicastIndex;                    //!< Index of multicast session associated with last received packet

            uint8_t _rxBuffer[MAX_PHY_PACKET_SIZE];     //!< Buffer of last packet received
            uint8_t _rxBufferSize;                      //!< Size of the last packet received
            uint8_t _txBuffer[MAX_PHY_PACKET_SIZE];     //!< Buffer of packet to send
            uint8_t _txBufferSize;                      //!< Size of buffer to send
            bool _txBufferFull;                         //!< Indicates that buffer was filled with mac commands

            uint16_t _joinNonce;                        //!< Random nonce value used for Join Request and to derive session keys

            int16_t _rssi;                              //!< RSSI value of last received packet in dB
            int16_t _snr;                               //!< SNR value of last received packet in cB

            bool _pongReceived;                         //!< Indicator of pong received
            int16_t _pongRssi;                          //!< RSSI value of last received pong
            int16_t _pongSnr;                           //!< SNR value of last received pong

            MacState _state;                            //!< Current mac state

            uint32_t _downlinkCounter;                  //!< Temporary downlink counter
            bool _duplicateReceived;                    //!< Indication of duplicate packet received due to missed ack

            DownlinkControl _downlinkCtrl;              //!< Downlink ctrl status of last rx packet
    };

}

#endif // __LORA_MAC_H__