Rejoin logic added

BE to LE fixes, missing MLME types added

LoRaWAN 1.1 Features added (Some LoRaPhy impl missing still + some TODOs in code)

- MLME confirm handling refactored
- Rejoin handling missing
- new CF_LIST mechanism missing (+resets involved)
- NVM handling missing

Rejoin logic added
feature-lorawan-1-1
Antti Kauppila 2018-08-24 15:12:48 +03:00
parent 0d3283e3a0
commit ccc3675a6a
9 changed files with 261 additions and 76 deletions

View File

@ -79,7 +79,15 @@ LoRaWANStack::LoRaWANStack()
_device_mode_ind_ongoing(false), _device_mode_ind_ongoing(false),
_new_class_type(CLASS_A), _new_class_type(CLASS_A),
_automatic_uplink_ongoing(false), _automatic_uplink_ongoing(false),
_queue(NULL) _queue(NULL),
_rejoin_type1_send_period(MBED_CONF_LORA_REJOIN_TYPE1_SEND_PERIOD),
_rejoin_type1_stamp(0),
_rejoin_type0_counter(0),
_forced_datarate(DR_0),
_forced_period(0),
_forced_retry_count(0),
_forced_rejoin_type(REJOIN_REQUEST_TYPE0),
_forced_counter(0)
{ {
_tx_metadata.stale = true; _tx_metadata.stale = true;
_rx_metadata.stale = true; _rx_metadata.stale = true;
@ -768,6 +776,8 @@ void LoRaWANStack::process_reception(const uint8_t *const payload, uint16_t size
_ctrl_flags &= ~TX_DONE_FLAG; _ctrl_flags &= ~TX_DONE_FLAG;
_ctrl_flags &= ~RETRY_EXHAUSTED_FLAG; _ctrl_flags &= ~RETRY_EXHAUSTED_FLAG;
_rejoin_type0_counter++;
_loramac.on_radio_rx_done(payload, size, rssi, snr, callback(this, &LoRaWANStack::mlme_confirm_handler)); _loramac.on_radio_rx_done(payload, size, rssi, snr, callback(this, &LoRaWANStack::mlme_confirm_handler));
if (_loramac.get_mlme_confirmation()->pending) { if (_loramac.get_mlme_confirmation()->pending) {
@ -811,12 +821,26 @@ void LoRaWANStack::process_reception(const uint8_t *const payload, uint16_t size
mlme_indication_handler(); mlme_indication_handler();
} }
if (((_loramac.get_lora_time()->get_current_time()/1000) -
_rejoin_type1_stamp) > _rejoin_type1_send_period) {
_rejoin_type1_stamp = _loramac.get_lora_time()->get_current_time()/1000;
process_rejoin(REJOIN_REQUEST_TYPE1, false);
}
uint32_t max_time;
uint32_t max_count;
_loramac.get_rejoin_parameters(max_time, max_count);
if (_rejoin_type0_counter >= max_count) {
//This causes excactly same handling as a timeout
process_rejoin_type0();
}
core_util_atomic_flag_clear(&_rx_payload_in_use); core_util_atomic_flag_clear(&_rx_payload_in_use);
} }
void LoRaWANStack::process_reception_timeout(bool is_timeout) void LoRaWANStack::process_reception_timeout(bool is_timeout)
{ {
rx_slot_t slot = _loramac.get_current_slot(); rx_slot_t slot = _loramac.get_current_slot();
_rejoin_type0_counter++;
// when is_timeout == false, a CRC error took place in the received frame // when is_timeout == false, a CRC error took place in the received frame
// we treat that erroneous frame as no frame received at all, hence handle // we treat that erroneous frame as no frame received at all, hence handle
@ -841,6 +865,24 @@ void LoRaWANStack::process_reception_timeout(bool is_timeout)
*/ */
if (slot == RX_SLOT_WIN_2) { if (slot == RX_SLOT_WIN_2) {
post_process_tx_no_reception(); post_process_tx_no_reception();
_loramac.post_process_mcps_req();
state_controller(DEVICE_STATE_STATUS_CHECK);
state_machine_run_to_completion();
if ((_loramac.get_lora_time()->get_current_time()/1000) -
_rejoin_type1_stamp > _rejoin_type1_send_period) {
_rejoin_type1_stamp = _loramac.get_lora_time()->get_current_time()/1000;
process_rejoin(REJOIN_REQUEST_TYPE1, false);
}
uint32_t max_time;
uint32_t max_count;
_loramac.get_rejoin_parameters(max_time, max_count);
if (_rejoin_type0_counter >= max_count) {
//This causes excactly same handling as a timeout
process_rejoin_type0();
}
} }
} }
@ -1043,6 +1085,13 @@ void LoRaWANStack::mlme_confirm_handler(loramac_mlme_confirm_t& mlme_confirm)
if (_loramac.get_server_type() == LW1_1) { if (_loramac.get_server_type() == LW1_1) {
_rekey_ind_needed = true; _rekey_ind_needed = true;
_rekey_ind_counter = 0; _rekey_ind_counter = 0;
// THIS IS NOT ALLOWED HERE!
// We might get JOIN_ACCEPT for rejoin type 1,
// which points to different server!
//reset_forced_rejoin();
} else {
_loramac.get_lora_time()->stop(_forced_timer);
_loramac.get_lora_time()->stop(_rejoin_type0_timer);
} }
state_controller(DEVICE_STATE_CONNECTED); state_controller(DEVICE_STATE_CONNECTED);
break; break;
@ -1059,7 +1108,25 @@ void LoRaWANStack::mlme_confirm_handler(loramac_mlme_confirm_t& mlme_confirm)
state_controller(DEVICE_STATE_JOINING); state_controller(DEVICE_STATE_JOINING);
} }
} else if (mlme_confirm.type == MLME_FORCE_REJOIN) { } else if (mlme_confirm.type == MLME_FORCE_REJOIN) {
//TODO: handle this if (join_req_type_t(mlme_confirm.rejoin_type) <= REJOIN_REQUEST_TYPE2 &&
_loramac.get_server_type() == LW1_1 ) {
_forced_datarate = mlme_confirm.datarate;
_forced_period = ((1 << mlme_confirm.period)*32 + (rand()%33))*1000;
_forced_retry_count = mlme_confirm.max_retries;
if (_forced_retry_count) {
_forced_retry_count += 1;
}
_forced_rejoin_type = join_req_type_t(mlme_confirm.rejoin_type);
// See LW 1.1 chapter 5.13 - RejoinType
if (join_req_type_t(mlme_confirm.rejoin_type) == REJOIN_REQUEST_TYPE1) {
_forced_rejoin_type = REJOIN_REQUEST_TYPE0;
}
reset_forced_rejoin();
process_rejoin(_forced_rejoin_type, true);
if (_forced_retry_count) {
_loramac.get_lora_time()->start(_forced_timer, _forced_period);
}
}
} }
} }
@ -1341,4 +1408,61 @@ void LoRaWANStack::process_uninitialized_state(lorawan_status_t &op_status)
if (op_status == LORAWAN_STATUS_OK) { if (op_status == LORAWAN_STATUS_OK) {
_device_current_state = DEVICE_STATE_IDLE; _device_current_state = DEVICE_STATE_IDLE;
} }
if (MBED_CONF_LORA_VERSION == LORAWAN_VERSION_1_1) {
_loramac.get_lora_time()->init(_forced_timer,
mbed::callback(this, &LoRaWANStack::forced_timer_expiry));
_loramac.get_lora_time()->init(_rejoin_type0_timer,
mbed::callback(this, &LoRaWANStack::process_rejoin_type0));
_rejoin_type1_stamp = _loramac.get_lora_time()->get_current_time()/1000;
}
}
void LoRaWANStack::process_rejoin(join_req_type_t rejoin_type, bool is_forced)
{
if (_loramac.get_server_type() == LW1_1 ) {
_loramac.rejoin(rejoin_type, is_forced, _forced_datarate);
if (rejoin_type == REJOIN_REQUEST_TYPE0) {
_loramac.get_lora_time()->stop(_rejoin_type0_timer);
_rejoin_type0_counter = 0;
uint32_t max_time;
uint32_t max_count;
_loramac.get_rejoin_parameters(max_time, max_count);
_loramac.get_lora_time()->start(_rejoin_type0_timer, max_time);
}
}
}
void LoRaWANStack::reset_forced_rejoin()
{
_forced_counter = 0;
_loramac.get_lora_time()->stop(_forced_timer);
}
void LoRaWANStack::forced_timer_expiry()
{
if (_loramac.get_server_type() == LW1_1 ) {
if (_forced_counter < _forced_retry_count) {
process_rejoin(_forced_rejoin_type, true);
_loramac.get_lora_time()->start(_forced_timer, _forced_period);
} else {
reset_forced_rejoin();
}
}
}
void LoRaWANStack::process_rejoin_type0()
{
if (_loramac.get_server_type() == LW1_1 ) {
//stop in case counter was exceeded
_loramac.get_lora_time()->stop(_rejoin_type0_timer);
_rejoin_type0_counter = 0;
process_rejoin(REJOIN_REQUEST_TYPE0, false);
uint32_t max_time;
uint32_t max_count;
_loramac.get_rejoin_parameters(max_time, max_count);
_loramac.get_lora_time()->start(_rejoin_type0_timer, max_time);
}
} }

View File

@ -513,8 +513,17 @@ private:
void post_process_tx_with_reception(void); void post_process_tx_with_reception(void);
void post_process_tx_no_reception(void); void post_process_tx_no_reception(void);
void process_rejoin(join_req_type_t rejoin_type, bool is_forced);
void reset_forced_rejoin();
void forced_timer_expiry();
void process_rejoin_type0();
private: private:
LoRaMac _loramac; LoRaMac _loramac;
LoRaWANTimeHandler _lora_time;
radio_events_t radio_events; radio_events_t radio_events;
device_states_t _device_current_state; device_states_t _device_current_state;
lorawan_app_callbacks_t _callbacks; lorawan_app_callbacks_t _callbacks;
@ -539,6 +548,17 @@ private:
uint8_t _rx_payload[LORAMAC_PHY_MAXPAYLOAD]; uint8_t _rx_payload[LORAMAC_PHY_MAXPAYLOAD];
events::EventQueue *_queue; events::EventQueue *_queue;
lorawan_time_t _tx_timestamp; lorawan_time_t _tx_timestamp;
uint32_t _rejoin_type1_send_period;
uint32_t _rejoin_type1_stamp;
timer_event_t _rejoin_type0_timer;
uint32_t _rejoin_type0_counter;
uint8_t _forced_datarate;
uint32_t _forced_period;
uint8_t _forced_retry_count;
join_req_type_t _forced_rejoin_type;
uint8_t _forced_counter;
timer_event_t _forced_timer;
}; };
#endif /* LORAWANSTACK_H_ */ #endif /* LORAWANSTACK_H_ */

View File

@ -66,6 +66,16 @@ using namespace mbed;
*/ */
#define DOWN_LINK 1 #define DOWN_LINK 1
static void memcpy_convert_endianess(uint8_t *dst,
const uint8_t *src,
uint16_t size)
{
dst = dst + (size - 1);
while (size--) {
*dst-- = *src++;
}
}
LoRaMac::LoRaMac() LoRaMac::LoRaMac()
: _lora_time(), : _lora_time(),
_lora_phy(NULL), _lora_phy(NULL),
@ -86,6 +96,8 @@ LoRaMac::LoRaMac()
_prev_qos_level(LORAWAN_DEFAULT_QOS), _prev_qos_level(LORAWAN_DEFAULT_QOS),
_demod_ongoing(false) _demod_ongoing(false)
{ {
_params.rejoin_forced = false;
_params.forced_datarate = DR_0;
_params.is_rx_window_enabled = true; _params.is_rx_window_enabled = true;
_params.max_ack_timeout_retries = 1; _params.max_ack_timeout_retries = 1;
_params.ack_timeout_retry_counter = 1; _params.ack_timeout_retry_counter = 1;
@ -118,11 +130,6 @@ const loramac_mcps_indication_t *LoRaMac::get_mcps_indication() const
return &_mcps_indication; return &_mcps_indication;
} }
const loramac_mlme_confirm_t *LoRaMac::get_mlme_confirmation() const
{
return &_mlme_confirmation;
}
const loramac_mlme_indication_t *LoRaMac::get_mlme_indication() const const loramac_mlme_indication_t *LoRaMac::get_mlme_indication() const
{ {
return &_mlme_indication; return &_mlme_indication;
@ -184,18 +191,7 @@ loramac_event_info_status_t LoRaMac::handle_join_accept_frame(const uint8_t *pay
uint32_t mic_rx = 0; uint32_t mic_rx = 0;
server_type_t stype = LW1_0_2; server_type_t stype = LW1_0_2;
//Store server type to local so that invalid join accept of rejoin request won't affect the orig. type.
if ( (((_params.rx_buffer[11] >> 7) & 0x01) == 1) && MBED_CONF_LORA_VERSION == LORAWAN_VERSION_1_1) {
stype = LW1_1;
} else {
stype = LW1_0_2;
//Server does not support LW 1.1 so we need to unset JS keys
memcpy(_params.keys.js_intkey, _params.keys.nwk_key, sizeof(_params.keys.nwk_skey));
memcpy(_params.keys.js_enckey, _params.keys.nwk_key, sizeof(_params.keys.nwk_skey));
}
uint8_t *decrypt_key = NULL; uint8_t *decrypt_key = NULL;
uint8_t *mic_key = _params.keys.js_intkey; //in case of LW1.0.2 js_intkey == nwk_key == app_key
if (_params.join_request_type == JOIN_REQUEST) { if (_params.join_request_type == JOIN_REQUEST) {
decrypt_key = _params.keys.nwk_key; decrypt_key = _params.keys.nwk_key;
@ -203,6 +199,13 @@ loramac_event_info_status_t LoRaMac::handle_join_accept_frame(const uint8_t *pay
decrypt_key = _params.keys.js_enckey; decrypt_key = _params.keys.js_enckey;
} }
if (0 != _lora_crypto.decrypt_join_frame(payload + 1, size - 1,
decrypt_key, APPKEY_KEY_LENGTH,
_params.rx_buffer + 1)) {
return LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL;
}
_params.rx_buffer[0] = payload[0];
//Store server type to local so that invalid join accept of rejoin request won't affect the orig. type. //Store server type to local so that invalid join accept of rejoin request won't affect the orig. type.
if ( (((_params.rx_buffer[11] >> 7) & 0x01) == 1) && MBED_CONF_LORA_VERSION == LORAWAN_VERSION_1_1) { if ( (((_params.rx_buffer[11] >> 7) & 0x01) == 1) && MBED_CONF_LORA_VERSION == LORAWAN_VERSION_1_1) {
stype = LW1_1; stype = LW1_1;
@ -213,18 +216,14 @@ loramac_event_info_status_t LoRaMac::handle_join_accept_frame(const uint8_t *pay
memcpy(_params.keys.js_enckey, _params.keys.nwk_key, sizeof(_params.keys.nwk_skey)); memcpy(_params.keys.js_enckey, _params.keys.nwk_key, sizeof(_params.keys.nwk_skey));
} }
if (0 != _lora_crypto.decrypt_join_frame(payload + 1, size - 1,
decrypt_key, APPKEY_KEY_LENGTH,
_params.rx_buffer + 1)) {
return LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL;
}
uint8_t payload_start = 1; uint8_t payload_start = 1;
uint8_t mic_start = 0; uint8_t mic_start = 0;
uint8_t args_size = 0; uint8_t args_size = 0;
uint8_t args[16]; uint8_t args[16];
uint8_t *mic_key = _params.keys.js_intkey; //in case of LW1.0.2 js_intkey == nwk_key == app_key
if (stype == LW1_0_2) { if (stype == LW1_0_2) {
_params.rx_buffer[0] = payload[0];
mic_start = size - LORAMAC_MFR_LEN; mic_start = size - LORAMAC_MFR_LEN;
memcpy(args, _params.rx_buffer + 1, 6); memcpy(args, _params.rx_buffer + 1, 6);
@ -232,16 +231,20 @@ loramac_event_info_status_t LoRaMac::handle_join_accept_frame(const uint8_t *pay
args_size = 8; args_size = 8;
} else { } else {
//MIC calculation needs more params, so we move the payload a bit //MIC calculation needs more params, so we move the payload a bit
_params.rx_buffer[0] = (uint8_t)_params.join_request_type; memmove(_params.rx_buffer + 11, _params.rx_buffer, size);
memcpy(_params.rx_buffer + 11, _params.rx_buffer, size - LORAMAC_MFR_LEN); _params.rx_buffer[0] = _params.join_request_type; // JoinReqType
memcpy(_params.rx_buffer + 1, _params.keys.app_eui, 8); memcpy_convert_endianess(_params.rx_buffer + 1, _params.keys.app_eui, 8); // JoinEUI
memcpy(_params.rx_buffer + 9, (uint8_t *) &_params.dev_nonce, 2); _params.rx_buffer[9] = _params.dev_nonce & 0xFF; // DevNonce
mic_start = size - LORAMAC_MFR_LEN + 11; _params.rx_buffer[10] = (_params.dev_nonce >> 8) & 0xFF;
size += 11;
mic_start = size - LORAMAC_MFR_LEN;
payload_start += 11; payload_start += 11;
memcpy(args, _params.rx_buffer + payload_start, 3); memcpy(args, _params.rx_buffer + payload_start, 3);
memcpy(args + 3, _params.keys.app_eui, 8); memcpy_convert_endianess(args + 3, _params.keys.app_eui, 8);
memcpy(args + 3 + 8, (uint8_t *) &_params.dev_nonce, 2); args[3+8] = _params.dev_nonce & 0xFF;
args[3+9] = (_params.dev_nonce >> 8) & 0xFF;
args_size = 13; args_size = 13;
} }
@ -743,7 +746,6 @@ void LoRaMac::on_radio_tx_done(lorawan_time_t timestamp)
} }
} else { } else {
_mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_OK; _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_OK;
_mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT;
} }
_params.last_channel_idx = _params.channel; _params.last_channel_idx = _params.channel;
@ -826,7 +828,6 @@ void LoRaMac::on_radio_tx_timeout(void)
} }
_mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
_mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
_mac_commands.clear_command_buffer(); _mac_commands.clear_command_buffer();
@ -849,14 +850,8 @@ void LoRaMac::on_radio_rx_timeout(bool is_timeout)
if (_params.rx_slot == RX_SLOT_WIN_1) { if (_params.rx_slot == RX_SLOT_WIN_1) {
if (_params.is_node_ack_requested == true) { if (_params.is_node_ack_requested == true) {
_mcps_confirmation.status = is_timeout ? _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_RX1_ERROR;
LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT :
LORAMAC_EVENT_INFO_STATUS_RX1_ERROR;
} }
_mlme_confirmation.status = is_timeout ?
LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT :
LORAMAC_EVENT_INFO_STATUS_RX1_ERROR;
if (_device_class != CLASS_C) { if (_device_class != CLASS_C) {
if (_lora_time.get_elapsed_time(_params.timers.aggregated_last_tx_time) >= _params.rx_window2_delay) { if (_lora_time.get_elapsed_time(_params.timers.aggregated_last_tx_time) >= _params.rx_window2_delay) {
_lora_time.stop(_params.timers.rx_window2_timer); _lora_time.stop(_params.timers.rx_window2_timer);
@ -864,14 +859,8 @@ void LoRaMac::on_radio_rx_timeout(bool is_timeout)
} }
} else { } else {
if (_params.is_node_ack_requested == true) { if (_params.is_node_ack_requested == true) {
_mcps_confirmation.status = is_timeout ? _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR;
LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT :
LORAMAC_EVENT_INFO_STATUS_RX2_ERROR;
} }
_mlme_confirmation.status = is_timeout ?
LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT :
LORAMAC_EVENT_INFO_STATUS_RX2_ERROR;
} }
} }
@ -1574,7 +1563,10 @@ lorawan_status_t LoRaMac::prepare_join(const lorawan_connect_t *params, bool is_
_params.keys.nwk_key = params->connection_u.otaa.app_key; _params.keys.nwk_key = params->connection_u.otaa.app_key;
} }
if (0 != _lora_crypto.compute_join_server_keys(_params.keys.nwk_key, APPKEY_KEY_LENGTH, _params.keys.dev_eui, uint8_t converted_eui[8];
memcpy_convert_endianess(converted_eui, _params.keys.dev_eui, 8);
if (0 != _lora_crypto.compute_join_server_keys(_params.keys.nwk_key, APPKEY_KEY_LENGTH, converted_eui,
_params.keys.js_intkey, _params.keys.js_enckey)) { _params.keys.js_intkey, _params.keys.js_enckey)) {
return LORAWAN_STATUS_CRYPTO_FAIL; return LORAWAN_STATUS_CRYPTO_FAIL;
} }
@ -1649,7 +1641,10 @@ lorawan_status_t LoRaMac::prepare_join(const lorawan_connect_t *params, bool is_
_params.keys.nwk_key = _params.keys.app_key; _params.keys.nwk_key = _params.keys.app_key;
} }
if (0 != _lora_crypto.compute_join_server_keys(_params.keys.nwk_key, APPKEY_KEY_LENGTH, _params.keys.dev_eui, uint8_t converted_eui[8];
memcpy_convert_endianess(converted_eui, _params.keys.dev_eui, 8);
if (0 != _lora_crypto.compute_join_server_keys(_params.keys.nwk_key, APPKEY_KEY_LENGTH, converted_eui,
_params.keys.js_intkey, _params.keys.js_enckey)) { _params.keys.js_intkey, _params.keys.js_enckey)) {
return LORAWAN_STATUS_CRYPTO_FAIL; return LORAWAN_STATUS_CRYPTO_FAIL;
} }
@ -1700,23 +1695,15 @@ lorawan_status_t LoRaMac::join(bool is_otaa)
return send_join_request(); return send_join_request();
} }
lorawan_status_t LoRaMac::rejoin(join_req_type_t rejoin_type) lorawan_status_t LoRaMac::rejoin(join_req_type_t rejoin_type, bool is_forced, uint8_t datarate)
{ {
_params.join_request_type = rejoin_type; _params.join_request_type = rejoin_type;
_params.rejoin_forced = is_forced;
_params.forced_datarate = datarate;
return send_join_request(); return send_join_request();
} }
static void memcpy_convert_endianess(uint8_t *dst,
const uint8_t *src,
uint16_t size)
{
dst = dst + (size - 1);
while (size--) {
*dst-- = *src++;
}
}
lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr, lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr,
loramac_frame_ctrl_t *fctrl, loramac_frame_ctrl_t *fctrl,
const uint8_t fport, const uint8_t fport,
@ -1970,7 +1957,11 @@ lorawan_status_t LoRaMac::send_frame_on_channel(uint8_t channel)
int8_t tx_power = 0; int8_t tx_power = 0;
tx_config.channel = channel; tx_config.channel = channel;
tx_config.datarate = _params.sys_params.channel_data_rate; if (_params.rejoin_forced) {
tx_config.datarate = _params.forced_datarate;
} else {
tx_config.datarate = _params.sys_params.channel_data_rate;
}
tx_config.tx_power = _params.sys_params.channel_tx_power; tx_config.tx_power = _params.sys_params.channel_tx_power;
tx_config.max_eirp = _params.sys_params.max_eirp; tx_config.max_eirp = _params.sys_params.max_eirp;
tx_config.antenna_gain = _params.sys_params.antenna_gain; tx_config.antenna_gain = _params.sys_params.antenna_gain;
@ -1978,8 +1969,6 @@ lorawan_status_t LoRaMac::send_frame_on_channel(uint8_t channel)
_lora_phy->tx_config(&tx_config, &tx_power, &_params.timers.tx_toa); _lora_phy->tx_config(&tx_config, &tx_power, &_params.timers.tx_toa);
_mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR;
_mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR; _mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR;
_mcps_confirmation.data_rate = _params.sys_params.channel_data_rate; _mcps_confirmation.data_rate = _params.sys_params.channel_data_rate;
_mcps_confirmation.tx_power = tx_power; _mcps_confirmation.tx_power = tx_power;
@ -2008,6 +1997,11 @@ void LoRaMac::reset_mcps_indication()
_mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ERROR; _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ERROR;
} }
LoRaWANTimeHandler *LoRaMac::get_lora_time()
{
return &_lora_time;
}
lorawan_status_t LoRaMac::initialize(EventQueue *queue, lorawan_status_t LoRaMac::initialize(EventQueue *queue,
mbed::Callback<void(void)>scheduling_failure_handler) mbed::Callback<void(void)>scheduling_failure_handler)
{ {
@ -2233,3 +2227,9 @@ uint8_t LoRaMac::get_current_adr_ack_limit()
{ {
return _lora_phy->get_adr_ack_limit(); return _lora_phy->get_adr_ack_limit();
} }
void LoRaMac::get_rejoin_parameters(uint32_t& max_time, uint32_t& max_count)
{
max_time = _lora_phy->get_rejoin_max_time();
max_count = _lora_phy->get_rejoin_max_count();
}

View File

@ -196,6 +196,13 @@ public:
*/ */
lorawan_status_t multicast_channel_unlink(multicast_params_t *channel_param); lorawan_status_t multicast_channel_unlink(multicast_params_t *channel_param);
/**
* @brief get_rejoin_parameters Gets current rejoin parameters
* @param max_time Current rejoin max time
* @param max_count Current rejoin max count
*/
void get_rejoin_parameters(uint32_t& max_time, uint32_t& max_count);
/** Binds phy layer to MAC. /** Binds phy layer to MAC.
* *
* @param phy LoRaPHY object * @param phy LoRaPHY object
@ -353,9 +360,11 @@ public:
/** /**
* @brief rejoin Rejoins the network * @brief rejoin Rejoins the network
* @param rejoin_type Rejoin type indicates the rejoin message payload * @param rejoin_type Rejoin type indicates the rejoin message payload
* @param is_forced Indicates if the function was called because of ForceRejoinReq
* @param datarate In case of forced rejoin, datarate to be used for Rejoin request
* @return LORAWAN_STATUS_OK or a negative error code on failure. * @return LORAWAN_STATUS_OK or a negative error code on failure.
*/ */
lorawan_status_t rejoin(join_req_type_t rejoin_type); lorawan_status_t rejoin(join_req_type_t rejoin_type, bool is_forced = false, uint8_t datarate = DR_0);
/** /**
* MAC operations upon successful transmission * MAC operations upon successful transmission
@ -402,7 +411,6 @@ public:
*/ */
const loramac_mcps_confirm_t *get_mcps_confirmation() const; const loramac_mcps_confirm_t *get_mcps_confirmation() const;
const loramac_mcps_indication_t *get_mcps_indication() const; const loramac_mcps_indication_t *get_mcps_indication() const;
const loramac_mlme_confirm_t *get_mlme_confirmation() const;
const loramac_mlme_indication_t *get_mlme_indication() const; const loramac_mlme_indication_t *get_mlme_indication() const;
/** /**
@ -470,6 +478,8 @@ public:
void unlock(void) { } void unlock(void) { }
#endif #endif
LoRaWANTimeHandler *get_lora_time();
private: private:
/** /**
* @brief Queries the LoRaMAC the maximum possible FRMPayload size to send. * @brief Queries the LoRaMAC the maximum possible FRMPayload size to send.
@ -626,7 +636,6 @@ private:
* Resets MAC primitive blocks * Resets MAC primitive blocks
*/ */
void reset_mcps_confirmation(void); void reset_mcps_confirmation(void);
void reset_mlme_confirmation(void);
void reset_mcps_indication(void); void reset_mcps_indication(void);
/** /**

View File

@ -143,6 +143,7 @@ lorawan_status_t LoRaMacCommand::process_mac_commands(const uint8_t *payload, ui
switch (payload[mac_index++]) { switch (payload[mac_index++]) {
case SRV_MAC_RESET_CONF: { case SRV_MAC_RESET_CONF: {
loramac_mlme_confirm_t mlme_conf; loramac_mlme_confirm_t mlme_conf;
mlme_conf.type = MLME_RESET;
mlme_conf.status = LORAMAC_EVENT_INFO_STATUS_OK; mlme_conf.status = LORAMAC_EVENT_INFO_STATUS_OK;
mlme_conf.version = payload[mac_index++] & 0x0F; mlme_conf.version = payload[mac_index++] & 0x0F;
confirm_handler(mlme_conf); confirm_handler(mlme_conf);
@ -150,6 +151,7 @@ lorawan_status_t LoRaMacCommand::process_mac_commands(const uint8_t *payload, ui
break; break;
case SRV_MAC_LINK_CHECK_ANS: { case SRV_MAC_LINK_CHECK_ANS: {
loramac_mlme_confirm_t mlme_conf; loramac_mlme_confirm_t mlme_conf;
mlme_conf.type = MLME_LINK_CHECK;
mlme_conf.status = LORAMAC_EVENT_INFO_STATUS_OK; mlme_conf.status = LORAMAC_EVENT_INFO_STATUS_OK;
mlme_conf.demod_margin = payload[mac_index++]; mlme_conf.demod_margin = payload[mac_index++];
mlme_conf.nb_gateways = payload[mac_index++]; mlme_conf.nb_gateways = payload[mac_index++];
@ -305,6 +307,7 @@ lorawan_status_t LoRaMacCommand::process_mac_commands(const uint8_t *payload, ui
break; break;
case SRV_MAC_REKEY_CONF: { case SRV_MAC_REKEY_CONF: {
loramac_mlme_confirm_t mlme_conf; loramac_mlme_confirm_t mlme_conf;
mlme_conf.type = MLME_REKEY;
mlme_conf.status = LORAMAC_EVENT_INFO_STATUS_OK; mlme_conf.status = LORAMAC_EVENT_INFO_STATUS_OK;
mlme_conf.version = payload[mac_index++] & 0x0F; mlme_conf.version = payload[mac_index++] & 0x0F;
confirm_handler(mlme_conf); confirm_handler(mlme_conf);

View File

@ -39,6 +39,9 @@ SPDX-License-Identifier: BSD-3-Clause
#define GPS_EPOCH_DIFF_WITH_UTC 315964800 #define GPS_EPOCH_DIFF_WITH_UTC 315964800
#define CHANNELS_IN_MASK 16 #define CHANNELS_IN_MASK 16
#define DEVICE_DOES_NOT_SUPPORT_TIME 0
#define DEVICE_SUPPORTS_TIME 1
LoRaPHY::LoRaPHY() LoRaPHY::LoRaPHY()
: _radio(NULL), : _radio(NULL),
_lora_time(NULL), _lora_time(NULL),
@ -690,7 +693,7 @@ uint8_t LoRaPHY::update_rejoin_params(uint32_t max_time, uint32_t max_count)
//These will be taken into use at next rejoin "cycle" //These will be taken into use at next rejoin "cycle"
_rejoin_max_time = max_time; _rejoin_max_time = max_time;
_rejoin_max_count = max_count; _rejoin_max_count = max_count;
return 1; return DEVICE_SUPPORTS_TIME;
} }
void LoRaPHY::restore_default_channels() void LoRaPHY::restore_default_channels()
@ -1513,4 +1516,13 @@ uint8_t LoRaPHY::apply_DR_offset(int8_t dr, int8_t dr_offset)
return datarate; return datarate;
} }
uint32_t LoRaPHY::get_rejoin_max_time() const
{
return _rejoin_max_time;
}
uint32_t LoRaPHY::get_rejoin_max_count() const
{
return _rejoin_max_count;
}

View File

@ -604,6 +604,18 @@ public: //Verifiers
*/ */
void set_adr_ack_delay(const uint16_t& value); void set_adr_ack_delay(const uint16_t& value);
/**
* @brief getRejoin_max_time Getter for current rejoin max time
* @return Current rejoin max time in seconds
*/
uint32_t get_rejoin_max_time() const;
/**
* @brief get_rejoin_max_count Getter for current rejoin max count
* @return Current rejoin max count
*/
uint32_t get_rejoin_max_count() const;
protected: protected:
LoRaPHY(); LoRaPHY();

View File

@ -116,6 +116,10 @@
"rejoin-default-max-count": { "rejoin-default-max-count": {
"help": "LW1.1 only! Maximum amount of messages which can be sent between Rejoin requests.", "help": "LW1.1 only! Maximum amount of messages which can be sent between Rejoin requests.",
"value": 1000 "value": 1000
},
"rejoin-type1-send-period": {
"help": "Rejoin type 1 sending period. NOTE: Rejoin message will be sent when this period has expired. Default is 1 week",
"value": 604800
} }
} }
} }

View File

@ -553,14 +553,6 @@ typedef enum {
* A TX timeout occurred. * A TX timeout occurred.
*/ */
LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT, LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT,
/*!
* An RX timeout occurred on receive window 1.
*/
LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT,
/*!
* An RX timeout occurred on receive window 2.
*/
LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT,
/*! /*!
* An RX error occurred on receive window 1. * An RX error occurred on receive window 1.
*/ */
@ -1458,6 +1450,15 @@ typedef struct {
*/ */
multicast_params_t *multicast_channels; multicast_params_t *multicast_channels;
/*!
* \brief rejoin_forced Boolean indicating if rejoin is forced. See ForceRejoinReq LW 1.1 spec ch 5.13
*/
bool rejoin_forced;
/*!
* \brief forced_datarate See ForceRejoinReq LW 1.1 spec ch 5.13
*/
uint8_t forced_datarate;
} loramac_protocol_params; } loramac_protocol_params;
#endif /* LORAWAN_SYSTEM_LORAWAN_DATA_STRUCTURES_H_ */ #endif /* LORAWAN_SYSTEM_LORAWAN_DATA_STRUCTURES_H_ */