mbed-os/features/lorawan/lorastack/mac/LoRaMacClassB.h

520 lines
15 KiB
C++

#ifndef MBED_LORAWAN_LORAMACCLASSB_H_
#define MBED_LORAWAN_LORAMACCLASSB_H_
/**
* Copyright (c) 2017, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if (MBED_CONF_LORA_VERSION >= 01) && (MBED_CONF_LORA_CLASS_B == true)
#define LORA_CLASS_B_ENABLED
#endif
#include "system/lorawan_data_structures.h"
#include "lorastack/phy/LoRaPHY.h"
#include "lorastack/mac/LoRaMacCrypto.h"
#include "platform/ScopedLock.h"
#if MBED_CONF_RTOS_PRESENT
#include "rtos/Mutex.h"
#endif
class LoRaMacClassB {
public:
/**
* Initialize Class B system
*
* @param [in] lora_time
* @param [in] lora_phy
* @param [in] lora_crypto
* @param [in] params
* @param [in] open_rx_window LoRaMac open rx window callback
* @param [in] close_rx_window LoRaMac close rx window callback
* @return LORAWAN_STATUS_OK or a negative error return code
*/
inline static lorawan_status_t Initialize(LoRaWANTimeHandler *lora_time,
LoRaPHY *lora_phy,
LoRaMacCrypto *lora_crypto,
loramac_protocol_params *params,
mbed::Callback<bool(rx_config_params_t *)> open_rx_window,
mbed::Callback<void(rx_slot_t)> close_rx_window)
{
_loramac_class_b.initialize(lora_time, lora_phy, lora_crypto, params,
open_rx_window, close_rx_window);
return LORAWAN_STATUS_OK;
}
/**
* Enable beacon acquisition and tracking
*
* @return LORAWAN_STATUS_OK or a negative error return code
*/
inline static lorawan_status_t Enable_beacon_acquisition(mbed::Callback<void(loramac_beacon_status_t,
const loramac_beacon_t *)> beacon_event_cb)
{
return _loramac_class_b.enable_beacon_acquisition(beacon_event_cb);
}
/**
* Enable Class B mode. Called after successful beacon acquisition
* @return LORAWAN_STATUS_OK or a negative error return code
*/
inline static lorawan_status_t Enable(void)
{
return _loramac_class_b.enable();
}
/**
* Disables Class B beacon and ping slot scheduling
*/
inline static lorawan_status_t Disable(void)
{
return _loramac_class_b.disable();
}
/**
* Pause class b operation. Called prior to class A uplink
*/
inline static void Pause(void)
{
_loramac_class_b.pause();
}
/**
* Resume class b operation. Called after class A receive windows
*/
inline static void Resume(void)
{
_loramac_class_b.resume();
}
/**
* Handle radio receive timeout event
* @param [in] rx_slot The receive window type
*/
inline static void Handle_rx_timeout(rx_slot_t rx_slot)
{
if (is_operational()) {
_loramac_class_b.handle_rx_timeout(rx_slot);
}
}
/**
* Handle radio receive event
* @param [in] rx_slot
* @param [in] data
* @param [in] size
* @param [in] rx_timestamp
*/
inline static void Handle_rx(rx_slot_t rx_slot, const uint8_t *const data, uint16_t size, uint32_t rx_timestamp)
{
if (is_operational()) {
return _loramac_class_b.handle_rx(rx_slot, data, size, rx_timestamp);
}
}
/**
* Returns last received beacon info
*/
inline static lorawan_status_t Get_last_rx_beacon(loramac_beacon_t &beacon)
{
return _loramac_class_b.get_last_rx_beacon(beacon);
}
/**
* Add ping slot multicast address
*/
inline static bool Add_multicast_address(uint32_t address)
{
return _loramac_class_b.add_multicast_address(address);
}
/**
* Remove ping slot multicast address
*/
inline static void Remove_multicast_address(uint32_t address)
{
return _loramac_class_b.remove_multicast_address(address);
}
/**
* Returns True if class B beacon window scheduling is enabled
*/
inline static bool is_operational(void)
{
return (_loramac_class_b._opstatus.beacon_on);
}
/**
* These locks trample through to the upper layers and make
* the stack thread safe.
*/
#if MBED_CONF_RTOS_PRESENT
void lock(void)
{
_mutex.lock();
}
void unlock(void)
{
_mutex.unlock();
}
#else
void lock(void) { }
void unlock(void) { }
#endif
/**
* Constructor
*/
LoRaMacClassB();
/**
* Destructor
*/
~LoRaMacClassB() {};
protected:
/**
* Initialize class b system
* @param [in] lora_time
* @param [in] lora_phy
* @param [in] lora_crypto
* @param [in] open_rx_window function to open rx widnow
* @param [in] close_rx_window function to close rx widnow
*/
void initialize(LoRaWANTimeHandler *lora_time, LoRaPHY *lora_phy,
LoRaMacCrypto *lora_crypto, loramac_protocol_params *params,
mbed::Callback<bool(rx_config_params_t *)> open_rx_window,
mbed::Callback<void(rx_slot_t)> close_rx_window);
/**
* Enable beacon acquisition
* @param [in] beacon_event_cb - stack beacon event callback
*/
lorawan_status_t enable_beacon_acquisition(mbed::Callback<void(loramac_beacon_status_t,
const loramac_beacon_t *)> beacon_event_cb);
/**
* @brief Enables class b mode
* @return[out] LORAWAN_STATUS_OK or negative error code
*/
lorawan_status_t enable(void);
/**
* @brief Disables class b mode
*/
lorawan_status_t disable(void);
/**
* @brief Pause class b mode
*/
void pause(void);
/**
* @brief Resume class b mode
*/
void resume(void);
/**
* @brief RX window timeout handler
* @param [in] rx_slot
*/
void handle_rx_timeout(rx_slot_t rx_slot) ;
/**
* @brief RX window reception handler
* @param [in] rx_slot receive window
* @param [in] data received data
* @param [in] size data size in bytes
* @param [in] rx_timestamp radio receive time
*/
void handle_rx(rx_slot_t rx_slot, const uint8_t *const data, uint16_t size, uint32_t rx_timestamp);
/**
* @brief Process frame received in beacon window
* @param [in] data
* @param [in] size data size in bytes
* @param [in] rx_timestamp radio receive time
*/
void handle_beacon_rx(const uint8_t *const data, uint16_t size, uint32_t rx_timestamp);
/**
* @brief Process a beacon frame and perform integrity checks
* @param [in] frame
* @param [in] size
*/
lorawan_time_t process_beacon_frame(const uint8_t *const frame, uint16_t size);
/**
* @brief Handle beacon window timeout
*/
void handle_beacon_rx_timeout(void);
/**
* @brief Calculate beacon window configuration
* @param [in] beacon_time beacon time
* @param [out] rx_config beacon window configuration
*/
void set_beacon_rx_config(uint32_t beacon_time, rx_config_params_t *rx_config);
/**
* @brief Schedules next beacon window opening
*/
bool schedule_beacon_window(void);
/**
* @brief Open beacon window
*/
void open_beacon_window(void);
/**
* @brief Schedule next ping slot window
*/
void schedule_ping_slot(void);
/**
* @brief Resets window expansion parameters to defaults
*/
void reset_window_expansion(void);
/**
* @brief Expands beacon window size
*/
void expand_window(void);
void beacon_acquisition_timeout(void);
/**
* @brief Computes beacon window ping slot configuration and
* schedules the next ping rx window
* param [in] beacon_time
*/
void start_ping_slots(uint32_t beacon_time);
/**
* @brief Open ping slot window
*/
void open_ping_slot(void);
/**
* @brief Computes beacon window ping slot offset
*
* param [in] beacon_time
* param [in] address device address
* param [in] ping_period ping slot period expressed in number of ping slots
* param [out] ping_offset the offset for the beacon window
*/
bool compute_ping_offset(uint32_t beacon_time, uint32_t address,
uint16_t ping_period, uint16_t &ping_offset);
/**
* @brief Computes next ping slot for given address
*
* param [in] beacon_time beacon time
* param [in] current_time current device time
* param [in] ping_period Period of receiver wakeup expressed in number of slots
* param [in] ping_nb Number of ping slots per beacon period
* param [in] address unicast or multicast device address
* param [in] ping_offset Randomized offset computed at each beacon period start
* param [out] next_slot_nb computed slotaddress ping slot configuration
* param [out] slot_time next ping slot window device time
* return device time for ping slot, 0 if no ping slots for the current beacon period
*/
lorawan_gps_time_t compute_ping_slot(uint32_t beacon_time, lorawan_gps_time_t current_time,
uint16_t ping_period, uint8_t ping_nb,
uint32_t address, uint16_t ping_slot_offset,
uint16_t &next_slot_nb, rx_config_params_t &rx_config);
/**
* @brief Return precise device time
*/
inline lorawan_gps_time_t get_gps_time(void)
{
return _lora_time->get_gps_time();
}
/**
* Return last received beacon
*/
lorawan_status_t get_last_rx_beacon(loramac_beacon_t &beacon);
/**
* Send beacon miss indication
*/
void send_beacon_miss_indication(void);
/**
* @brief get protocol parameters pointer
*/
inline loramac_protocol_params *protocol_params(void)
{
MBED_ASSERT(_protocol_params);
return _protocol_params;
}
/**
* @brief Adds multicast address to ping slots scheduling
*/
bool add_multicast_address(uint32_t address);
/**
* @brief Remove multicast address ping slot scheduling
*/
void remove_multicast_address(uint32_t address);
/**
* Class B Window Expansion
*/
struct loramac_window_expansion_t {
int16_t movement; // window movement in ms
uint16_t timeout; // window timeout in symbols
};
/**
* Beacon Context
*/
struct loramac_beacon_context_t {
static const uint8_t BEACON_FRAME_COMMON_SIZE = 15;
uint8_t frame_size(void)
{
return rfu1_size + rfu2_size + BEACON_FRAME_COMMON_SIZE;
}
lorawan_time_t beacon_time; // beacon period time
rx_config_params_t rx_config;
uint8_t rfu1_size; // beacon frame rfu1 size
uint8_t rfu2_size; // beacon frame rfu2 size
loramac_beacon_t received_beacon; // last received beacon
loramac_window_expansion_t expansion; // beacon window expansion
uint32_t time_on_air; // beacon frame time on air
} _beacon;
/**
* Ping Slot Context
*/
struct loramac_ping_slot_context_t {
const static int8_t UNICAST_PING_SLOT_IDX = 0;
loramac_window_expansion_t expansion; // ping slot expansion
struct {
uint32_t address; // device address
uint16_t offset; // ping slot offset
uint16_t slot_nb; // next ping slot number
rx_config_params_t rx_config; // receiver configuration
} slot[1 + MBED_CONF_LORA_CLASS_B_MULTICAST_ADDRESS_MAX_COUNT];
int8_t slot_idx; // holds next ping_slot idx
} _ping;
/**
* Class B Operational Status
*/
typedef struct {
uint32_t initialized : 1; // Class B initialized
uint32_t beacon_on : 1; // Beacon windows enabled
uint32_t beacon_found : 1; // Beacon found
uint32_t ping_on : 1; // Class B ping slots enabled
uint32_t paused : 1; // Class B enabled, rx slots paused
uint32_t beacon_rx : 1; // Beacon slot is open
uint32_t ping_rx : 1; // PIng slot is open
} class_b_operstatus_bits_t;
class_b_operstatus_bits_t _opstatus;
timer_event_t _beacon_timer; // beacon window timer
timer_event_t _beacon_acq_timer; // beacon acquisition timeout
timer_event_t _ping_slot_timer; // ping window timer
LoRaPHY *_lora_phy;
LoRaWANTimeHandler *_lora_time;
LoRaMacCrypto *_lora_crypto;
loramac_protocol_params *_protocol_params;
mbed::Callback<bool(rx_config_params_t *)> _open_rx_window; // loramac open rx window function
mbed::Callback<void(rx_slot_t)> _close_rx_window; // loramac close rx window function
mbed::Callback<void(loramac_beacon_status_t, const loramac_beacon_t *)> _beacon_event_cb; // beacon event callback
static LoRaMacClassB _loramac_class_b;
#if MBED_CONF_RTOS_PRESENT
rtos::Mutex _mutex;
#endif
typedef mbed::ScopedLock<LoRaMacClassB> Lock;
};
#else
class LoRaMacClassB {
public:
inline static lorawan_status_t Initialize(LoRaWANTimeHandler *lora_time,
LoRaPHY *lora_phy, LoRaMacCrypto *lora_crypto,
loramac_protocol_params *params,
mbed::Callback<bool(rx_config_params_t *)> open_rx_window,
mbed::Callback<void(rx_slot_t)> close_rx_window)
{
return LORAWAN_STATUS_UNSUPPORTED;
}
inline static lorawan_status_t Enable_beacon_acquisition(mbed::Callback<void(loramac_beacon_status_t,
const loramac_beacon_t *)> beacon_event_cb)
{
return LORAWAN_STATUS_UNSUPPORTED;
}
inline static lorawan_status_t Enable(void)
{
return LORAWAN_STATUS_UNSUPPORTED;
}
inline static lorawan_status_t Disable(void)
{
return LORAWAN_STATUS_UNSUPPORTED;
}
inline static void Pause(void)
{
}
inline static void Resume(void)
{
}
inline static void Handle_rx_timeout(rx_slot_t rx_slot)
{
}
inline static void Handle_rx(rx_slot_t rx_slot, const uint8_t *const data, uint16_t size, uint32_t rx_timestamp)
{
}
inline static lorawan_status_t Get_last_rx_beacon(loramac_beacon_t &beacon)
{
return LORAWAN_STATUS_NO_BEACON_FOUND;
}
inline static bool Add_multicast_address(uint32_t address)
{
return false;
}
inline static void Remove_multicast_address(uint32_t address)
{
}
};
#endif // #if LORA_CLASS_B_ENABLED
#endif // #ifndef MBED_LORAWAN_LORAMACCLASSB_H_