Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LoRaWAN: ClockSynch/Multicast/Fragmentation Plugins & session handling #9707

Closed
wants to merge 15 commits into from
81 changes: 81 additions & 0 deletions features/lorawan/LoRaWANBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,33 @@ class LoRaWANBase {
*/
virtual lorawan_status_t enable_adaptive_datarate() = 0;

/** Sets a given frequency to be used by the stack for RX2 window
*
* Usually the RX2 frequency is fixed for a certain region or a change can be
* communicated through MAC commands. This API provides yet another way to tell
* the stack to use a certain frequency for RX2. It is especially useful in the
* situations when you know out-of-band that the RX2 frequency being used by the
* NS is different from the default RX2 frequency mandated in the protocol
* specification. Another example for the usage of this API could be the situation
* when special plug-ins or application extensions like 'MulticastControlPackage'
* requires the device to switch to class C and start continuous listening on a
* given frequency.
*
* @param frequency Frequency in Hz to be used as RX2 frequency
* @param dr Table index of the data rate, e.g., DR_0 which means SF12
*
* @return LORAWAN_STATUS_OK on success, negative error code on failure
*/
virtual lorawan_status_t set_rx2_frequency_and_dr(const uint32_t frequency,
const uint8_t dr) = 0;

/** Restores default RX2 frequency as mandated by specifications
*
* This API reverses the effect of 'set_rx2_frequency' and restores the
* default RX2 frequency.
*/
virtual void restore_rx2_frequency_and_dr(void) = 0;

/** Disables adaptive data rate
*
* When adaptive data rate (ADR) is disabled, either you can set a certain
Expand Down Expand Up @@ -496,6 +523,60 @@ class LoRaWANBase {
* LORAWAN_STATUS_NO_OP if the operation cannot be completed (nothing to cancel)
*/
virtual lorawan_status_t cancel_sending(void) = 0;

/** Adds an entry to the device Multicast register
*
* This API is used to add a new entry to the the device Multicast register.
* The total number of Multicast entries into the register, is compile time
* configurable and the maximum limit is 4 simultaneous Multicast session
* entries. For example, add the following code in your mbed_app.json to enable
* a Multicast register with place holders for 4 Multicast session entries:
* @code
* lora.max-multicast-sessions: 4
* @endcode
*
* The stack will look-up the Multicast register to filte incoming traffic
* for any Multicast downlinks. This is a general purpose API which can be
* used to setup a Multicast session out-of-band (i.e., you already know all
* the credentials) or it can be used by various plug-ins and application
* extensions which work out the given credentials based upon certain standard
* protocols, e.g., MulticastControlPackage available under 'lorawan/plugins'
* directory. This is an implementation of 'LoRaWAN Remote Multicast Setup
* Specification v1.0.0'.
*
* @param entry A pointer to 'mcast_addr_entry_t' which contains all the information
* needed to participate in a Multicast group. For more details, please
* check LoRaWAN Remote Multicast Setup Specification v1.0.0
*
* @return LORAWAN_STATUS_OK if the entry is successfully added to the register,
* otherwise a negative error code is returned.
*/
virtual lorawan_status_t register_multicast_address(const mcast_addr_entry_t *entry) = 0;

/** Provides access to device Multicast register
*
* The Multicast register is maintained by the stack and is freely readable/writable
* by the application. This API is used to gain access to the Multicast register.
*
* @return A pointer to the Multicast register
*/
virtual lorawan_mcast_register_t *get_multicast_addr_register(void) = 0;

/** Provides a way to verify communication parameters
*
* This API is needed to entertain special communication needs for a Multicast
* session. There can be cases when a certain Multicast group that your device
* is a part of, may require a special set of frequency and spread factor (data rate),
* e.g., in case of Firmware update or when a remote Multicast session with a certain
* device class is being setup.
* In these scenarios the application must verify if the given frequency and spread
* factor are supported, available or legal.
*
* @param frequency Frequency in Hz to be used for the RX windows
* @param dr Index of the data rate (SF) to be used, e.g.,
* DR_0 = SF12 in EU868 region.
*/
virtual lorawan_status_t verify_multicast_freq_and_dr(uint32_t frequency, uint8_t dr) = 0;
};

#endif /* LORAWAN_BASE_H_ */
82 changes: 82 additions & 0 deletions features/lorawan/LoRaWANInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,16 @@

#include "LoRaWANInterface.h"
#include "lorastack/phy/loraphy_target.h"
#include "platform/mbed_rtc_time.h"
#include "mbed-trace/mbed_trace.h"
#define TRACE_GROUP "IFCE"

using namespace events;

LoRaWANInterface::LoRaWANInterface(LoRaRadio &radio)
: _default_phy(NULL)
{
_mcast_register.active_mask = 0;
_default_phy = new LoRaPHY_region;
MBED_ASSERT(_default_phy);
_lw_stack.bind_phy_and_radio_driver(radio, *_default_phy);
Expand All @@ -35,6 +39,7 @@ LoRaWANInterface::LoRaWANInterface(LoRaRadio &radio)
LoRaWANInterface::LoRaWANInterface(LoRaRadio &radio, LoRaPHY &phy)
: _default_phy(NULL)
{
_mcast_register.active_mask = 0;
_lw_stack.bind_phy_and_radio_driver(radio, phy);
}

Expand Down Expand Up @@ -86,6 +91,19 @@ lorawan_status_t LoRaWANInterface::set_datarate(uint8_t data_rate)
return _lw_stack.set_channel_data_rate(data_rate);
}

lorawan_status_t LoRaWANInterface::set_rx2_frequency_and_dr(const uint32_t frequency,
const uint8_t dr)
{
Lock lock(*this);
return _lw_stack.change_rx2_frequency_and_dr(frequency, dr);
}

void LoRaWANInterface::restore_rx2_frequency_and_dr(void)
{
Lock lock(*this);
_lw_stack.restore_default_rx2_freq_and_dr();
}

lorawan_status_t LoRaWANInterface::set_confirmed_msg_retries(uint8_t count)
{
Lock lock(*this);
Expand Down Expand Up @@ -181,3 +199,67 @@ lorawan_status_t LoRaWANInterface::set_device_class(const device_class_t device_
Lock lock(*this);
return _lw_stack.set_device_class(device_class);
}

lorawan_status_t LoRaWANInterface::register_multicast_address(const mcast_addr_entry_t *e)
{
if (e->g_id >= MBED_CONF_LORA_MAX_MULTICAST_SESSIONS || e->addr == 0
|| e->app_session_key == NULL || e->nwk_session_key == NULL) {
return LORAWAN_STATUS_PARAMETER_INVALID;
}

memcpy(&_mcast_register.entry[e->g_id], e, sizeof(mcast_addr_entry_t));
SET_BIT(_mcast_register.active_mask, e->g_id);

Lock lock(*this);
_lw_stack.update_multicast_addr_register(&_mcast_register);

return LORAWAN_STATUS_OK;
}

lorawan_mcast_register_t *LoRaWANInterface::get_multicast_addr_register(void)
{
return &_mcast_register;
}

lorawan_status_t LoRaWANInterface::verify_multicast_freq_and_dr(uint32_t frequency, uint8_t dr)
{
Lock lock(*this);
return _lw_stack.check_multicast_params(frequency, dr);
}

lorawan_time_t LoRaWANInterface::get_current_gps_time()
{
Lock lock(*this);
return _lw_stack.get_current_gps_time();
}

void LoRaWANInterface::set_current_gps_time(lorawan_time_t gps_time)
{
Lock lock(*this);
_lw_stack.set_current_gps_time(gps_time);
}

lorawan_status_t LoRaWANInterface::set_system_time_utc(unsigned int tai_utc_diff)
{
// do not lock here

// Adjust epoch for 1970 to 1980 (time for Unix epoch to GPS epoch)
lorawan_time_t u_time = time(NULL) + UNIX_GPS_EPOCH_DIFF;
// Adjust for leap seconds since 1980. TAI is always ahead of GPS by 19 seconds
u_time += (tai_utc_diff - 19);
lorawan_time_t cur_gps_time = get_current_gps_time();

if (cur_gps_time == 0) {
// GPS time is not set. Application needs to request a clock sync.
return LORAWAN_STATUS_SERVICE_UNKNOWN;
}

u_time += cur_gps_time;

set_time(u_time);

time_t now = time(NULL);
tr_info("System Clock set - (UTC) = %s", ctime(&now));

return LORAWAN_STATUS_OK;
}
39 changes: 39 additions & 0 deletions features/lorawan/LoRaWANInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ class LoRaWANInterface: public LoRaWANBase {
virtual lorawan_status_t add_link_check_request();
virtual void remove_link_check_request();
virtual lorawan_status_t set_datarate(uint8_t data_rate);
virtual lorawan_status_t set_rx2_frequency_and_dr(const uint32_t frequency,
const uint8_t dr);
virtual void restore_rx2_frequency_and_dr(void);
virtual lorawan_status_t enable_adaptive_datarate();
virtual lorawan_status_t disable_adaptive_datarate();
virtual lorawan_status_t set_confirmed_msg_retries(uint8_t count);
Expand All @@ -74,6 +77,40 @@ class LoRaWANInterface: public LoRaWANBase {
virtual lorawan_status_t get_rx_metadata(lorawan_rx_metadata &metadata);
virtual lorawan_status_t get_backoff_metadata(int &backoff);
virtual lorawan_status_t cancel_sending(void);
virtual lorawan_status_t register_multicast_address(const mcast_addr_entry_t *entry);
virtual lorawan_mcast_register_t *get_multicast_addr_register(void);
virtual lorawan_status_t verify_multicast_freq_and_dr(uint32_t frequency, uint8_t dr);
lorawan_time_t get_current_gps_time(void);
void set_current_gps_time(lorawan_time_t gps_time);

/** Sets up UTC system time
*
* This API provides a convenience utility to setup UTC system time.
* Please note that device level synchronization does not require any conversion
* from GPS time. That's why any application level or stack level APIs involved
* in time synchronization should always use 'get_current_gps_time()' and
* 'set_current_gps_time(time)' APIs. 'set_system_time_utc(...)' API can be used
* for other application purposes where acquisition of UTC time is important.
* In addition to that it should be taken into account that the internal network
* assisted GPS time acquisition may not be 100% accurate. It involves local monotonic
* ticks (in ms) which is a direct function of CPU ticks and can be inaccurate. The
* network provided time-stamp for GPS time may also involve inaccuracies owing to the
* fact that the device will never know at what instant the time-stamp was taken and hence
* cannot compensate for it.
*
* 'set_system_time_utc(...)' API utilizes stored network assisted GPS time
* to convert for UTC time. The Temps Atomique International (TAI) time is
* always ahead of GPS time by 19 seconds, whereas in 2019 TAI is ahead of
* UTC by 37 seconds. This difference between TAI and UTC must be provided
* by the user because this number is subject to change (to compensate for leap
* seconds).
*
* @param tai_utc_diff Number of seconds TAI is ahead of UTC time.
*
* @return LORAWAN_STATUS_OK if system time is set, negative error code
* otherwise.
*/
lorawan_status_t set_system_time_utc(unsigned int tai_utc_diff);

void lock(void)
{
Expand All @@ -96,6 +133,8 @@ class LoRaWANInterface: public LoRaWANBase {
* If PHY object is provided by the application, this pointer is NULL.
*/
LoRaPHY *_default_phy;

lorawan_mcast_register_t _mcast_register;
};

#endif /* LORAWANINTERFACE_H_ */
Loading