/*!
 * \file      LoRaMacClassB.h
 *
 * \brief     LoRa MAC Class B layer implementation
 *
 * \copyright Revised BSD License, see section \ref LICENSE.
 *
 * \code
 *                ______                              _
 *               / _____)             _              | |
 *              ( (____  _____ ____ _| |_ _____  ____| |__
 *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
 *               _____) ) ____| | | || |_| ____( (___| | | |
 *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
 *              (C)2013 Semtech
 *
 *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
 *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
 *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
 *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
 *              embedded.connectivity.solutions===============
 *
 * \endcode
 *
 * \author    Miguel Luis ( Semtech )
 *
 * \author    Gregory Cristian ( Semtech )
 *
 * \author    Daniel Jaeckle ( STACKFORCE )
 *
 * \defgroup  LORAMACCLASSB LoRa MAC Class B layer implementation
 *            This module specifies the API implementation of the LoRaMAC Class B layer.
 *            This is a placeholder for a detailed description of the LoRaMac
 *            layer and the supported features.
 * \{
 */
#ifndef __LORAMACCLASSB_H__
#define __LORAMACCLASSB_H__

#ifdef __cplusplus
extern "C"
{
#endif

#include "systime.h"
#include "LoRaMacTypes.h"

/*!
 * States of the class B beacon acquisition and tracking
 */
typedef enum eBeaconState
{
    /*!
     * Initial state to acquire the beacon
     */
    BEACON_STATE_ACQUISITION,
    /*!
     * Beacon acquisition state when a time reference is available
     */
    BEACON_STATE_ACQUISITION_BY_TIME,
    /*!
     * Handles the state when the beacon reception fails
     */
    BEACON_STATE_TIMEOUT,
    /*!
     * Handles the state when the beacon was missed due to an uplink
     */
    BEACON_STATE_BEACON_MISSED,
    /*!
     * Reacquisition state which applies the algorithm to enlarge the reception
     * windows
     */
    BEACON_STATE_REACQUISITION,
    /*!
     * The node has locked a beacon successfully
     */
    BEACON_STATE_LOCKED,
    /*!
     * The beacon state machine is stopped due to operations with higher priority
     */
    BEACON_STATE_HALT,
    /*!
     * The node currently operates in the beacon window and is idle. In this
     * state, the temperature measurement takes place
     */
    BEACON_STATE_IDLE,
    /*!
     * The node operates in the guard time of class B
     */
    BEACON_STATE_GUARD,
    /*!
     * The node is in receive mode to lock a beacon
     */
    BEACON_STATE_RX,
    /*!
     * The nodes switches the device class
     */
    BEACON_STATE_LOST,
}BeaconState_t;

/*!
 * States of the class B ping slot mechanism
 */
typedef enum ePingSlotState
{
    /*!
     * Calculation of the ping slot offset
     */
    PINGSLOT_STATE_CALC_PING_OFFSET,
    /*!
     * State to set the timer to open the next ping slot
     */
    PINGSLOT_STATE_SET_TIMER,
    /*!
     * The node is in idle state
     */
    PINGSLOT_STATE_IDLE,
    /*!
     * The node opens up a ping slot window
     */
    PINGSLOT_STATE_RX,
}PingSlotState_t;

/*!
 * Class B ping slot context structure
 */
typedef struct sPingSlotContext
{

    /*!
     * Ping slot length time in ms
     */
    uint32_t PingSlotWindow;
    /*!
     * Ping offset
     */
    uint16_t PingOffset;
    /*!
     * Current symbol timeout. The node enlarges this variable in case of beacon
     * loss.
     */
    uint16_t SymbolTimeout;
    /*!
     * The multicast channel which will be enabled next.
     */
    MulticastCtx_t *NextMulticastChannel;
}PingSlotContext_t;


/*!
 * Class B beacon context structure
 */
typedef struct sBeaconContext
{
    struct sBeaconCtrl
    {
        /*!
         * Set if the node receives beacons
         */
        uint8_t BeaconMode          : 1;
        /*!
         * Set if the node has acquired the beacon
         */
        uint8_t BeaconAcquired      : 1;
        /*!
         * Set if a beacon delay was set for the beacon acquisition
         */
        uint8_t BeaconDelaySet      : 1;
        /*!
         * Set if a beacon channel was set for the beacon acquisition
         */
        uint8_t BeaconChannelSet    : 1;
        /*!
         * Set if beacon acquisition is pending
         */
        uint8_t AcquisitionPending  : 1;
        /*!
         * Set if the beacon state machine will be resumed
         */
        uint8_t ResumeBeaconing      : 1;
    }Ctrl;

    /*!
     * Current temperature
     */
    float Temperature;
    /*!
     * Beacon time received with the beacon frame
     */
    SysTime_t BeaconTime;
    /*!
     * Time when the last beacon was received
     */
    SysTime_t LastBeaconRx;
    /*!
     * Time when the next beacon will be received
     */
    SysTime_t NextBeaconRx;
    /*!
     * This is the time where the RX window will be opened.
     * Its base is NextBeaconRx with temperature compensations
     * and RX window movement.
     */
    TimerTime_t NextBeaconRxAdjusted;
    /*!
     * Current symbol timeout. The node enlarges this variable in case of beacon
     * loss.
     */
    uint16_t SymbolTimeout;
    /*!
     * Specifies how much time the beacon window will be moved.
     */
    TimerTime_t BeaconWindowMovement;
    /*!
     * Beacon timing channel for next beacon
     */
    uint8_t BeaconTimingChannel;
    /*!
     * Delay for next beacon in ms
     */
    TimerTime_t BeaconTimingDelay;
    TimerTime_t TimeStamp;
    /*!
     * Beacons transmit time precision determined using
     * param field of beacon frame format.
     */
    SysTime_t BeaconTimePrecision;
}BeaconContext_t;

/*!
 * Data structure which contains the callbacks
 */
typedef struct sLoRaMacClassBCallback
{
    /*!
     * \brief   Measures the temperature level
     *
     * \retval  Temperature level
     */
    float ( *GetTemperatureLevel )( void );
    /*!
     *\brief    Will be called each time a Radio IRQ is handled by the MAC
     *          layer.
     *
     *\warning  Runs in a IRQ context. Should only change variables state.
     */
    void ( *MacProcessNotify )( void );
}LoRaMacClassBCallback_t;

/*!
 * Data structure which pointers to the properties LoRaMAC
 */
typedef struct sLoRaMacClassBParams
{
    /*!
     * Pointer to the MlmeIndication structure
     */
    MlmeIndication_t *MlmeIndication;
    /*!
     * Pointer to the McpsIndication structure
     */
    McpsIndication_t *McpsIndication;
    /*!
     * Pointer to the MlmeConfirm structure
     */
    MlmeConfirm_t *MlmeConfirm;
    /*!
     * Pointer to the LoRaMacFlags structure
     */
    LoRaMacFlags_t *LoRaMacFlags;
    /*!
     * Pointer to the LoRaMac device address
     */
    uint32_t *LoRaMacDevAddr;
    /*!
     * Pointer to the LoRaMac region definition
     */
    LoRaMacRegion_t *LoRaMacRegion;
    /*!
     * Pointer to the LoRaMacParams structure
     */
    LoRaMacParams_t *LoRaMacParams;
    /*!
     * Pointer to the multicast channel list
     */
    MulticastCtx_t *MulticastChannels;
    /*!
     * Pointer to the activation type
     */
    ActivationType_t *NetworkActivation;
}LoRaMacClassBParams_t;

/*!
 * Signature of callback function to be called by this module when the
 * non-volatile needs to be saved.
 */
typedef void ( *LoRaMacClassBNvmEvent )( void );

/*!
 * \brief Initialize LoRaWAN Class B
 *
 * \param [IN] classBParams Information and feedback parameter
 * \param [IN] callbacks Contains the callback which the Class B implementation needs
 * \param [IN] nvm Pointer to an external non-volatile memory data structure.
 */
void LoRaMacClassBInit( LoRaMacClassBParams_t *classBParams, LoRaMacClassBCallback_t *callbacks,
                        LoRaMacClassBNvmData_t* nvm );

/*!
 * \brief Set the state of the beacon state machine
 *
 * \param [IN] beaconState Beacon state.
 */
void LoRaMacClassBSetBeaconState( BeaconState_t beaconState );

/*!
 * \brief Set the state of the ping slot state machine
 *
 * \param [IN] pingSlotState Ping slot state.
 */
void LoRaMacClassBSetPingSlotState( PingSlotState_t pingSlotState );

/*!
 * \brief Set the state of the multicast slot state machine
 *
 * \param [IN] pingSlotState multicast slot state.
 */
void LoRaMacClassBSetMulticastSlotState( PingSlotState_t multicastSlotState );

/*!
 * \brief Verifies if an acquisition procedure is in progress
 *
 * \retval [true, if the acquisition is in progress; false, if not]
 */
bool LoRaMacClassBIsAcquisitionInProgress( void );

/*!
 * \brief State machine of the Class B for beaconing
 */
void LoRaMacClassBBeaconTimerEvent( void* context );

/*!
 * \brief State machine of the Class B for ping slots
 */
void LoRaMacClassBPingSlotTimerEvent( void* context );

/*!
 * \brief State machine of the Class B for multicast slots
 */
void LoRaMacClassBMulticastSlotTimerEvent( void* context );

/*!
 * \brief Receives and decodes the beacon frame
 *
 * \param [IN] payload Pointer to the payload
 * \param [IN] size Size of the payload
 * \retval [true, if the node has received a beacon; false, if not]
 */
bool LoRaMacClassBRxBeacon( uint8_t *payload, uint16_t size );

/*!
 * \brief The function validates, if the node expects a beacon
 *        at the current time.
 *
 * \retval [true, if the node expects a beacon; false, if not]
 */
bool LoRaMacClassBIsBeaconExpected( void );

/*!
 * \brief The function validates, if the node expects a ping slot
 *        at the current time.
 *
 * \retval [true, if the node expects a ping slot; false, if not]
 */
bool LoRaMacClassBIsPingExpected( void );

/*!
 * \brief The function validates, if the node expects a multicast slot
 *        at the current time.
 *
 * \retval [true, if the node expects a multicast slot; false, if not]
 */
bool LoRaMacClassBIsMulticastExpected( void );

/*!
 * \brief Verifies if the acquisition pending bit is set
 *
 * \retval [true, if the bit is set; false, if not]
 */
bool LoRaMacClassBIsAcquisitionPending( void );

/*!
 * \brief Verifies if the beacon mode active bit is set
 *
 * \retval [true, if the bit is set; false, if not]
 */
bool LoRaMacClassBIsBeaconModeActive( void );

/*!
 * \brief Stops the beacon and ping slot operation
 */
void LoRaMacClassBHaltBeaconing( void );

/*!
 * \brief Resumes the beacon and ping slot operation
 */
void LoRaMacClassBResumeBeaconing( void );

/*!
 * \brief Sets the periodicity of the ping slots
 *
 * \param [IN] periodicity Periodicity
 */
void LoRaMacClassBSetPingSlotInfo( uint8_t periodicity );

/*!
 * \brief Switches the device class
 *
 * \param [IN] nextClass Device class to switch to
 *
 * \retval LoRaMacStatus_t Status of the operation.
 */
LoRaMacStatus_t LoRaMacClassBSwitchClass( DeviceClass_t nextClass );

/*!
 * \brief   LoRaMAC ClassB MIB-Get
 *
 * \details The mac information base service to get attributes of the LoRaMac
 *          Class B layer.
 *
 * \param   [IN] mibRequest - MIB-GET-Request to perform. Refer to \ref MibRequestConfirm_t.
 *
 * \retval  LoRaMacStatus_t Status of the operation. Possible returns are:
 *          \ref LORAMAC_STATUS_OK,
 *          \ref LORAMAC_STATUS_SERVICE_UNKNOWN,
 *          \ref LORAMAC_STATUS_PARAMETER_INVALID.
 */
LoRaMacStatus_t LoRaMacClassBMibGetRequestConfirm( MibRequestConfirm_t *mibGet );

/*!
 * \brief   LoRaMAC Class B MIB-Set
 *
 * \details The mac information base service to set attributes of the LoRaMac
 *          Class B layer.
 *
 * \param   [IN] mibRequest - MIB-SET-Request to perform. Refer to \ref MibRequestConfirm_t.
 *
 * \retval  LoRaMacStatus_t Status of the operation. Possible returns are:
 *          \ref LORAMAC_STATUS_OK,
 *          \ref LORAMAC_STATUS_BUSY,
 *          \ref LORAMAC_STATUS_SERVICE_UNKNOWN,
 *          \ref LORAMAC_STATUS_PARAMETER_INVALID.
 */
LoRaMacStatus_t LoRaMacMibClassBSetRequestConfirm( MibRequestConfirm_t *mibSet );

/*!
 * \brief This function handles the PING_SLOT_FREQ_ANS
 */
void LoRaMacClassBPingSlotInfoAns( void );

/*!
 * \brief This function handles the PING_SLOT_CHANNEL_REQ
 *
 * \param [IN] datarate Device class to switch to
 * \param [IN] frequency Device class to switch to
 *
 * \retval Status for the MAC answer.
 */
uint8_t LoRaMacClassBPingSlotChannelReq( uint8_t datarate, uint32_t frequency );

/*!
 * \brief This function handles the BEACON_TIMING_ANS
 *
 * \param [IN] beaconTimingDelay The beacon timing delay
 * \param [IN] beaconTimingChannel The beacon timing channel
 * \param [IN] lastRxDone The time of the last frame reception
 */
void LoRaMacClassBBeaconTimingAns( uint16_t beaconTimingDelay, uint8_t beaconTimingChannel, TimerTime_t lastRxDone );

/*!
 * \brief This function handles the ClassB DEVICE_TIME_ANS
 */
void LoRaMacClassBDeviceTimeAns( void );

/*!
 * \brief This function handles the BEACON_FREQ_REQ
 *
 * \param [IN] frequency Frequency to set
 *
 * \retval [true, if MAC shall send an answer; false, if not]
 */
bool LoRaMacClassBBeaconFreqReq( uint32_t frequency );

/*!
 * \brief Queries the ping slot window time
 *
 * \param [IN] txTimeOnAir TX time on air for the next uplink
 *
 * \retval Returns the time the uplink should be delayed
 */
TimerTime_t LoRaMacClassBIsUplinkCollision( TimerTime_t txTimeOnAir );

/*!
 * \brief Stops the timers for the RX slots. This includes the
 *        timers for ping and multicast slots.
 */
void LoRaMacClassBStopRxSlots( void );

/*!
 * \brief Starts the timers for the RX slots. This includes the
 *        timers for ping and multicast slots.
 */
void LoRaMacClassBStartRxSlots( void );

/*!
 * \brief Starts the timers for the RX slots. This includes the
 *        timers for ping and multicast slots.
 *
 * \param [IN] periodicity Downlink periodicity
 *
 * \param [IN] multicastChannel Related multicast channel
 */
void LoRaMacClassBSetMulticastPeriodicity( MulticastCtx_t* multicastChannel );

/*!
 * \brief Sets the FPending bit status of the related downlink slot
 *
 * \param [IN] address Slot address, could be unicast or multicast
 *
 * \param [IN] fPendingSet Set to 1, if the fPending bit in the
 *             sequence is set, otherwise 0.
 */
void LoRaMacClassBSetFPendingBit( uint32_t address, uint8_t fPendingSet );

/*!
 * \brief Class B process function.
 */
void LoRaMacClassBProcess( void );

#ifdef __cplusplus
}
#endif

#endif // __LORAMACCLASSB_H__