LoRaMacChannelPlan class provides APIs which are not usable for
PHY layer implementations who do not support custom channel plans.
So we had some code in APIs which was explicitely using magic numbers
for the channel mask. Although it turned out to be not a bug as a layer
down we were checking for custom channel support. However, we now
check for custom channel support before going deep into PHY layer that will
make the code run faster and we have done some cosmetics to the code for
readability.
Channel mask is manipulated with inline methods
The PHY layer had a lot of duplicated code in various geographic regions.
In this commit we have tried to concentrate all common functionaliy into
one single class which LoRaPHY that provides three kind of methods:
i) Non virtual base methods which are there for upper layer use, e.g.,
providing access to driver or generic PHY layer functionality which
needs to be exposed to upper layers.
ii) Virtual methods (no hard limit on implementation) that can be overriden
in derived classes. Some PHY implementations will need that as they may
come with very peculiar channel schemes, e.g., dynamic channel schemes
in US bands.
iii) Protected methods which are only available for the derived PHYs
We have adopted a mechanism for the dervied PHYs to announce their differenmtiating
parameters in their constructors by filling up a data structure known as lora_phy_params_t
which exists at base level. Access modifier for this data structure is protected so it can only be
used by the base or derived classes, i.e., no exposure to upper layers.
For extra functionality and differentiating controls, a derived PHY can override any virual method as necessary.
In addition to that we have adopted the Mbed-OS style guide and have changed data structures and code to reflect that.
Some data structures are removed.
* Algorithm to get alternate DR is modified. Current scheme, works as multiples of 6 as EU and EU like PHYs
provide 6 datarates. We make sure that we try a datarate at least once. If nuber of join retries is a multiple
of 6, we may try multiple times on each data rate.
* Most of the PHYs with dynamic channel plans, always override the above mentioned algorithm as the rules governing
this algorithm do not hild in their case.
* band_t data structure is enhanced with lower band frequency and higher band frequency. That enables us to validate
frequency based upon the band and hence we can have a single function for all PHYs to validate frequency.
* In some PHYs, there were some extra channel masks were defined which were not being used. Hence removed.
* EIRP table corrected in some PHYs based upon spec.
* PHY functions in response to Mac commands are renamed to reflect what they exactly do.
for example accept_rx_param_setup_req() because that's what they do. they can either accept
the mac command or reject it.# Please enter the commit message for your changes.
This commit also introduces API change for disconnect(). disconnect() will
now return LORAWAN_STATUS_DEVICE_OFF for successfull disconnect.
* LoRaWANStack::handle_tx() can be called with NULL buffer when length is 0.
This commit fixes the case where user has provided NULL buffer and length
is > max_possible_size.
handle_tx() now always returns LORAWAN_STATUS_PARAMETER_INVALID if given
buffer is NULL pointer and length > 0.
General error checking is added and some asserts are added for events.
In order to reset LoRaMac's state in disconnect, we need to implement
an API which can be used to cancel all outstanding requests and reset
LoRaMac's internal state to idle.
This commit introduces LoRaMac::disconnect() which can be used for
this purpose.
Instead of initiating own timer objects we can use EventQueue::call_in() method
as we already have handle to EventQueue object.
Also setting timeout and starting timer has been combined to TimerStart method.
We now save roughly 500 bytes by removing storage of default
parameters in the loramac_params_t data structure. We use Mib to
get default values from PHY whenever needed instead.
loramac_sys_arams_t now contains only the runtime values set during operation
whenever defaults are needed we directly query the PHY layer or via Mib as the
need maybe.
Baseline is changed to use a single set of data structures that simplifies the
code in the LoRaWANStack and Mac layer. We are now following certian rules for naming
data structures.
- All structures visible outside their domain are prefixed as 'lorawan_'
- All mac structures are prefixed as 'loramac_'
- All subsystem or module strucutures carry their name in prefix, like 'mcps_'
PHY layer still have legacy camel case data structures which will be entertained
later while we will be simplifying PHY layer.
Test cases are also updated with the new data structure naming conventions.
One major difference from the previous baseline is the removal of static buffer
from mcps indication. And we do not copy data from stack buffer to rx_msg buffer.
This saves at least 512 bytes.
It may look like now that if we have received something but the user have not read
from the buffer, then the buffer will be overwritten and we will lose previous frame.
Yes, we will. But the same will happen even if we would have copied the buffer into rx_msg
because then the rx_msg gets overwritten. So we decide to abandon copying the buffer at
multiple locations. We inform the user about reception, if the user doesn't read and
the data gets overwritten, then so be it.
Channel planning was distributed over LoRaWANStack and LoRaMac previously.
We now centralize it by allocating the service to its own class.
Thus making the workflow consistent, i.e.,
Request for channel plan = Application->Interface->stack->Mac->ChannelPlan
Major change apart from adding the channel plan subsystem are the API changes
in LoRaMac class.
As a part of MAC layer breakdown into independent subsystems, we have
introduced a class for MIB service.
Major changes from the baseline are:
- making OpenRxWindow() public in LoRaMac.cpp
- Moving various data structures to central protocol data structure
MAC layer will services will be broken down into independent
subsystems. This is the first of those efforts. We have introduced
LoRaMacMlme class that handles everything related to MLME subsystem or
subservice. To accomodate subsystems we have grouped all protocol level
variables into one big data structure. A pointer to that data structure
will be passed around the subsystems in order to regulate the entire
system.
LoRaMac::Send() and LoRaMac::SetTxContWave*() APIs are made public as
they are needed to be accessed by the subsystems.
Ticker objects embeded in TimerEvent_t data structure were getting constructed
even for the non LORAWAN builds. And that's what was bloating the builds.
We now lazy initialize them using Mbed-OS utility clas SingletonPtr.
A central data structure has been created that carries all the protocol level
variables for the Mac layer. This is important as we are going to break down
MAC services into subsystems and we will pass around common data using that data structure.
Time handler class had a c style callback attached to it which
had been hampering us to be fully object oriented.
That particular callback is changed to Mbed Callback which is attatched
to a specific object hence allowing us to be fully object oriented.
LoRaWANTimer is now called as LoRaWANTimeHandler class as this class handles both
current time and timer functionalities.
Some refactoring on how LoRa objects are created was needed:
- LoRaWANTimeHandler object is created by LoRaWANStack and shares with LoRaMac and PHY.
- LoRaPHY object is now member of LoRaWANStack class instead of static variable in source file.
MAC layer is now a class rather than being a blob.
In addition to that Mac commands are now being handled in
a seperate subsystem (a class of its own). In future we
will do the same with othe sublayers of MAC like MLME, MCPS etc.
The drive behind this exercise is to make MAC and supporting layers
into an object oriented system.
Major bug fixes include:
- last join time inclusion in band parameters
- disabling rx2 window if we missed the slot already
- MLME uplink schdule hook
- nbRep according to spec
- maintaining datarate after successful joining
- suppressing MLME requests if MAC is in TX_DELAYED state
- Uplink dwell time verification
Some missing features are implemented. Details are as follows.
Support for LinkCheckRequet:
An application API is added, add_link_check_request() to delegate a
request for Link Check Request MAC command.
* Application provides a callback function that needs to be called on reception of
link check response.
* Mac command is piggybacked with data frames.
This API makes the sticky MAC command stick with the application payloads until/unless
the application un-sticks the said mac command using remove_link_check_request() API.
Handling fPending bit:
If in the Downlink, we get the fPending bit set in fctrl octet,
we attempt to send an empty message back to Network Server to
open additional Receive windows. This operation is independent
of the application. An RX_DONE event is queued bedore generating
the said empty message. Specification does not mention what can be the
type of that empty message. We have decided it to be of CONFIRMED
type as it gives us an added benefit of retries if the corresponding
RX slots are missed.
Radio event callbacks as Mbed callbacks:
radio_events_t structure has been carrying C-style callbacks which was
inherited from the legacy code. These callbacks has now been changed to
Mbed Callbacks that makes sure that we can be object oriented from now
on.
All compliance test related codes are now inside LORAWAN_COMPLIANCE_TEST
build flag. This will reduce memory usage in when compliance test codes
are not needed.
TxNextPacketTimer callback was being used for testing only (compliance testing to be precise).
Now there are independent methods and direct calls to automatic timers for the
compliance testing so there is no particular need for this timer anymore.
Application should be able to add some optional callbacks if it needs to.
Ofcourse there is a penalty of 8-12 bytes per callback, but there can be
certain needs of the application that needs to be met for example setting
up a link check request etc.
We have introduced a structure that contains callbacks for the application use.
- 'events' callback is mandatory, user must assign it. Because this callback brings
state changes for the application. We cannot segregate this into individual handlers
because of RAM penalty.
- Other calbacks (none of them are implemented yet are optional).
Example of using the API is provided with doxygen
The EventQueue thread in LoRaMac.cpp is disbanded and the LoRaWAN
protocol is redesigned to store a pointer for an application
provided EventQueue. It means that now the stack runs in the
same thread as application. Application provided EventQueue is used
to defer ISRs from radio driver and timer callbacks as well as the
application events are queued to the same event loop.
The actual mac algorithms are being used as it is in the reference
implementation.
We introduce an internal class that starts a thread and constructs an event queue
to handle deffered calls from interrupt context for RTOS. The code base is
compatible with Mbed-OS 2 as well.
GetPhyEventHandlers() API provides mac callback funtions for PHY layer,
which are in turn delegated to radio driver from the PHY layer.
LoRaMacInitialization() is augmented with LoRaPHY parameter which let's
the MAC layer know which particular PHY layer is in use.
LoRaMacSetTxTimer() and LoRaMacStopTxTimer() are used when duty cycle is
off for testing purpose or to support custom application timers.
If the duty cycle is off, mac and phy layer work togather to figure
out the next possible transmission time.
LoRaMacCrypto APIs are provided which provide seemless integration of
mbedTLS into mac layer for cryptography. User application is supposed to
provide proper mbedTLS configuration file.
All other APIs are retained as it is.
LoRaPHY is the abstract class for the LoRa PHY layer which governs
the LoRaRadio and provides some common functionality to all regional
implementations.
We support 10 regions and every region comes loaded with default parameters.
These parameters can be changed by the Mac layer or explicitely by the stack
controller layer using APIs provided. This layer in essence detaches Mac completely
from PHY and provides more modular approach to the entire system.
Apart from class structure, the internal functionality is directly deduced from
semtech reference implementation that's why most of the internal data structures are
used on 'as is' basis.
In addition to that, the PHY layer provides APIs to control the LoRaRadio layer, i.e.,
the lora radio driver, ensuring that the radio is accessed from a single entry point.
A seperate data structure file is added which is common to PHY layers only.