LoRa: LoRaPHY dependency removed from LoRaMacStack

- This is internal change, no functionality has been changed
- LoRaWanInterface cleaned up and code moved to LoRaMacStack
- Compliance code in LoRaMacStack moved to EOF
- Green tea tests have been run manually
- Doxygen updated accordingly

LoRA: reorder class members
pull/6411/head
Antti Kauppila 2018-03-15 10:43:31 +02:00
parent fe225a8430
commit b63c98e103
5 changed files with 476 additions and 520 deletions

View File

@ -98,7 +98,6 @@ LoRaWANStack::LoRaWANStack()
#endif
memset(&_lw_session, 0, sizeof(_lw_session));
memset(&_tx_msg, 0, sizeof(_tx_msg));
memset(&_rx_msg, 0, sizeof(_rx_msg));
LoRaMacPrimitives.mcps_confirm = callback(this, &LoRaWANStack::mcps_confirm_handler);
@ -122,12 +121,7 @@ LoRaWANStack& LoRaWANStack::get_lorawan_stack()
void LoRaWANStack::bind_radio_driver(LoRaRadio& radio)
{
//Move these to LoRaMAC class
radio_events_t *events = _loramac.get_phy_event_handlers();
_lora_phy.set_radio_instance(radio);
radio.lock();
radio.init_radio(events);
radio.unlock();
_loramac.bind_radio_driver(radio);
}
lorawan_status_t LoRaWANStack::connect()
@ -209,7 +203,7 @@ lorawan_status_t LoRaWANStack::initialize_mac_layer(EventQueue *queue)
_compliance_test.app_data_buffer = compliance_test_buffer;
#endif
_loramac.initialize(&LoRaMacPrimitives, &_lora_phy, queue);
_loramac.initialize(&LoRaMacPrimitives, queue);
// Reset counters to zero. Will change in future with 1.1 support.
_lw_session.downlink_counter = 0;
@ -218,81 +212,6 @@ lorawan_status_t LoRaWANStack::initialize_mac_layer(EventQueue *queue)
return lora_state_machine(DEVICE_STATE_INIT);
}
uint16_t LoRaWANStack::check_possible_tx_size(uint16_t size)
{
loramac_tx_info_t tx_info;
if (_loramac.query_tx_possible(size, &tx_info) == LORAWAN_STATUS_LENGTH_ERROR) {
// Cannot transmit this much. Return how much data can be sent
// at the moment
return tx_info.max_possible_payload_size;
}
return tx_info.current_payload_size;
}
/** Hands over the frame to MAC layer
*
* \return returns the state of the LoRa MAC
*/
lorawan_status_t LoRaWANStack::send_frame_to_mac()
{
loramac_mcps_req_t mcps_req;
lorawan_status_t status;
loramac_mib_req_confirm_t mib_get_params;
mcps_req.type = _tx_msg.type;
if (MCPS_UNCONFIRMED == mcps_req.type) {
mcps_req.f_buffer = _tx_msg.f_buffer;
mcps_req.f_buffer_size = _tx_msg.f_buffer_size;
mcps_req.fport = _tx_msg.fport;
mcps_req.nb_trials = 1;
mib_get_params.type = MIB_CHANNELS_DATARATE;
if(mib_get_request(&mib_get_params) != LORAWAN_STATUS_OK) {
tr_debug("Couldn't get MIB parameters: Using default data rate");
mcps_req.data_rate = _lora_phy.get_default_tx_datarate();
} else {
mcps_req.data_rate = mib_get_params.param.channel_data_rate;
}
} else if (mcps_req.type == MCPS_CONFIRMED) {
mcps_req.f_buffer = _tx_msg.f_buffer;
mcps_req.f_buffer_size = _tx_msg.f_buffer_size;
mcps_req.fport = _tx_msg.fport;
mcps_req.nb_trials = _tx_msg.nb_trials;
mib_get_params.type = MIB_CHANNELS_DATARATE;
if(mib_get_request(&mib_get_params) != LORAWAN_STATUS_OK) {
tr_debug("Couldn't get MIB parameters: Using default data rate");
mcps_req.data_rate = _lora_phy.get_default_tx_datarate();
} else {
mcps_req.data_rate = mib_get_params.param.channel_data_rate;
}
} else if ( mcps_req.type == MCPS_PROPRIETARY) {
mcps_req.f_buffer = _tx_msg.f_buffer;
mcps_req.f_buffer_size = _tx_msg.f_buffer_size;
mcps_req.fport = 0;
mcps_req.nb_trials = 1;
mib_get_params.type = MIB_CHANNELS_DATARATE;
if(mib_get_request(&mib_get_params) != LORAWAN_STATUS_OK) {
tr_debug("Couldn't get MIB parameters: Using default data rate");
mcps_req.data_rate = _lora_phy.get_default_tx_datarate();
} else {
mcps_req.data_rate = mib_get_params.param.channel_data_rate;
}
} else {
return LORAWAN_STATUS_SERVICE_UNKNOWN;
}
status = mcps_request_handler(&mcps_req);
return status;
}
lorawan_status_t LoRaWANStack::set_confirmed_msg_retry(uint8_t count)
{
if (count >= MAX_CONFIRMED_MSG_RETRIES) {
@ -396,6 +315,8 @@ lorawan_status_t LoRaWANStack::enable_adaptive_datarate(bool adr_enabled)
return LORAWAN_STATUS_NOT_INITIALIZED;
}
//return _loramac.enable_adaptive_datarate(adr_enabled);
loramac_mib_req_confirm_t adr_mib_params;
adr_mib_params.type = MIB_ADR;
@ -489,11 +410,14 @@ lorawan_status_t LoRaWANStack::activation_by_personalization(const lorawan_conne
}
int16_t LoRaWANStack::handle_tx(uint8_t port, const uint8_t* data,
uint16_t length, uint8_t flags)
uint16_t length, uint8_t flags, bool null_allowed)
{
if (!null_allowed && !data) {
return LORAWAN_STATUS_PARAMETER_INVALID;
}
// add a link check request with normal data, until the application
// explicitly removes it.
if (_link_check_requested) {
// add a link check request with normal data, until the application
// explicitly removes it.
set_link_check_request();
}
@ -501,20 +425,17 @@ int16_t LoRaWANStack::handle_tx(uint8_t port, const uint8_t* data,
return LORAWAN_STATUS_NO_ACTIVE_SESSIONS;
}
if (_tx_msg.tx_ongoing) {
if(_loramac.tx_ongoing()) {
return LORAWAN_STATUS_WOULD_BLOCK;
}
if (!data && length > 0) {
return LORAWAN_STATUS_PARAMETER_INVALID;
}
#if defined(LORAWAN_COMPLIANCE_TEST)
if (_compliance_test.running) {
return LORAWAN_STATUS_COMPLIANCE_TEST_ON;
}
#endif
//TODO: Stack MUST know joining status!!!!
loramac_mib_req_confirm_t mib_req;
lorawan_status_t status;
mib_req.type = MIB_NETWORK_JOINED;
@ -539,62 +460,14 @@ int16_t LoRaWANStack::handle_tx(uint8_t port, const uint8_t* data,
return LORAWAN_STATUS_PARAMETER_INVALID;
}
_tx_msg.port = port;
int16_t len = _loramac.prepare_ongoing_tx(port, data, length, flags, _num_retry);
uint16_t max_possible_size = check_possible_tx_size(length);
if (max_possible_size > MBED_CONF_LORA_TX_MAX_SIZE) {
// LORAWAN_APP_DATA_MAX_SIZE should at least be
// either equal to or bigger than maximum possible
// tx size because our tx message buffer takes its
// length from that macro. Force maximum possible tx unit
// to be equal to the buffer size user chose.
max_possible_size = MBED_CONF_LORA_TX_MAX_SIZE;
}
if (max_possible_size < length) {
tr_info("Cannot transmit %d bytes. Possible TX Size is %d bytes",
length, max_possible_size);
_tx_msg.pending_size = length - max_possible_size;
_tx_msg.f_buffer_size = max_possible_size;
// copy user buffer upto the max_possible_size
memcpy(_tx_msg.f_buffer, data, _tx_msg.f_buffer_size);
} else {
// Whole message can be sent at one time
_tx_msg.f_buffer_size = length;
_tx_msg.pending_size = 0;
// copy user buffer upto the max_possible_size
if (length > 0) {
memcpy(_tx_msg.f_buffer, data, length);
}
}
// Handles all unconfirmed messages, including proprietary and multicast
if ((flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_FLAG
|| (flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_MULTICAST
|| (flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_PROPRIETARY) {
_tx_msg.type = MCPS_UNCONFIRMED;
_tx_msg.fport = _app_port;
}
// Handles all confirmed messages, including proprietary and multicast
if ((flags & MSG_FLAG_MASK) == MSG_CONFIRMED_FLAG
|| (flags & MSG_FLAG_MASK) == MSG_CONFIRMED_MULTICAST
|| (flags & MSG_FLAG_MASK) == MSG_CONFIRMED_PROPRIETARY) {
_tx_msg.type = MCPS_CONFIRMED;
_tx_msg.fport = _app_port;
_tx_msg.nb_trials = _num_retry;
}
tr_info("RTS = %u bytes, PEND = %u", _tx_msg.f_buffer_size, _tx_msg.pending_size);
status = lora_state_machine(DEVICE_STATE_SEND);
// send user the length of data which is scheduled now.
// user should take care of the pending data.
return (status == LORAWAN_STATUS_OK) ? _tx_msg.f_buffer_size : (int16_t) status;
return (status == LORAWAN_STATUS_OK) ? len : (int16_t) status;
}
int16_t LoRaWANStack::handle_rx(const uint8_t port, uint8_t* data,
@ -766,9 +639,7 @@ void LoRaWANStack::mcps_confirm_handler(loramac_mcps_confirm_t *mcps_confirm)
// Couldn't schedule packet, ack not recieved in CONFIRMED case
// or some other error happened. Discard buffer, unset the tx-ongoing
// flag and let the application know
_tx_msg.tx_ongoing = false;
memset(_tx_msg.f_buffer, 0, MBED_CONF_LORA_TX_MAX_SIZE);
_tx_msg.f_buffer_size = MBED_CONF_LORA_TX_MAX_SIZE;
_loramac.reset_ongoing_tx();
tr_error("mcps_confirm_handler: Error code = %d", mcps_confirm->status);
@ -808,7 +679,7 @@ void LoRaWANStack::mcps_confirm_handler(loramac_mcps_confirm_t *mcps_confirm)
// Tell the application about successful transmission and store
// data rate plus frame counter.
_lw_session.uplink_counter = mcps_confirm->ul_frame_counter;
_tx_msg.tx_ongoing = false;
_loramac.set_tx_ongoing(false);
if (_callbacks.events) {
const int ret = _queue->call(_callbacks.events, TX_DONE);
MBED_ASSERT(ret != 0);
@ -909,7 +780,7 @@ void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t *mcps_indic
// that we could retry a certain number of times if the uplink
// failed for some reason
if (mcps_indication->fpending_status && mib_req.param.dev_class != CLASS_C) {
handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG);
handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG, true);
}
// Class C and node received a confirmed message so we need to
@ -918,7 +789,7 @@ void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t *mcps_indic
// but version 1.1.0 says that network SHALL not send any new
// confirmed messages until ack has been sent
if (mib_req.param.dev_class == CLASS_C && mcps_indication->type == MCPS_CONFIRMED) {
handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG);
handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG, true);
}
} else {
// Invalid port, ports 0, 224 and 225-255 are reserved.
@ -928,144 +799,6 @@ void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t *mcps_indic
}
}
#if defined(LORAWAN_COMPLIANCE_TEST)
/** Compliance testing function
*
* \param mcps_indication Pointer to the indication structure,
* containing indication attributes.
*/
void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t *mcps_indication)
{
if (_compliance_test.running == false) {
// Check compliance test enable command (i)
if ((mcps_indication->buffer_size == 4) &&
(mcps_indication->buffer[0] == 0x01) &&
(mcps_indication->buffer[1] == 0x01) &&
(mcps_indication->buffer[2] == 0x01) &&
(mcps_indication->buffer[3] == 0x01)) {
_compliance_test.is_tx_confirmed = false;
_compliance_test.app_port = 224;
_compliance_test.app_data_size = 2;
_compliance_test.downlink_counter = 0;
_compliance_test.link_check = false;
_compliance_test.demod_margin = 0;
_compliance_test.nb_gateways = 0;
_compliance_test.running = true;
_compliance_test.state = 1;
loramac_mib_req_confirm_t mib_req;
mib_req.type = MIB_ADR;
mib_req.param.is_adr_enable = true;
mib_set_request(&mib_req);
#if MBED_CONF_LORA_PHY == 0
_loramac.LoRaMacTestSetDutyCycleOn(false);
#endif
//5000ms
_loramac.LoRaMacSetTxTimer(5000);
//TODO: Should we call lora_state_machine here instead of just setting the state?
_device_current_state = DEVICE_STATE_COMPLIANCE_TEST;
// lora_state_machine(DEVICE_STATE_COMPLIANCE_TEST);
tr_debug("Compliance test activated.");
}
} else {
_compliance_test.state = mcps_indication->buffer[0];
switch (_compliance_test.state) {
case 0: // Check compliance test disable command (ii)
_compliance_test.is_tx_confirmed = true;
_compliance_test.app_port = MBED_CONF_LORA_APP_PORT;
_compliance_test.app_data_size = LORAWAN_COMPLIANCE_TEST_DATA_SIZE;
_compliance_test.downlink_counter = 0;
_compliance_test.running = false;
loramac_mib_req_confirm_t mib_req;
mib_req.type = MIB_ADR;
mib_req.param.is_adr_enable = MBED_CONF_LORA_ADR_ON;
mib_set_request(&mib_req);
#if MBED_CONF_LORA_PHY == 0
_loramac.LoRaMacTestSetDutyCycleOn(MBED_CONF_LORA_DUTY_CYCLE_ON);
#endif
// Go to idle state after compliance test mode.
tr_debug("Compliance test disabled.");
_loramac.LoRaMacStopTxTimer();
// Clear any compliance test message stuff before going back to normal operation.
memset(&_tx_msg, 0, sizeof(_tx_msg));
lora_state_machine(DEVICE_STATE_IDLE);
break;
case 1: // (iii, iv)
_compliance_test.app_data_size = 2;
break;
case 2: // Enable confirmed messages (v)
_compliance_test.is_tx_confirmed = true;
_compliance_test.state = 1;
break;
case 3: // Disable confirmed messages (vi)
_compliance_test.is_tx_confirmed = false;
_compliance_test.state = 1;
break;
case 4: // (vii)
_compliance_test.app_data_size = mcps_indication->buffer_size;
_compliance_test.app_data_buffer[0] = 4;
for(uint8_t i = 1; i < MIN(_compliance_test.app_data_size, LORAMAC_PHY_MAXPAYLOAD); ++i) {
_compliance_test.app_data_buffer[i] = mcps_indication->buffer[i] + 1;
}
send_compliance_test_frame_to_mac();
break;
case 5: // (viii)
loramac_mlme_req_t mlme_req;
mlme_req.type = MLME_LINK_CHECK;
_loramac.mlme_request(&mlme_req);
break;
case 6: // (ix)
loramac_mlme_req_t mlme_request;
loramac_mib_req_confirm_t mib_request;
// Disable TestMode and revert back to normal operation
_compliance_test.is_tx_confirmed = true;
_compliance_test.app_port = MBED_CONF_LORA_APP_PORT;
_compliance_test.app_data_size = LORAWAN_COMPLIANCE_TEST_DATA_SIZE;
_compliance_test.downlink_counter = 0;
_compliance_test.running = false;
mib_request.type = MIB_ADR;
mib_request.param.is_adr_enable = MBED_CONF_LORA_ADR_ON;
mib_set_request(&mib_request);
#if MBED_CONF_LORA_PHY == 0
_loramac.LoRaMacTestSetDutyCycleOn(MBED_CONF_LORA_DUTY_CYCLE_ON);
#endif
mlme_request.type = MLME_JOIN;
mlme_request.req.join.dev_eui = _lw_session.connection.connection_u.otaa.dev_eui;
mlme_request.req.join.app_eui = _lw_session.connection.connection_u.otaa.app_eui;
mlme_request.req.join.app_key = _lw_session.connection.connection_u.otaa.app_key;
mlme_request.req.join.nb_trials = _lw_session.connection.connection_u.otaa.nb_trials;
_loramac.mlme_request(&mlme_request);
break;
case 7: // (x)
if (mcps_indication->buffer_size == 3) {
loramac_mlme_req_t mlme_req;
mlme_req.type = MLME_TXCW;
mlme_req.req.cw_tx_mode.timeout = (uint16_t)((mcps_indication->buffer[1] << 8) | mcps_indication->buffer[2]);
_loramac.mlme_request(&mlme_req);
} else if (mcps_indication->buffer_size == 7) {
loramac_mlme_req_t mlme_req;
mlme_req.type = MLME_TXCW_1;
mlme_req.req.cw_tx_mode.timeout = (uint16_t)((mcps_indication->buffer[1] << 8) | mcps_indication->buffer[2]);
mlme_req.req.cw_tx_mode.frequency = (uint32_t)((mcps_indication->buffer[3] << 16) | (mcps_indication->buffer[4] << 8)
| mcps_indication->buffer[5]) * 100;
mlme_req.req.cw_tx_mode.power = mcps_indication->buffer[6];
_loramac.mlme_request(&mlme_req);
}
_compliance_test.state = 1;
break;
}
}
}
#endif
lorawan_status_t LoRaWANStack::mib_set_request(loramac_mib_req_confirm_t *mib_set_params)
{
if (NULL == mib_set_params) {
@ -1140,10 +873,8 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state)
mib_set_request(&mib_req);
// reset buffers to original state
memset(_tx_msg.f_buffer, 0, MBED_CONF_LORA_TX_MAX_SIZE);
_tx_msg.pending_size = 0;
_tx_msg.f_buffer_size = 0;
_tx_msg.tx_ongoing = false;
_loramac.reset_ongoing_tx(true);
_rx_msg.msg.mcps_indication.buffer = NULL;
_rx_msg.receive_ready = false;
_rx_msg.prev_read_size = 0;
@ -1243,11 +974,11 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state)
break;
case DEVICE_STATE_SEND:
// If a transmission is ongoing, don't interrupt
if (_tx_msg.tx_ongoing) {
if (_loramac.tx_ongoing()) {
status = LORAWAN_STATUS_OK;
} else {
_tx_msg.tx_ongoing = true;
status = send_frame_to_mac();
_loramac.set_tx_ongoing(true);
status = _loramac.send_ongoing_tx();
switch (status) {
case LORAWAN_STATUS_OK:
@ -1300,63 +1031,53 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state)
}
#if defined(LORAWAN_COMPLIANCE_TEST)
/**
*
* Prepares the upload message to reserved ports
*
* \param port Application port
*/
void LoRaWANStack::prepare_special_tx_frame(uint8_t port)
{
if (port == 224) {
// Clear any normal message stuff before compliance test.
memset(&_tx_msg, 0, sizeof(_tx_msg));
if (_compliance_test.link_check == true) {
_compliance_test.link_check = false;
_compliance_test.state = 1;
_tx_msg.f_buffer_size = 3;
_tx_msg.f_buffer[0] = 5;
_tx_msg.f_buffer[1] = _compliance_test.demod_margin;
_tx_msg.f_buffer[2] = _compliance_test.nb_gateways;
} else {
switch (_compliance_test.state) {
case 4:
_compliance_test.state = 1;
_tx_msg.f_buffer_size = _compliance_test.app_data_size;
_tx_msg.f_buffer[0] = _compliance_test.app_data_buffer[0];
for(uint8_t i = 1; i < MIN(_compliance_test.app_data_size, MBED_CONF_LORA_TX_MAX_SIZE); ++i) {
_tx_msg.f_buffer[i] = _compliance_test.app_data_buffer[i];
}
break;
case 1:
_tx_msg.f_buffer_size = 2;
_tx_msg.f_buffer[0] = _compliance_test.downlink_counter >> 8;
_tx_msg.f_buffer[1] = _compliance_test.downlink_counter;
break;
}
}
}
}
/** Hands over the compliance test frame to MAC layer
*
* \return returns the state of the LoRa MAC
*/
lorawan_status_t LoRaWANStack::send_compliance_test_frame_to_mac()
{
loramac_mcps_req_t mcps_req;
prepare_special_tx_frame(_compliance_test.app_port);
// prepare_special_tx_frame(_compliance_test.app_port);
//TODO: What if the port is not 224 ???
if (_compliance_test.app_port == 224) {
// Clear any normal message stuff before compliance test.
memset(&mcps_req, 0, sizeof(mcps_req));
if (_compliance_test.link_check == true) {
_compliance_test.link_check = false;
_compliance_test.state = 1;
mcps_req.f_buffer_size = 3;
mcps_req.f_buffer[0] = 5;
mcps_req.f_buffer[1] = _compliance_test.demod_margin;
mcps_req.f_buffer[2] = _compliance_test.nb_gateways;
} else {
switch (_compliance_test.state) {
case 4:
_compliance_test.state = 1;
mcps_req.f_buffer_size = _compliance_test.app_data_size;
mcps_req.f_buffer[0] = _compliance_test.app_data_buffer[0];
for(uint8_t i = 1; i < MIN(_compliance_test.app_data_size, MBED_CONF_LORA_TX_MAX_SIZE); ++i) {
mcps_req.f_buffer[i] = _compliance_test.app_data_buffer[i];
}
break;
case 1:
mcps_req.f_buffer_size = 2;
mcps_req.f_buffer[0] = _compliance_test.downlink_counter >> 8;
mcps_req.f_buffer[1] = _compliance_test.downlink_counter;
break;
}
}
}
//TODO: If port is not 224, this might not work!
//Is there a test case where same _tx_msg's buffer would be used, when port is not 224???
if (!_compliance_test.is_tx_confirmed) {
mcps_req.type = MCPS_UNCONFIRMED;
mcps_req.f_buffer = _tx_msg.f_buffer;
mcps_req.f_buffer_size = _tx_msg.f_buffer_size;
// mcps_req.f_buffer = _tx_msg.f_buffer;
// mcps_req.f_buffer_size = _tx_msg.f_buffer_size;
mcps_req.fport = _compliance_test.app_port;
mcps_req.nb_trials = 1;
mcps_req.data_rate = _lora_phy.get_default_tx_datarate();
mcps_req.data_rate = _loramac.get_default_tx_datarate();
tr_info("Transmit unconfirmed compliance test frame %d bytes.", mcps_req.f_buffer_size);
@ -1365,11 +1086,11 @@ lorawan_status_t LoRaWANStack::send_compliance_test_frame_to_mac()
}
} else if (_compliance_test.is_tx_confirmed) {
mcps_req.type = MCPS_CONFIRMED;
mcps_req.f_buffer = _tx_msg.f_buffer;
mcps_req.f_buffer_size = _tx_msg.f_buffer_size;
// mcps_req.f_buffer = _tx_msg.f_buffer;
// mcps_req.f_buffer_size = _tx_msg.f_buffer_size;
mcps_req.fport = _compliance_test.app_port;
mcps_req.nb_trials = _num_retry;
mcps_req.data_rate = _lora_phy.get_default_tx_datarate();
mcps_req.data_rate = _loramac.get_default_tx_datarate();
tr_info("Transmit confirmed compliance test frame %d bytes.", mcps_req.f_buffer_size);
@ -1382,5 +1103,141 @@ lorawan_status_t LoRaWANStack::send_compliance_test_frame_to_mac()
return mcps_request_handler(&mcps_req);
}
/** Compliance testing function
*
* \param mcps_indication Pointer to the indication structure,
* containing indication attributes.
*/
void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t *mcps_indication)
{
if (_compliance_test.running == false) {
// Check compliance test enable command (i)
if ((mcps_indication->buffer_size == 4) &&
(mcps_indication->buffer[0] == 0x01) &&
(mcps_indication->buffer[1] == 0x01) &&
(mcps_indication->buffer[2] == 0x01) &&
(mcps_indication->buffer[3] == 0x01)) {
_compliance_test.is_tx_confirmed = false;
_compliance_test.app_port = 224;
_compliance_test.app_data_size = 2;
_compliance_test.downlink_counter = 0;
_compliance_test.link_check = false;
_compliance_test.demod_margin = 0;
_compliance_test.nb_gateways = 0;
_compliance_test.running = true;
_compliance_test.state = 1;
loramac_mib_req_confirm_t mib_req;
mib_req.type = MIB_ADR;
mib_req.param.is_adr_enable = true;
mib_set_request(&mib_req);
#if MBED_CONF_LORA_PHY == 0
_loramac.LoRaMacTestSetDutyCycleOn(false);
#endif
//5000ms
_loramac.LoRaMacSetTxTimer(5000);
//TODO: Should we call lora_state_machine here instead of just setting the state?
_device_current_state = DEVICE_STATE_COMPLIANCE_TEST;
// lora_state_machine(DEVICE_STATE_COMPLIANCE_TEST);
tr_debug("Compliance test activated.");
}
} else {
_compliance_test.state = mcps_indication->buffer[0];
switch (_compliance_test.state) {
case 0: // Check compliance test disable command (ii)
_compliance_test.is_tx_confirmed = true;
_compliance_test.app_port = MBED_CONF_LORA_APP_PORT;
_compliance_test.app_data_size = LORAWAN_COMPLIANCE_TEST_DATA_SIZE;
_compliance_test.downlink_counter = 0;
_compliance_test.running = false;
loramac_mib_req_confirm_t mib_req;
mib_req.type = MIB_ADR;
mib_req.param.is_adr_enable = MBED_CONF_LORA_ADR_ON;
mib_set_request(&mib_req);
#if MBED_CONF_LORA_PHY == 0
_loramac.LoRaMacTestSetDutyCycleOn(MBED_CONF_LORA_DUTY_CYCLE_ON);
#endif
// Go to idle state after compliance test mode.
tr_debug("Compliance test disabled.");
_loramac.LoRaMacStopTxTimer();
// Clear any compliance test message stuff before going back to normal operation.
_loramac.reset_ongoing_tx();
lora_state_machine(DEVICE_STATE_IDLE);
break;
case 1: // (iii, iv)
_compliance_test.app_data_size = 2;
break;
case 2: // Enable confirmed messages (v)
_compliance_test.is_tx_confirmed = true;
_compliance_test.state = 1;
break;
case 3: // Disable confirmed messages (vi)
_compliance_test.is_tx_confirmed = false;
_compliance_test.state = 1;
break;
case 4: // (vii)
_compliance_test.app_data_size = mcps_indication->buffer_size;
_compliance_test.app_data_buffer[0] = 4;
for(uint8_t i = 1; i < MIN(_compliance_test.app_data_size, LORAMAC_PHY_MAXPAYLOAD); ++i) {
_compliance_test.app_data_buffer[i] = mcps_indication->buffer[i] + 1;
}
send_compliance_test_frame_to_mac();
break;
case 5: // (viii)
loramac_mlme_req_t mlme_req;
mlme_req.type = MLME_LINK_CHECK;
_loramac.mlme_request(&mlme_req);
break;
case 6: // (ix)
loramac_mlme_req_t mlme_request;
loramac_mib_req_confirm_t mib_request;
// Disable TestMode and revert back to normal operation
_compliance_test.is_tx_confirmed = true;
_compliance_test.app_port = MBED_CONF_LORA_APP_PORT;
_compliance_test.app_data_size = LORAWAN_COMPLIANCE_TEST_DATA_SIZE;
_compliance_test.downlink_counter = 0;
_compliance_test.running = false;
mib_request.type = MIB_ADR;
mib_request.param.is_adr_enable = MBED_CONF_LORA_ADR_ON;
mib_set_request(&mib_request);
#if MBED_CONF_LORA_PHY == 0
_loramac.LoRaMacTestSetDutyCycleOn(MBED_CONF_LORA_DUTY_CYCLE_ON);
#endif
mlme_request.type = MLME_JOIN;
mlme_request.req.join.dev_eui = _lw_session.connection.connection_u.otaa.dev_eui;
mlme_request.req.join.app_eui = _lw_session.connection.connection_u.otaa.app_eui;
mlme_request.req.join.app_key = _lw_session.connection.connection_u.otaa.app_key;
mlme_request.req.join.nb_trials = _lw_session.connection.connection_u.otaa.nb_trials;
_loramac.mlme_request(&mlme_request);
break;
case 7: // (x)
if (mcps_indication->buffer_size == 3) {
loramac_mlme_req_t mlme_req;
mlme_req.type = MLME_TXCW;
mlme_req.req.cw_tx_mode.timeout = (uint16_t)((mcps_indication->buffer[1] << 8) | mcps_indication->buffer[2]);
_loramac.mlme_request(&mlme_req);
} else if (mcps_indication->buffer_size == 7) {
loramac_mlme_req_t mlme_req;
mlme_req.type = MLME_TXCW_1;
mlme_req.req.cw_tx_mode.timeout = (uint16_t)((mcps_indication->buffer[1] << 8) | mcps_indication->buffer[2]);
mlme_req.req.cw_tx_mode.frequency = (uint32_t)((mcps_indication->buffer[3] << 16) | (mcps_indication->buffer[4] << 8)
| mcps_indication->buffer[5]) * 100;
mlme_req.req.cw_tx_mode.power = mcps_indication->buffer[6];
_loramac.mlme_request(&mlme_req);
}
_compliance_test.state = 1;
break;
}
}
}
#endif

View File

@ -34,7 +34,6 @@ SPDX-License-Identifier: BSD-3-Clause
#include "lorastack/mac/LoRaMac.h"
#include "lorawan/system/lorawan_data_structures.h"
#include "LoRaRadio.h"
#include "loraphy_target.h"
/**
* A mask for the network ID.
@ -279,13 +278,15 @@ public:
* MSG_CONFIRMED_FLAG and MSG_UNCONFIRMED_FLAG are
* mutually exclusive.
*
* @param null_allowed Internal use only. Needed for sending empty packet
* having CONFIRMED bit on.
*
* @return The number of bytes sent, or
* LORAWAN_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);
uint16_t length, uint8_t flags, bool null_allowed = false);
/** Receives a message from the Network Server.
*
@ -386,11 +387,6 @@ private:
*/
lorawan_status_t lora_state_machine(device_states_t new_state);
/**
* Hands over the packet to Mac layer by posting an MCPS request.
*/
lorawan_status_t send_frame_to_mac();
/**
* Callback function for MLME indication. Mac layer calls this function once
* an MLME indication is received. This method translates Mac layer data
@ -443,16 +439,6 @@ private:
*/
lorawan_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);
/** End device OTAA join.
*
* Based on the LoRaWAN standard 1.0.2.
@ -481,9 +467,7 @@ private:
private:
LoRaWANTimeHandler _lora_time;
LoRaMac _loramac;
LoRaPHY_region _lora_phy;
loramac_primitives_t LoRaMacPrimitives;
device_states_t _device_current_state;
@ -498,10 +482,6 @@ private:
events::EventQueue *_queue;
#if defined(LORAWAN_COMPLIANCE_TEST)
/**
* This function is used only for compliance testing
*/
void prepare_special_tx_frame(uint8_t port);
/**
* Used only for compliance testing

View File

@ -77,10 +77,9 @@ using namespace events;
#define DOWN_LINK 1
LoRaMac::LoRaMac(LoRaWANTimeHandler &lora_time)
: mac_commands(), _lora_time(lora_time)
LoRaMac::LoRaMac()
: _lora_phy(_lora_time), mac_commands()
{
lora_phy = NULL;
//radio_events_t RadioEvents;
_params.keys.dev_eui = NULL;
_params.keys.app_eui = NULL;
@ -88,6 +87,7 @@ LoRaMac::LoRaMac(LoRaWANTimeHandler &lora_time)
memset(_params.keys.nwk_skey, 0, sizeof(_params.keys.nwk_skey));
memset(_params.keys.app_skey, 0, sizeof(_params.keys.app_skey));
memset(&_ongoing_tx_msg, 0, sizeof(_ongoing_tx_msg));
_params.dev_nonce = 0;
_params.net_id = 0;
@ -188,7 +188,7 @@ void LoRaMac::on_radio_tx_done( void )
loramac_mlme_confirm_t mlme_confirm = mlme.get_confirmation();
if (_params.dev_class != CLASS_C) {
lora_phy->put_radio_to_sleep();
_lora_phy.put_radio_to_sleep();
} else {
open_continuous_rx2_window();
}
@ -204,7 +204,7 @@ void LoRaMac::on_radio_tx_done( void )
if ((_params.dev_class == CLASS_C ) ||
(_params.is_node_ack_requested == true)) {
_lora_time.start(_params.timers.ack_timeout_timer,
_params.rx_window2_delay + lora_phy->get_ack_timeout());
_params.rx_window2_delay + _lora_phy.get_ack_timeout());
}
} else {
mcps.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_OK;
@ -232,7 +232,7 @@ void LoRaMac::on_radio_tx_done( void )
tx_done_params.channel = _params.channel;
tx_done_params.joined = _params.is_nwk_joined;
tx_done_params.last_tx_done_time = cur_time;
lora_phy->set_last_tx_done(&tx_done_params);
_lora_phy.set_last_tx_done(&tx_done_params);
// Update Aggregated last tx done time
_params.timers.aggregated_last_tx_time = cur_time;
@ -302,7 +302,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi,
mcps.get_indication().type = MCPS_UNCONFIRMED;
if (_params.dev_class != CLASS_C) {
lora_phy->put_radio_to_sleep();
_lora_phy.put_radio_to_sleep();
}
_lora_time.stop( _params.timers.rx_window2_timer );
@ -377,7 +377,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi,
// Size of the regular payload is 12. Plus 1 byte MHDR and 4 bytes MIC
cflist.size = size - 17;
lora_phy->apply_cf_list(&cflist);
_lora_phy.apply_cf_list(&cflist);
mlme.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_OK;
_params.is_nwk_joined = true;
@ -390,7 +390,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi,
case FRAME_TYPE_DATA_CONFIRMED_DOWN:
case FRAME_TYPE_DATA_UNCONFIRMED_DOWN:
{
uint8_t value = lora_phy->get_max_payload(mcps.get_indication().rx_datarate, _params.is_repeater_supported);
uint8_t value = _lora_phy.get_max_payload(mcps.get_indication().rx_datarate, _params.is_repeater_supported);
if (MAX(0, (int16_t) ((int16_t)size - (int16_t)LORA_MAC_FRMPAYLOAD_OVERHEAD )) > (int32_t)value) {
mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_ERROR;
@ -469,7 +469,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi,
}
}
if (sequence_counter_diff >= lora_phy->get_maximum_frame_counter_gap()) {
if (sequence_counter_diff >= _lora_phy.get_maximum_frame_counter_gap()) {
mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS;
mcps.get_indication().dl_frame_counter = downlink_counter;
prepare_rx_done_abort( );
@ -575,7 +575,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi,
// Decode frame payload MAC commands
if (LORAWAN_STATUS_OK != mac_commands.process_mac_commands(
_params.payload, 0, frame_len, snr,
mlme.get_confirmation(), _params.sys_params, *lora_phy)) {
mlme.get_confirmation(), _params.sys_params, _lora_phy)) {
mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_ERROR;
} else if (mac_commands.has_sticky_mac_cmd()) {
set_mlme_schedule_ul_indication();
@ -592,7 +592,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi,
// Decode Options field MAC commands. Omit the fPort.
if (LORAWAN_STATUS_OK != mac_commands.process_mac_commands(
payload, 8, app_payload_start_index - 1, snr,
mlme.get_confirmation(), _params.sys_params, *lora_phy )) {
mlme.get_confirmation(), _params.sys_params, _lora_phy )) {
mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_ERROR;
} else if (mac_commands.has_sticky_mac_cmd()) {
set_mlme_schedule_ul_indication();
@ -620,7 +620,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi,
if (LORAWAN_STATUS_OK != mac_commands.process_mac_commands(
payload, 8, app_payload_start_index, snr,
mlme.get_confirmation(),
_params.sys_params, *lora_phy)) {
_params.sys_params, _lora_phy)) {
mcps.get_indication().status = LORAMAC_EVENT_INFO_STATUS_ERROR;
} else if (mac_commands.has_sticky_mac_cmd()) {
set_mlme_schedule_ul_indication();
@ -673,7 +673,7 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi,
void LoRaMac::on_radio_tx_timeout( void )
{
if (_params.dev_class != CLASS_C) {
lora_phy->put_radio_to_sleep();
_lora_phy.put_radio_to_sleep();
} else {
open_continuous_rx2_window();
}
@ -688,7 +688,7 @@ void LoRaMac::on_radio_tx_timeout( void )
void LoRaMac::on_radio_rx_error( void )
{
if (_params.dev_class != CLASS_C) {
lora_phy->put_radio_to_sleep();
_lora_phy.put_radio_to_sleep();
}
if (_params.rx_slot == RX_SLOT_WIN_1) {
@ -724,7 +724,7 @@ void LoRaMac::on_radio_rx_error( void )
void LoRaMac::on_radio_rx_timeout(void)
{
if (_params.dev_class != CLASS_C) {
lora_phy->put_radio_to_sleep();
_lora_phy.put_radio_to_sleep();
}
if (_params.rx_slot == RX_SLOT_WIN_1) {
@ -864,7 +864,7 @@ void LoRaMac::on_mac_state_check_timer_event(void)
_params.ack_timeout_retry_counter++;
if ((_params.ack_timeout_retry_counter % 2) == 1) {
_params.sys_params.channel_data_rate = lora_phy->get_next_lower_tx_datarate(
_params.sys_params.channel_data_rate = _lora_phy.get_next_lower_tx_datarate(
_params.sys_params.channel_data_rate);
}
@ -887,7 +887,7 @@ void LoRaMac::on_mac_state_check_timer_event(void)
}
}
} else {
lora_phy->restore_default_channels();
_lora_phy.restore_default_channels();
_params.mac_state &= ~LORAMAC_TX_RUNNING;
@ -970,7 +970,7 @@ void LoRaMac::on_tx_delayed_timer_event(void)
reset_mac_parameters();
_params.sys_params.channel_data_rate = lora_phy->get_alternate_DR(_params.join_request_trial_counter + 1);
_params.sys_params.channel_data_rate = _lora_phy.get_alternate_DR(_params.join_request_trial_counter + 1);
mac_hdr.value = 0;
mac_hdr.bits.mtype = FRAME_TYPE_JOIN_REQ;
@ -1004,10 +1004,10 @@ void LoRaMac::on_rx_window1_timer_event(void)
_params.rx_window1_config.rx_slot = _params.rx_slot;
if (_params.dev_class == CLASS_C) {
lora_phy->put_radio_to_standby();
_lora_phy.put_radio_to_standby();
}
lora_phy->rx_config(&_params.rx_window1_config,
_lora_phy.rx_config(&_params.rx_window1_config,
(int8_t*) &mcps.get_indication().rx_datarate);
rx_window_setup(_params.rx_window1_config.is_rx_continuous,
@ -1031,7 +1031,7 @@ void LoRaMac::on_rx_window2_timer_event(void)
_params.rx_window2_config.is_rx_continuous = true;
}
if (lora_phy->rx_config(&_params.rx_window2_config,
if (_lora_phy.rx_config(&_params.rx_window2_config,
(int8_t*) &mcps.get_indication().rx_datarate) == true) {
rx_window_setup(_params.rx_window2_config.is_rx_continuous,
@ -1089,7 +1089,7 @@ void LoRaMac::on_ack_timeout_timer_event(void)
void LoRaMac::rx_window_setup(bool rx_continuous, uint32_t max_rx_window_time)
{
lora_phy->setup_rx_window(rx_continuous, max_rx_window_time);
_lora_phy.setup_rx_window(rx_continuous, max_rx_window_time);
}
bool LoRaMac::validate_payload_length(uint8_t length, int8_t datarate,
@ -1098,7 +1098,7 @@ bool LoRaMac::validate_payload_length(uint8_t length, int8_t datarate,
uint16_t max_value = 0;
uint16_t payloadSize = 0;
max_value = lora_phy->get_max_payload(datarate, _params.is_repeater_supported);
max_value = _lora_phy.get_max_payload(datarate, _params.is_repeater_supported);
// Calculate the resulting payload size
payloadSize = (length + fopts_len);
@ -1176,7 +1176,7 @@ lorawan_status_t LoRaMac::schedule_tx(void)
nextChan.last_aggregate_tx_time = _params.timers.aggregated_last_tx_time;
// Select channel
status = lora_phy->set_next_channel(&nextChan, &_params.channel,
status = _lora_phy.set_next_channel(&nextChan, &_params.channel,
&dutyCycleTimeOff,
&_params.timers.aggregated_timeoff);
switch (status) {
@ -1198,15 +1198,15 @@ lorawan_status_t LoRaMac::schedule_tx(void)
tr_debug("Next Channel Idx=%d, DR=%d", _params.channel, nextChan.current_datarate);
// Compute Rx1 windows parameters
uint8_t dr_offset = lora_phy->apply_DR_offset(_params.sys_params.channel_data_rate,
uint8_t dr_offset = _lora_phy.apply_DR_offset(_params.sys_params.channel_data_rate,
_params.sys_params.rx1_dr_offset);
lora_phy->compute_rx_win_params(dr_offset, _params.sys_params.min_rx_symb,
_lora_phy.compute_rx_win_params(dr_offset, _params.sys_params.min_rx_symb,
_params.sys_params.max_sys_rx_error,
&_params.rx_window1_config);
// Compute Rx2 windows parameters
lora_phy->compute_rx_win_params(_params.sys_params.rx2_channel.datarate,
_lora_phy.compute_rx_win_params(_params.sys_params.rx2_channel.datarate,
_params.sys_params.min_rx_symb,
_params.sys_params.max_sys_rx_error,
&_params.rx_window2_config);
@ -1245,7 +1245,7 @@ void LoRaMac::calculate_backOff(uint8_t channel)
backoff_params.last_tx_was_join_req = _params.is_last_tx_join_request;
// Update regional back-off
lora_phy->calculate_backoff(&backoff_params);
_lora_phy.calculate_backoff(&backoff_params);
// Update aggregated time-off. This must be an assignment and no incremental
// update as we do only calculate the time-off based on the last transmission
@ -1277,7 +1277,7 @@ void LoRaMac::reset_mac_parameters(void)
_params.is_rx_window_enabled = true;
lora_phy->reset_to_default_values(&_params, false);
_lora_phy.reset_to_default_values(&_params, false);
_params.is_node_ack_requested = false;
_params.is_srv_ack_requested = false;
@ -1303,6 +1303,150 @@ void LoRaMac::open_continuous_rx2_window (void)
_params.rx_slot = RX_SLOT_WIN_CLASS_C;
}
uint8_t LoRaMac::get_default_tx_datarate()
{
return _lora_phy.get_default_tx_datarate();
}
bool LoRaMac::tx_ongoing()
{
return _ongoing_tx_msg.tx_ongoing;
}
void LoRaMac::set_tx_ongoing(bool ongoing)
{
_ongoing_tx_msg.tx_ongoing = ongoing;
}
void LoRaMac::reset_ongoing_tx(bool reset_pending)
{
_ongoing_tx_msg.tx_ongoing = false;
memset(_ongoing_tx_msg.f_buffer, 0, MBED_CONF_LORA_TX_MAX_SIZE);
_ongoing_tx_msg.f_buffer_size = 0;
if (reset_pending) {
_ongoing_tx_msg.pending_size = 0;
}
}
int16_t LoRaMac::prepare_ongoing_tx(uint8_t port, const uint8_t* data,
uint16_t length, uint8_t flags, uint8_t num_retries)
{
_ongoing_tx_msg.port = port;
uint8_t max_possible_size = query_tx_possible(length);
//TODO: refactor following 20 lines or so. There must be a better way for this
if (max_possible_size > MBED_CONF_LORA_TX_MAX_SIZE) {
// LORAWAN_APP_DATA_MAX_SIZE should at least be
// either equal to or bigger than maximum possible
// tx size because our tx message buffer takes its
// length from that macro. Force maximum possible tx unit
// to be equal to the buffer size user chose.
max_possible_size = MBED_CONF_LORA_TX_MAX_SIZE;
}
if (max_possible_size < length) {
tr_info("Cannot transmit %d bytes. Possible TX Size is %d bytes",
length, max_possible_size);
_ongoing_tx_msg.pending_size = length - max_possible_size;
_ongoing_tx_msg.f_buffer_size = max_possible_size;
// copy user buffer upto the max_possible_size
memcpy(_ongoing_tx_msg.f_buffer, data, _ongoing_tx_msg.f_buffer_size);
} else {
// Whole message can be sent at one time
_ongoing_tx_msg.f_buffer_size = length;
_ongoing_tx_msg.pending_size = 0;
// copy user buffer upto the max_possible_size
if (length > 0) {
memcpy(_ongoing_tx_msg.f_buffer, data, length);
}
}
// Handles all unconfirmed messages, including proprietary and multicast
if ((flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_FLAG
|| (flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_MULTICAST
|| (flags & MSG_FLAG_MASK) == MSG_UNCONFIRMED_PROPRIETARY) {
_ongoing_tx_msg.type = MCPS_UNCONFIRMED;
_ongoing_tx_msg.fport = port;
_ongoing_tx_msg.nb_trials = 1;
}
// Handles all confirmed messages, including proprietary and multicast
if ((flags & MSG_FLAG_MASK) == MSG_CONFIRMED_FLAG
|| (flags & MSG_FLAG_MASK) == MSG_CONFIRMED_MULTICAST
|| (flags & MSG_FLAG_MASK) == MSG_CONFIRMED_PROPRIETARY) {
_ongoing_tx_msg.type = MCPS_CONFIRMED;
_ongoing_tx_msg.fport = port;
_ongoing_tx_msg.nb_trials = num_retries;
}
tr_info("RTS = %u bytes, PEND = %u", _ongoing_tx_msg.f_buffer_size, _ongoing_tx_msg.pending_size);
return _ongoing_tx_msg.f_buffer_size;
}
lorawan_status_t LoRaMac::send_ongoing_tx()
{
lorawan_status_t status;
loramac_mib_req_confirm_t mib_get_params;
if (_params.mac_state != LORAMAC_IDLE) {
return LORAWAN_STATUS_BUSY;
}
int8_t datarate = get_default_tx_datarate();
mib_get_params.type = MIB_CHANNELS_DATARATE;
if(mib_get_request_confirm(&mib_get_params) == LORAWAN_STATUS_OK) {
datarate = mib_get_params.param.channel_data_rate;
}
// TODO: The comment is different than the code???
// Apply the minimum possible datarate.
// Some regions have limitations for the minimum datarate.
datarate = MAX(datarate, (int8_t)_lora_phy.get_minimum_tx_datarate());
loramac_mhdr_t machdr;
machdr.value = 0;
mcps.reset_confirmation();
_params.ack_timeout_retry_counter = 1;
_params.max_ack_timeout_retries = 1;
if (MCPS_UNCONFIRMED == _ongoing_tx_msg.type) {
machdr.bits.mtype = FRAME_TYPE_DATA_UNCONFIRMED_UP;
} else if (_ongoing_tx_msg.type == MCPS_CONFIRMED) {
machdr.bits.mtype = FRAME_TYPE_DATA_CONFIRMED_UP;
_params.max_ack_timeout_retries = _ongoing_tx_msg.nb_trials;
} else if ( _ongoing_tx_msg.type == MCPS_PROPRIETARY) {
//Is this dead code currently??? Nobody sets this type
machdr.bits.mtype = FRAME_TYPE_PROPRIETARY;
} else {
return LORAWAN_STATUS_SERVICE_UNKNOWN;
}
if (_params.sys_params.adr_on == false) {
if (_lora_phy.verify_tx_datarate(datarate, false) == true) {
_params.sys_params.channel_data_rate = datarate;
} else {
return LORAWAN_STATUS_PARAMETER_INVALID;
}
}
status = send(&machdr, _ongoing_tx_msg.fport, _ongoing_tx_msg.f_buffer,
_ongoing_tx_msg.f_buffer_size);
if (status == LORAWAN_STATUS_OK) {
mcps.get_confirmation().req_type = _ongoing_tx_msg.type;
_params.flags.bits.mcps_req = 1;
} else {
_params.is_node_ack_requested = false;
}
return status;
}
static void memcpy_convert_endianess(uint8_t *dst, const uint8_t *src,
uint16_t size)
{
@ -1348,7 +1492,7 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr,
_params.keys.dev_eui, 8);
_params.buffer_pkt_len += 8;
_params.dev_nonce = lora_phy->get_radio_rng();
_params.dev_nonce = _lora_phy.get_radio_rng();
_params.buffer[_params.buffer_pkt_len++] = _params.dev_nonce & 0xFF;
_params.buffer[_params.buffer_pkt_len++] = (_params.dev_nonce >> 8) & 0xFF;
@ -1375,7 +1519,7 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr,
}
if (_params.sys_params.adr_on) {
if (lora_phy->get_next_ADR(true,
if (_lora_phy.get_next_ADR(true,
_params.sys_params.channel_data_rate,
_params.sys_params.channel_tx_power,
_params.adr_ack_counter)) {
@ -1503,7 +1647,7 @@ lorawan_status_t LoRaMac::send_frame_on_channel(uint8_t channel)
tx_config.antenna_gain = _params.sys_params.antenna_gain;
tx_config.pkt_len = _params.buffer_pkt_len;
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.get_confirmation().status = LORAMAC_EVENT_INFO_STATUS_ERROR;
@ -1525,61 +1669,15 @@ lorawan_status_t LoRaMac::send_frame_on_channel(uint8_t channel)
}
// Send now
lora_phy->handle_send(_params.buffer, _params.buffer_pkt_len);
_lora_phy.handle_send(_params.buffer, _params.buffer_pkt_len);
_params.mac_state |= LORAMAC_TX_RUNNING;
return LORAWAN_STATUS_OK;
}
//lorawan_status_t LoRaMac::set_tx_continuous_wave(uint16_t timeout)
//{
// cw_mode_params_t continuous_wave;
// continuous_wave.channel = _params.channel;
// continuous_wave.datarate = _params.sys_params.channel_data_rate;
// continuous_wave.tx_power = _params.sys_params.channel_tx_power;
// continuous_wave.max_eirp = _params.sys_params.max_eirp;
// continuous_wave.antenna_gain = _params.sys_params.antenna_gain;
// continuous_wave.timeout = timeout;
// lora_phy->set_tx_cont_mode(&continuous_wave);
// // Starts the MAC layer status check timer
// _lora_time.start(_params.timers.mac_state_check_timer,
// MAC_STATE_CHECK_TIMEOUT);
// _params.mac_state |= LORAMAC_TX_RUNNING;
// return LORAWAN_STATUS_OK;
//}
//lorawan_status_t LoRaMac::set_tx_continuous_wave1(uint16_t timeout,
// uint32_t frequency,
// uint8_t power)
//{
// cw_mode_params_t continuous_wave;
// continuous_wave.channel = 0;
// continuous_wave.datarate = 0;
// continuous_wave.tx_power = power;
// continuous_wave.max_eirp = 0;
// continuous_wave.antenna_gain = 0;
// continuous_wave.timeout = timeout;
// lora_phy->set_tx_cont_mode(&continuous_wave);
// // Starts the MAC layer status check timer
// _lora_time.start(_params.timers.mac_state_check_timer,
// MAC_STATE_CHECK_TIMEOUT);
// _params.mac_state |= LORAMAC_TX_RUNNING;
// return LORAWAN_STATUS_OK;
//}
lorawan_status_t LoRaMac::initialize(loramac_primitives_t *primitives,
LoRaPHY *phy, EventQueue *queue)
EventQueue *queue)
{
_lora_time.activate_timer_subsystem(queue);
@ -1590,19 +1688,17 @@ lorawan_status_t LoRaMac::initialize(loramac_primitives_t *primitives,
return LORAWAN_STATUS_PARAMETER_INVALID;
}
lora_phy = phy;
// Activate MLME subsystem
mlme.activate_mlme_subsystem(lora_phy);
mlme.activate_mlme_subsystem(&_lora_phy);
// Activate MCPS subsystem
mcps.activate_mcps_subsystem();
// Activate MIB subsystem
mib.activate_mib_subsystem(lora_phy);
mib.activate_mib_subsystem(&_lora_phy);
// Activate channel planning subsystem
channel_plan.activate_channelplan_subsystem(lora_phy);
channel_plan.activate_channelplan_subsystem(&_lora_phy);
mac_primitives = primitives;
@ -1619,7 +1715,7 @@ lorawan_status_t LoRaMac::initialize(loramac_primitives_t *primitives,
_params.timers.aggregated_last_tx_time = 0;
_params.timers.aggregated_timeoff = 0;
lora_phy->reset_to_default_values(&_params, true);
_lora_phy.reset_to_default_values(&_params, true);
// Init parameters which are not set in function ResetMacParameters
_params.sys_params.max_sys_rx_error = 10;
@ -1629,11 +1725,11 @@ lorawan_status_t LoRaMac::initialize(loramac_primitives_t *primitives,
reset_mac_parameters();
// Random seed initialization
srand(lora_phy->get_radio_rng());
srand(_lora_phy.get_radio_rng());
_params.is_nwk_public = MBED_CONF_LORA_PUBLIC_NETWORK;
lora_phy->setup_public_network_mode(_params.is_nwk_public);
lora_phy->put_radio_to_sleep();
_lora_phy.setup_public_network_mode(_params.is_nwk_public);
_lora_phy.put_radio_to_sleep();
// Initialize timers
_lora_time.init(_params.timers.mac_state_check_timer,
@ -1673,7 +1769,7 @@ void LoRaMac::disconnect()
_lora_time.stop(_params.timers.ack_timeout_timer);
// Put radio to sleep
lora_phy->put_radio_to_sleep();
_lora_phy.put_radio_to_sleep();
// Reset internal state
_params.is_nwk_joined = false;
@ -1693,31 +1789,27 @@ void LoRaMac::disconnect()
_params.mac_state = LORAMAC_IDLE;
}
lorawan_status_t LoRaMac::query_tx_possible(uint8_t size,
loramac_tx_info_t* tx_info)
uint8_t LoRaMac::query_tx_possible(uint8_t size)
{
uint8_t max_possible_payload_size = 0;
uint8_t current_payload_size = 0;
uint8_t fopt_len = mac_commands.get_mac_cmd_length()
+ mac_commands.get_repeat_commands_length();
if (tx_info == NULL) {
return LORAWAN_STATUS_PARAMETER_INVALID;
}
// if applicaion has turned on ADR, we want to opt it out
// if application has turned on ADR, we want to opt it out
if (_params.sys_params.adr_on) {
lora_phy->get_next_ADR(false, _params.sys_params.channel_data_rate,
_lora_phy.get_next_ADR(false, _params.sys_params.channel_data_rate,
_params.sys_params.channel_tx_power,
_params.adr_ack_counter);
}
tx_info->current_payload_size = lora_phy->get_max_payload(_params.sys_params.channel_data_rate, _params.is_repeater_supported);
current_payload_size = _lora_phy.get_max_payload(_params.sys_params.channel_data_rate, _params.is_repeater_supported);
// Verify if the fOpts fit into the maximum payload
if (tx_info->current_payload_size >= fopt_len) {
tx_info->max_possible_payload_size = tx_info->current_payload_size - fopt_len;
if (current_payload_size >= fopt_len) {
max_possible_payload_size = current_payload_size - fopt_len;
} else {
tx_info->max_possible_payload_size = tx_info->current_payload_size;
max_possible_payload_size = current_payload_size;
// The fOpts don't fit into the maximum payload. Omit the MAC commands to
// ensure that another uplink is possible.
fopt_len = 0;
@ -1728,9 +1820,9 @@ lorawan_status_t LoRaMac::query_tx_possible(uint8_t size,
// Verify if the fOpts and the payload fit into the maximum payload
if (validate_payload_length(size, _params.sys_params.channel_data_rate,
fopt_len) == false) {
return LORAWAN_STATUS_LENGTH_ERROR;
return max_possible_payload_size;
}
return LORAWAN_STATUS_OK;
return current_payload_size;
}
lorawan_status_t LoRaMac::add_channel_plan(const lorawan_channelplan_t& plan)
@ -1876,7 +1968,7 @@ lorawan_status_t LoRaMac::mlme_request( loramac_mlme_req_t *mlmeRequest )
_params.keys.app_key = mlmeRequest->req.join.app_key;
_params.max_join_request_trials = mlmeRequest->req.join.nb_trials;
if (!lora_phy->verify_nb_join_trials(mlmeRequest->req.join.nb_trials)) {
if (!_lora_phy.verify_nb_join_trials(mlmeRequest->req.join.nb_trials)) {
// Value not supported, get default
_params.max_join_request_trials = MBED_CONF_LORA_NB_TRIALS;
}
@ -1886,7 +1978,7 @@ lorawan_status_t LoRaMac::mlme_request( loramac_mlme_req_t *mlmeRequest )
reset_mac_parameters();
_params.sys_params.channel_data_rate =
lora_phy->get_alternate_DR(_params.join_request_trial_counter + 1);
_lora_phy.get_alternate_DR(_params.join_request_trial_counter + 1);
loramac_mhdr_t machdr;
machdr.value = 0;
@ -1929,7 +2021,7 @@ lorawan_status_t LoRaMac::mcps_request( loramac_mcps_req_t *mcpsRequest )
// TODO: The comment is different than the code???
// Apply the minimum possible datarate.
// Some regions have limitations for the minimum datarate.
datarate = MAX(datarate, (int8_t)lora_phy->get_minimum_tx_datarate());
datarate = MAX(datarate, (int8_t)_lora_phy.get_minimum_tx_datarate());
machdr.value = 0;
@ -1963,7 +2055,7 @@ lorawan_status_t LoRaMac::mcps_request( loramac_mcps_req_t *mcpsRequest )
// }
if (_params.sys_params.adr_on == false) {
if (lora_phy->verify_tx_datarate(datarate, false) == true) {
if (_lora_phy.verify_tx_datarate(datarate, false) == true) {
_params.sys_params.channel_data_rate = datarate;
} else {
return LORAWAN_STATUS_PARAMETER_INVALID;
@ -1997,7 +2089,7 @@ lorawan_status_t LoRaMac::mib_set_request_confirm( loramac_mib_req_confirm_t *mi
return status;
}
radio_events_t *LoRaMac::get_phy_event_handlers()
void LoRaMac::bind_radio_driver(LoRaRadio& radio)
{
radio_events.tx_done = mbed::callback(this, &LoRaMac::handle_tx_done);
radio_events.rx_done = mbed::callback(this, &LoRaMac::handle_rx_done);
@ -2005,7 +2097,10 @@ radio_events_t *LoRaMac::get_phy_event_handlers()
radio_events.tx_timeout = mbed::callback(this, &LoRaMac::handle_tx_timeout);
radio_events.rx_timeout = mbed::callback(this, &LoRaMac::handle_rx_timeout);
return &radio_events;
_lora_phy.set_radio_instance(radio);
radio.lock();
radio.init_radio(&radio_events);
radio.unlock();
}
#if defined(LORAWAN_COMPLIANCE_TEST)
@ -2038,7 +2133,7 @@ void LoRaMac::LoRaMacTestSetMic( uint16_t txPacketCounter )
void LoRaMac::LoRaMacTestSetDutyCycleOn( bool enable )
{
if(lora_phy->verify_duty_cycle(enable) == true)
if(_lora_phy.verify_duty_cycle(enable) == true)
{
_params.is_dutycycle_on = enable;
}

View File

@ -49,6 +49,7 @@
#include "lorastack/mac/LoRaMacMcps.h"
#include "lorastack/mac/LoRaMacMib.h"
#include "lorastack/mac/LoRaMacChannelPlan.h"
#include "loraphy_target.h"
class LoRaMac {
@ -57,7 +58,7 @@ public:
/**
* Constructor
*/
LoRaMac(LoRaWANTimeHandler &lora_time);
LoRaMac();
/**
* Destructor
@ -75,15 +76,13 @@ public:
* @param primitives [in] A pointer to the structure defining the LoRaMAC
* event functions. Refer to \ref loramac_primitives_t.
*
* @param phy [in] A pointer to the selected PHY layer.
*
* @param queue [in] A pointer to the application provided EventQueue.
*
* @return `lorawan_status_t` The status of the operation. The possible values are:
* \ref LORAWAN_STATUS_OK
* \ref LORAWAN_STATUS_PARAMETER_INVALID
*/
lorawan_status_t initialize(loramac_primitives_t *primitives, LoRaPHY *phy,
lorawan_status_t initialize(loramac_primitives_t *primitives,
events::EventQueue *queue);
/**
@ -97,26 +96,16 @@ public:
/**
* @brief Queries the LoRaMAC whether it is possible to send the next frame with
* a given payload size. The LoRaMAC takes the scheduled MAC commands into
* account and reports when the frame can be sent.
* account and returns corresponding value.
*
* @param size [in] The size of the applicable payload to be sent next.
* @param tx_info [out] The structure \ref loramac_tx_info_t contains
* information on the actual maximum payload possible
* (according to the configured datarate or the next
* datarate according to ADR), and the maximum frame
* size, taking the scheduled MAC commands into account.
*
* @return `lorawan_status_t` The status of the operation. When the parameters are
* not valid, the function returns \ref LORAWAN_STATUS_PARAMETER_INVALID.
* In case of a length error caused by the applicable payload in combination
* with the MAC commands, the function returns \ref LORAWAN_STATUS_LENGTH_ERROR.
* @return Size of the biggest packet that can be sent.
* Please note that if the size of the MAC commands in the queue do
* not fit into the payload size on the related datarate, the LoRaMAC will
* omit the MAC commands.
* If the query is valid, and the LoRaMAC is able to send the frame,
* the function returns \ref LORAWAN_STATUS_OK.
*/
lorawan_status_t query_tx_possible(uint8_t size, loramac_tx_info_t* tx_info);
uint8_t query_tx_possible(uint8_t size);
/**
* @brief Adds a channel plan to the system.
@ -358,13 +347,18 @@ public:
*/
lorawan_status_t mcps_request(loramac_mcps_req_t *request);
/**
* @brief LoRaMAC layer provides its callback functions for
* PHY layer.
/** 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 initialises radio callback handles which the radio driver will
* use in order to report events.
*
* @param radio LoRaRadio object, i.e., the radio driver
*
* @return Pointer to callback functions for radio events
*/
radio_events_t *get_phy_event_handlers();
void bind_radio_driver(LoRaRadio& radio);
/**
* @brief Configures the events to trigger an MLME-Indication with
@ -427,7 +421,49 @@ public:
*/
void open_continuous_rx2_window(void);
/**
* @brief get_default_tx_datarate Gets the default TX datarate
* @return default TX datarate.
*/
uint8_t get_default_tx_datarate();
/**
* @brief tx_ongoing Check whether a prepare is done or not.
* @return True if prepare_ongoing_tx is called, false otherwise.
*/
bool tx_ongoing();
/**
* @brief set_tx_ongoing Changes the ongoing status for prepared message.
* @param ongoing The value indicating the status.
*/
void set_tx_ongoing(bool ongoing);
/**
* @brief reset_ongoing_tx Resets _ongoing_tx_msg.
* @param reset_pending If true resets pending size also.
*/
void reset_ongoing_tx(bool reset_pending = false);
/**
* @brief prepare_ongoing_tx This will prepare (and override) ongoing_tx_msg.
* @param port The application port number.
* @param data A pointer to the data being sent. The ownership of the
* buffer is not transferred.
* @param length The size of data in bytes.
* @param flags A flag used to determine what type of
* message is being sent.
* @param num_retries Number of retries for a confirmed type message
* @return The number of bytes prepared for sending.
*/
int16_t prepare_ongoing_tx(uint8_t port, const uint8_t* data,
uint16_t length, uint8_t flags, uint8_t num_retries);
/**
* @brief send_ongoing_tx Sends the ongoing_tx_msg
* @return LORAWAN_STATUS_OK or a negative error code on failure.
*/
lorawan_status_t send_ongoing_tx();
private:
/**
@ -552,10 +588,15 @@ private:
void handle_fhss_change_channel(uint8_t cur_channel);
private:
/**
* Timer subsystem handle
*/
LoRaWANTimeHandler _lora_time;
/**
* LoRa PHY layer object storage
*/
LoRaPHY *lora_phy;
LoRaPHY_region _lora_phy;
/**
* MAC command handle
@ -582,11 +623,6 @@ private:
*/
LoRaMacChannelPlan channel_plan;
/**
* Timer subsystem handle
*/
LoRaWANTimeHandler &_lora_time;
/**
* Central MAC layer data storage
*/
@ -607,6 +643,8 @@ private:
*/
events::EventQueue *ev_queue;
loramac_tx_message_t _ongoing_tx_msg;
#if defined(LORAWAN_COMPLIANCE_TEST)
public: // Test interface

View File

@ -1550,20 +1550,6 @@ typedef struct {
mib_params_t param;
}loramac_mib_req_confirm_t;
/*!
* LoRaMAC TX information
*/
typedef struct {
/*!
* Defines the size of the applicable payload that can be processed.
*/
uint8_t max_possible_payload_size;
/*!
* The current payload size, dependent on the current datarate.
*/
uint8_t current_payload_size;
} loramac_tx_info_t;
/** LoRaMAC status.
*
*/