Adding LoRaWANStack class to control MAC and PHY

LoRaWANStack class is our controller layer on top of our
current MAC and PHY layer. It provides services to an implementation
of LoRaWANBase class.

It is a singleton class owing to the fact that the mac layer underneath
is not a class object. Instead, it uses the MAC via setting mib, mlme, mcps
requests and getting responses back from the mac layer using confirmations and
indications.

In essense this class is a special handle for
mac layer underneath which is predominantly reference design based.
In future we may refactor the LoRaMac.cpp code to make it object oriented
and cleaner.

At one end, it binds the application selected radio driver with the PHY layer
and at the other end it provides services to upper layers handling the mac via
well defined APIs.

For proper selection of a PHY layer, user must use Mbed config system.
For this purpose an mbed_lib.json is provided which can be overriden by the
user defined mbed_app.json. By default the EU868 band is selected as a PHY layer.
User must set relevant keys for the selected connection mechanism.
pull/6087/head
Hasnain Virk 2017-11-27 15:17:18 +02:00 committed by Jimmy Brisson
parent 5734b57c0a
commit 2f860d2be5
3 changed files with 2555 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,424 @@
/**
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
___ _____ _ ___ _ _____ ___ ___ ___ ___
/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
embedded.connectivity.solutions===============
Description: LoRaWAN stack layer that controls both MAC and PHY underneath
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE )
Copyright (c) 2017, Arm Limited and affiliates.
SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef LORAWANSTACK_H_
#define LORAWANSTACK_H_
#include <stdint.h>
#include "platform/Callback.h"
#include "platform/NonCopyable.h"
#include "lorawan/system/LoRaWANTimer.h"
#include "lorastack/mac/LoRaMac.h"
#include "lorawan/system/lorawan_data_structures.h"
#include "LoRaRadio.h"
/**
* A mask for the network ID.
*/
#define LORAWAN_NETWORK_ID_MASK ( uint32_t )0xFE000000
class LoRaWANStack: private mbed::NonCopyable<LoRaWANStack> {
public:
static LoRaWANStack& get_lorawan_stack();
/** Binds radio driver to PHY layer.
*
* MAC layer is totally detached from the PHY layer so the stack layer
* needs to play the role of an arbitrator. This API gets a radio driver
* object from the application (via LoRaWANInterface), binds it to the PHY
* layer and returns MAC layer callback handles which the radio driver will
* use in order to report events.
*
* @param radio LoRaRadio object, i.e., the radio driver
*
* @return A list of callbacks from MAC layer that needs to
* be passed to radio driver
*/
radio_events_t *bind_radio_driver(LoRaRadio& radio);
/** End device initialization.
*
* \return 0 on success, a negative error code on failure.
*/
lora_mac_status_t initialize_mac_layer();
/** Sets all callbacks of the LoRaWAN interface.
*
* \param *event_cb An event structure representing all possible callbacks.
*/
void set_lora_event_cb(mbed::Callback<void(lora_events_t)> event_cb);
/** Adds channels to use.
*
* You can provide a list of channels with appropriate parameters filled
* in. However, this list is not absolute. In some regions, a CF
* list gets implemented by default, which means that the network can overwrite your channel
* frequency settings right after receiving a Join Accept. You may try
* to set up any channel or channels after that and if the channel requested
* is already active, the request is silently ignored. A negative error
* code is returned if there is any problem with parameters.
*
* You need to ensure that the base station nearby supports the channel or channels being added.
*
* If your list includes a default channel (a channel where Join Requests
* are received) you cannot fully configure the channel parameters.
* Either leave the channel settings to default or check your
* corresponding PHY layer implementation. For example, LoRaPHYE868.
*
* @param channel_plan A list of channels or a single channel.
*
* @return LORA_MAC_STATUS_OK on success, a negative error
* code on failure.
*/
lora_mac_status_t add_channels(const lora_channelplan_t &channel_plan);
/** Removes a channel from the list.
*
* @param channel_id Index of the channel being removed
*
* @return LORA_MAC_STATUS_OK on success, a negative error
* code on failure.
*/
lora_mac_status_t remove_a_channel(uint8_t channel_id);
/** Removes a previously set channel plan.
*
* @return LORA_MAC_STATUS_OK on success, a negative error
* code on failure.
*/
lora_mac_status_t drop_channel_list();
/** Gets a list of currently enabled channels .
*
* @param channel_plan The channel plan structure to store final result.
*
* @return LORA_MAC_STATUS_OK on success, a negative error
* code on failure.
*/
lora_mac_status_t get_enabled_channels(lora_channelplan_t &channel_plan);
/** Sets up a retry counter for confirmed messages.
*
* Valid only for confirmed messages. This API sets the number of times the
* stack will retry a CONFIRMED message before giving up and reporting an
* error.
*
* @param count The number of retries for confirmed messages.
*
* @return LORA_MAC_STATUS_OK or a negative error code.
*/
lora_mac_status_t set_confirmed_msg_retry(uint8_t count);
/** Sets up the data rate.
*
* `set_datarate()` first verifies whether the data rate given is valid or not.
* If it is valid, the system sets the given data rate to the channel.
*
* @param data_rate The intended data rate, for example DR_0 or DR_1.
* Note that the macro DR_* can mean different
* things in different regions.
*
* @return LORA_MAC_STATUS_OK if everything goes well, otherwise
* a negative error code.
*/
lora_mac_status_t set_channel_data_rate(uint8_t data_rate);
/** Enables ADR.
*
* @param adr_enabled 0 ADR disabled, 1 ADR enabled.
*
* @return LORA_MAC_STATUS_OK on success, a negative error
* code on failure.
*/
lora_mac_status_t enable_adaptive_datarate(bool adr_enabled);
/** Commissions a LoRa device.
*
* @param commission_data A structure representing all the commission
* information.
*/
void commission_device(const lora_dev_commission_t &commission_data);
/** End device OTAA join.
*
* Based on the LoRaWAN standard 1.0.2.
* Join the network using the Over The Air Activation (OTAA) procedure.
*
* @param params The `lorawan_connect_t` type structure.
*
* @return LORA_MAC_STATUS_OK or
* LORA_MAC_STATUS_CONNECT_IN_PROGRESS on success,
* or a negative error code on failure.
*/
lora_mac_status_t join_request_by_otaa(const lorawan_connect_t &params);
/** End device ABP join.
*
* Based on the LoRaWAN standard 1.0.2.
* Join the network using the Activation By Personalization (ABP) procedure.
*
* @param params The `lorawan_connect_t` type structure.
*
* @return LORA_MAC_STATUS_OK or
* LORA_MAC_STATUS_CONNECT_IN_PROGRESS on success,
* or a negative error code on failure.
*/
lora_mac_status_t activation_by_personalization(const lorawan_connect_t &params);
/** Send message to gateway
*
* @param port The application port number. Port numbers 0 and 224
* are reserved, whereas port numbers from 1 to 223
* (0x01 to 0xDF) are valid port numbers.
* Anything out of this range is illegal.
*
* @param data A pointer to the data being sent. The ownership of the
* buffer is not transferred. The data is copied to the
* internal buffers.
*
* @param length The size of data in bytes.
*
* @param flags A flag used to determine what type of
* message is being sent, for example:
*
* MSG_UNCONFIRMED_FLAG = 0x01
* MSG_CONFIRMED_FLAG = 0x02
* MSG_MULTICAST_FLAG = 0x04
* MSG_PROPRIETARY_FLAG = 0x08
* MSG_MULTICAST_FLAG and MSG_PROPRIETARY_FLAG can be
* used in conjunction with MSG_UNCONFIRMED_FLAG and
* MSG_CONFIRMED_FLAG depending on the intended use.
*
* MSG_PROPRIETARY_FLAG|MSG_CONFIRMED_FLAG mask will set
* a confirmed message flag for a proprietary message.
* MSG_CONFIRMED_FLAG and MSG_UNCONFIRMED_FLAG are
* mutually exclusive.
*
*
* @return The number of bytes sent, or
* LORA_MAC_STATUS_WOULD_BLOCK if another TX is
* ongoing, or a negative error code on failure.
*/
int16_t handle_tx(uint8_t port, const uint8_t* data,
uint16_t length, uint8_t flags);
/** Receives a message from the Network Server.
*
* @param port The application port number. Port numbers 0 and 224
* are reserved, whereas port numbers from 1 to 223
* (0x01 to 0xDF) are valid port numbers.
* Anything out of this range is illegal.
*
* @param data A pointer to buffer where the received data will be
* stored.
*
* @param length The size of data in bytes
*
* @param flags A flag is used to determine what type of
* message is being received, for example:
*
* MSG_UNCONFIRMED_FLAG = 0x01,
* MSG_CONFIRMED_FLAG = 0x02
* MSG_MULTICAST_FLAG = 0x04,
* MSG_PROPRIETARY_FLAG = 0x08
*
* MSG_MULTICAST_FLAG and MSG_PROPRIETARY_FLAG can be
* used in conjunction with MSG_UNCONFIRMED_FLAG and
* MSG_CONFIRMED_FLAG depending on the intended use.
*
* MSG_PROPRIETARY_FLAG|MSG_CONFIRMED_FLAG mask will set
* a confirmed message flag for a proprietary message.
*
* MSG_CONFIRMED_FLAG and MSG_UNCONFIRMED_FLAG are
* not mutually exclusive, i.e., the user can subscribe to
* receive both CONFIRMED AND UNCONFIRMED messages at
* the same time.
*
* @return It could be one of these:
* i) 0 if there is nothing else to read.
* ii) Number of bytes still pending to read.
* iii) LORA_MAC_STATUS_WOULD_BLOCK if there is
* nothing available to read at the moment.
* iv) A negative error code on failure.
*/
int16_t handle_rx(const uint8_t port, uint8_t* data,
uint16_t length, uint8_t flags);
/** Shuts down the LoRaWAN protocol.
*
* In response to the user call for disconnection, the stack shuts down itself.
*/
void shutdown();
private:
LoRaWANStack();
~LoRaWANStack();
/**
* Checks if the user provided port is valid or not
*/
bool is_port_valid(uint8_t port);
/**
* State machine for stack controller layer.
* Needs to be wriggled for every state change
*/
lora_mac_status_t lora_state_machine();
/**
* Sets the current state of the device.
* Every call to set_device_state() should precede with
* a call to lora_state_machine() in order to take the state change
* in effect.
*/
void set_device_state(device_states_t new_state);
/**
* This function is used only for compliance testing
*/
void prepare_special_tx_frame(uint8_t port);
/**
* Hands over the packet to Mac layer by posting an MCPS request.
*/
lora_mac_status_t send_frame_to_mac();
/**
* Callback function for transmission based on user defined timer.
* Used only for testing when duty cycle is off.
*/
void on_tx_next_packet_timer_event(void);
/**
* Callback function for MCPS confirm. Mac layer calls this function once
* an MCPS confirmation is received. This method translates Mac layer data
* structure into stack layer data structure.
*/
void mcps_confirm(McpsConfirm_t *mcps_confirm);
/**
* Callback function for MCPS indication. Mac layer calls this function once
* an MCPS indication is received. This method translates Mac layer data
* structure into stack layer data structure.
*/
void mcps_indication(McpsIndication_t *mcps_indication);
/**
* Callback function for MLME confirm. Mac layer calls this function once
* an MLME confirmation is received. This method translates Mac layer data
* structure into stack layer data structure.
*/
void mlme_confirm(MlmeConfirm_t *mlme_confirm);
/**
* Handles an MLME request coming from the upper layers and delegates
* it to the Mac layer, for example, a Join request goes as an MLME request
* to the Mac layer.
*/
lora_mac_status_t mlme_request_handler(lora_mac_mlme_req_t *mlme_request);
/**
* Handles an MLME confirmation coming from the Mac layer and uses it to
* update the state for example, a Join Accept triggers an MLME confirmation,
* that eventually comes here and we take necessary steps accordingly.
*/
void mlme_confirm_handler(lora_mac_mlme_confirm_t *mlme_confirm);
/**
* Handles an MCPS request while attempting to hand over a packet from
* upper layers to Mac layer. For example in response to send_frame_to_mac(),
* an MCPS request is generated.
*/
lora_mac_status_t mcps_request_handler(lora_mac_mcps_req_t *mcps_request);
/**
* Handles an MCPS confirmation coming from the Mac layer in response to an
* MCPS request. We take appropriate actions in response to the confirmation,
* e.g., letting the application know that ack was not received in case of
* a CONFIRMED message or scheduling error etc.
*/
void mcps_confirm_handler(lora_mac_mcps_confirm_t *mcps_confirm);
/**
* Handles an MCPS indication coming from the Mac layer, e.g., once we
* receive a packet from the Network Server, it is indicated to this handler
* and consequently this handler posts an event to the application that
* there is something available to read.
*/
void mcps_indication_handler(lora_mac_mcps_indication_t *mcps_indication);
/**
* Sets a MIB request, i.e., update a particular parameter etc.
*/
lora_mac_status_t mib_set_request(lora_mac_mib_request_confirm_t *mib_set_params);
/**
* Requests the MIB to inquire about a particular parameter.
*/
lora_mac_status_t mib_get_request(lora_mac_mib_request_confirm_t *mib_get_params);
/**
* Sets up user application port
*/
lora_mac_status_t set_application_port(uint8_t port);
/**
* Helper function to figure out if the user defined data size is possible
* to send or not. The allowed size for transmission depends on the current
* data rate set for the channel. If its not possible to send user defined
* packet size, this method returns the maximum possible size at the moment,
* otherwise the user defined size is returned which means all of user data
* can be sent.
*/
uint16_t check_possible_tx_size(uint16_t size);
/**
* Used only for compliance testing
*/
void compliance_test_handler(lora_mac_mcps_indication_t *mcps_indication);
/**
* Used only for compliance testing
*/
lora_mac_status_t send_compliance_test_frame_to_mac();
/**
* converts error codes from Mac layer to controller layer
*/
lora_mac_status_t error_type_converter(LoRaMacStatus_t type);
compliance_test_t _compliance_test;
device_states_t _device_current_state;
mbed::Callback<void(lora_events_t)> _events;
radio_events_t *_mac_handlers;
lorawan_session_t _lw_session;
lora_mac_tx_message_t _tx_msg;
lora_mac_rx_message_t _rx_msg;
uint8_t _app_port;
uint8_t _num_retry;
bool _duty_cycle_on;
};
#endif /* LORAWANSTACK_H_ */

View File

@ -0,0 +1,78 @@
{
"name": "lora",
"config": {
"phy": {
"help": ["Select LoRa PHY layer. See README.md for more information. Default: 0 = LORA_PHY_EU868",
" 1 = LORA_PHY_AS923",
" 2 = LORA_PHY_AU915",
" 3 = LORA_PHY_CN470",
" 4 = LORA_PHY_CN779",
" 5 = LORA_PHY_EU433",
" 6 = LORA_PHY_IN865",
" 7 = LORA_PHY_KR920",
" 8 = LORA_PHY_US915",
" 9 = LORA_PHY_US915_HYBRID"],
"value": "0"
},
"over-the-air-activation": {
"help": "When set to 1 the application uses the Over-the-Air activation procedure, default: true",
"value": true
},
"nb-trials": {
"help": "Indicates how many times join can be tried, default: 8",
"value": 8
},
"device-eui": {
"help": "Mote device IEEE EUI",
"value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}"
},
"application-eui": {
"help": "Application IEEE EUI",
"value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}"
},
"application-key": {
"help": "AES encryption/decryption cipher application key",
"value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}"
},
"network-id": {
"help": "Current network ID",
"value": 0
},
"device-address": {
"help": "Device address on the network",
"value": "0x00000000"
},
"nwkskey": {
"help": "AES encryption/decryption cipher network session key",
"value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}"
},
"appskey": {
"help": "AES encryption/decryption cipher application session key",
"value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}"
},
"app-port": {
"help": "LoRaWAN application port, default: 15",
"value": 15
},
"tx-max-size": {
"help": "User application data buffer maximum size, default: 64, MAX: 255",
"value": 64
},
"adr-on": {
"help": "LoRaWAN Adaptive Data Rate, default: 1",
"value": 1
},
"public-network": {
"help": "LoRaWAN will connect to a public network or private network, true = public network",
"value": true
},
"duty-cycle-on": {
"help": "Enables/disables duty cycling. NOTE: Disable only for testing. Mandatory in many regions.",
"value": true
},
"lbt-on": {
"help": "Enables/disables LBT. NOTE: Disable only for testing. Mandatory in many regions/sub-bands.",
"value": true
}
}
}