mirror of https://github.com/ARMmbed/mbed-os.git
Adding ability to cancel outgoing transmission
Application can use cancel_sending() API to stop any outstanding, outgoing transmission (a TX which is not already queued for transmission). This can potentially enable use cases where the application could cancel a transmission and go to sleep if the backoff period is long enough rather than waiting for the transmission to happen.pull/6910/head
parent
8363311c7a
commit
26b28f78af
|
@ -389,6 +389,19 @@ public:
|
|||
*
|
||||
*/
|
||||
virtual lorawan_status_t get_backoff_metadata(int& backoff) = 0;
|
||||
|
||||
/** Cancel outgoing transmission
|
||||
*
|
||||
* This API is used to cancel any outstanding transmission in the TX pipe.
|
||||
* If an event for transmission is not already queued at the end of backoff timer,
|
||||
* the system can cancel the outstanding outgoing packet. Otherwise, the system is
|
||||
* busy sending and can't be held back.
|
||||
*
|
||||
* @return LORAWAN_STATUS_OK if the sending is cancelled.
|
||||
* LORAWAN_STATUS_BUSY otherwise.
|
||||
*
|
||||
*/
|
||||
virtual lorawan_status_t cancel_sending(void) = 0;
|
||||
};
|
||||
|
||||
#endif /* LORAWAN_BASE_H_ */
|
||||
|
|
|
@ -122,6 +122,12 @@ int16_t LoRaWANInterface::send(uint8_t port, const uint8_t* data, uint16_t lengt
|
|||
return _lw_stack.handle_tx(port, data, length, flags);
|
||||
}
|
||||
|
||||
lorawan_status_t LoRaWANInterface::cancel_sending(void)
|
||||
{
|
||||
Lock lock(*this);
|
||||
return _lw_stack.stop_sending();
|
||||
}
|
||||
|
||||
lorawan_status_t LoRaWANInterface::get_tx_metadata(lorawan_tx_metadata& metadata)
|
||||
{
|
||||
Lock lock(*this);
|
||||
|
|
|
@ -488,6 +488,20 @@ public:
|
|||
*/
|
||||
virtual lorawan_status_t get_backoff_metadata(int& backoff);
|
||||
|
||||
/** Cancel outgoing transmission
|
||||
*
|
||||
* This API is used to cancel any outstanding transmission in the TX pipe.
|
||||
* If an event for transmission is not already queued at the end of backoff timer,
|
||||
* the system can cancel the outstanding outgoing packet. Otherwise, the system is
|
||||
* busy sending and can't be held back. The system will not try to re-send if the
|
||||
* outgoing message was a CONFIRMED message even if the ack is not received.
|
||||
*
|
||||
* @return LORAWAN_STATUS_OK if the sending is cancelled.
|
||||
* LORAWAN_STATUS_BUSY otherwise.
|
||||
*
|
||||
*/
|
||||
virtual lorawan_status_t cancel_sending(void);
|
||||
|
||||
void lock(void) { _lw_stack.lock(); }
|
||||
void unlock(void) { _lw_stack.unlock(); }
|
||||
|
||||
|
|
|
@ -257,6 +257,21 @@ lorawan_status_t LoRaWANStack::enable_adaptive_datarate(bool adr_enabled)
|
|||
return LORAWAN_STATUS_OK;
|
||||
}
|
||||
|
||||
lorawan_status_t LoRaWANStack::stop_sending(void)
|
||||
{
|
||||
if (_loramac.clear_tx_pipe() == LORAWAN_STATUS_OK) {
|
||||
if (_device_current_state == DEVICE_STATE_SENDING) {
|
||||
_ctrl_flags &= ~TX_DONE_FLAG;
|
||||
_ctrl_flags &= ~TX_ONGOING_FLAG;
|
||||
_loramac.set_tx_ongoing(false);
|
||||
_device_current_state = DEVICE_STATE_IDLE;
|
||||
return LORAWAN_STATUS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return LORAWAN_STATUS_BUSY;
|
||||
}
|
||||
|
||||
int16_t LoRaWANStack::handle_tx(const uint8_t port, const uint8_t* data,
|
||||
uint16_t length, uint8_t flags,
|
||||
bool null_allowed, bool allow_port_0)
|
||||
|
@ -517,8 +532,8 @@ void LoRaWANStack::process_transmission_timeout()
|
|||
// this is a fatal error and should not happen
|
||||
tr_debug("TX Timeout");
|
||||
_loramac.on_radio_tx_timeout();
|
||||
_ctrl_flags &= ~TX_ONGOING_FLAG;
|
||||
_ctrl_flags |= TX_DONE_FLAG;
|
||||
_ctrl_flags |= TX_ONGOING_FLAG;
|
||||
_ctrl_flags &= ~TX_DONE_FLAG;
|
||||
state_controller(DEVICE_STATE_STATUS_CHECK);
|
||||
state_machine_run_to_completion();
|
||||
}
|
||||
|
@ -576,12 +591,21 @@ void LoRaWANStack::process_reception(const uint8_t* const payload, uint16_t size
|
|||
if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED) {
|
||||
// if ack was not received, we will try retransmission after
|
||||
// ACK_TIMEOUT. handle_data_frame() already disables ACK_TIMEOUT timer
|
||||
// if ack was received
|
||||
// if ack was received. Otherwise, following method will be called in
|
||||
// LoRaMac.cpp, on_ack_timeout_timer_event().
|
||||
if (_loramac.get_mcps_indication()->is_ack_recvd) {
|
||||
tr_debug("Ack=OK, NbTrials=%d", _loramac.get_mcps_confirmation()->nb_retries);
|
||||
_loramac.post_process_mcps_req();
|
||||
_ctrl_flags |= TX_DONE_FLAG;
|
||||
_ctrl_flags &= ~TX_ONGOING_FLAG;
|
||||
state_controller(DEVICE_STATE_STATUS_CHECK);
|
||||
} else {
|
||||
if (!_loramac.continue_sending_process()) {
|
||||
tr_error("Retries exhausted for Class A device");
|
||||
_ctrl_flags &= ~TX_DONE_FLAG;
|
||||
_ctrl_flags |= TX_ONGOING_FLAG;
|
||||
state_controller(DEVICE_STATE_STATUS_CHECK);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// handle UNCONFIRMED, PROPRIETARY case here, RX slots were turned off due to
|
||||
|
@ -636,13 +660,19 @@ void LoRaWANStack::process_reception_timeout(bool is_timeout)
|
|||
* of UNCONFIRMED message after RX windows are done with.
|
||||
* For a CONFIRMED message, it means that we have not received
|
||||
* ack (actually nothing was received), and we should retransmit if we can.
|
||||
*
|
||||
* NOTE: This code block doesn't get hit for Class C as in Class C, RX2 timeout
|
||||
* never occurs.
|
||||
*/
|
||||
if (slot == RX_SLOT_WIN_2) {
|
||||
_loramac.post_process_mcps_req();
|
||||
|
||||
if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED
|
||||
&& _loramac.continue_sending_process()) {
|
||||
return;
|
||||
if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED) {
|
||||
if (_loramac.continue_sending_process()) {
|
||||
return;
|
||||
} else {
|
||||
tr_error("Retries exhausted for Class A device");
|
||||
}
|
||||
}
|
||||
|
||||
state_controller(DEVICE_STATE_STATUS_CHECK);
|
||||
|
@ -666,7 +696,6 @@ void LoRaWANStack::make_tx_metadata_available(void)
|
|||
void LoRaWANStack::make_rx_metadata_available(void)
|
||||
{
|
||||
_rx_metadata.stale = false;
|
||||
_rx_metadata.fpending_status = _loramac.get_mcps_indication()->fpending_status;
|
||||
_rx_metadata.rx_datarate = _loramac.get_mcps_indication()->rx_datarate;
|
||||
_rx_metadata.rssi = _loramac.get_mcps_indication()->rssi;
|
||||
_rx_metadata.snr = _loramac.get_mcps_indication()->snr;
|
||||
|
@ -972,7 +1001,7 @@ void LoRaWANStack::process_status_check_state()
|
|||
// we may or may not have a successful UNCONFIRMED transmission
|
||||
// here. In CONFIRMED case this block is invoked only
|
||||
// when the MAX number of retries are exhausted, i.e., only error
|
||||
// case will fall here.
|
||||
// case will fall here. Moreover, it will happen for Class A only.
|
||||
_ctrl_flags &= ~TX_DONE_FLAG;
|
||||
_ctrl_flags &= ~TX_ONGOING_FLAG;
|
||||
_loramac.set_tx_ongoing(false);
|
||||
|
@ -981,8 +1010,11 @@ void LoRaWANStack::process_status_check_state()
|
|||
|
||||
} else if (_device_current_state == DEVICE_STATE_RECEIVING) {
|
||||
|
||||
if (_ctrl_flags & TX_DONE_FLAG) {
|
||||
if ((_ctrl_flags & TX_DONE_FLAG) || (_ctrl_flags & TX_ONGOING_FLAG)) {
|
||||
// for CONFIRMED case, ack validity is already checked
|
||||
// If it was a successful transmission, TX_ONGOING_FLAG will not be set.
|
||||
// If it was indeed set, that means the device was in Class C mode and
|
||||
// CONFIRMED transmission was in place and the ack retries maxed out.
|
||||
_ctrl_flags &= ~TX_DONE_FLAG;
|
||||
_ctrl_flags &= ~TX_ONGOING_FLAG;
|
||||
_loramac.set_tx_ongoing(false);
|
||||
|
|
|
@ -415,6 +415,16 @@ public:
|
|||
*/
|
||||
lorawan_status_t acquire_backoff_metadata(int& backoff);
|
||||
|
||||
/** Stops sending
|
||||
*
|
||||
* Stop sending any outstanding messages if they are not yet queued for
|
||||
* transmission, i.e., if the backoff timer is nhot elapsed yet.
|
||||
*
|
||||
* @return LORAWAN_STATUS_OK if the transmission is cancelled.
|
||||
* LORAWAN_STATUS_BUSY otherwise.
|
||||
*/
|
||||
lorawan_status_t stop_sending(void);
|
||||
|
||||
void lock(void) { _loramac.lock(); }
|
||||
void unlock(void) { _loramac.unlock(); }
|
||||
|
||||
|
|
|
@ -208,7 +208,7 @@ void LoRaMac::on_radio_tx_done(void)
|
|||
_lora_time.start(_params.timers.rx_window2_timer, _params.rx_window2_delay);
|
||||
}
|
||||
|
||||
if (_params.is_node_ack_requested == true) {
|
||||
if (_params.is_node_ack_requested) {
|
||||
_lora_time.start(_params.timers.ack_timeout_timer,
|
||||
_params.rx_window2_delay + _lora_phy.get_ack_timeout());
|
||||
}
|
||||
|
@ -1013,6 +1013,22 @@ int LoRaMac::get_backoff_timer_event_id(void)
|
|||
return _params.timers.backoff_timer.timer_id;
|
||||
}
|
||||
|
||||
lorawan_status_t LoRaMac::clear_tx_pipe(void)
|
||||
{
|
||||
// check if the event is not already queued
|
||||
if (_ev_queue->time_left(get_backoff_timer_event_id()) > 0) {
|
||||
_lora_time.stop(_params.timers.backoff_timer);
|
||||
_lora_time.stop(_params.timers.ack_timeout_timer);
|
||||
memset(_params.tx_buffer, 0, sizeof _params.tx_buffer);
|
||||
_params.tx_buffer_len = 0;
|
||||
reset_ongoing_tx(true);
|
||||
tr_debug("Sending Cancelled");
|
||||
return LORAWAN_STATUS_OK;
|
||||
}
|
||||
|
||||
return LORAWAN_STATUS_BUSY;
|
||||
}
|
||||
|
||||
lorawan_status_t LoRaMac::schedule_tx()
|
||||
{
|
||||
channel_selection_params_t next_channel;
|
||||
|
@ -1085,6 +1101,12 @@ lorawan_status_t LoRaMac::schedule_tx()
|
|||
+ _params.rx_window2_config.window_offset;
|
||||
}
|
||||
|
||||
// handle the ack to the server here so that if the sending was cancelled
|
||||
// by the user in the backoff period, we would still ack the previous frame.
|
||||
if (_params.is_srv_ack_requested) {
|
||||
_params.is_srv_ack_requested = false;
|
||||
}
|
||||
|
||||
return send_frame_on_channel(_params.channel);
|
||||
}
|
||||
|
||||
|
@ -1488,7 +1510,6 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr,
|
|||
}
|
||||
|
||||
if (_params.is_srv_ack_requested == true) {
|
||||
_params.is_srv_ack_requested = false;
|
||||
fctrl->bits.ack = 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -447,6 +447,12 @@ public:
|
|||
*/
|
||||
int get_backoff_timer_event_id(void);
|
||||
|
||||
/**
|
||||
* Clears out the TX pipe by discarding any outgoing message if the backoff
|
||||
* timer is still running.
|
||||
*/
|
||||
lorawan_status_t clear_tx_pipe(void);
|
||||
|
||||
/**
|
||||
* These locks trample through to the upper layers and make
|
||||
* the stack thread safe.
|
||||
|
|
|
@ -350,29 +350,29 @@ typedef struct lora_channelplan {
|
|||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* A boolean to mark if the meta data is stale
|
||||
* The transmission time on air of the frame.
|
||||
*/
|
||||
bool stale;
|
||||
uint32_t tx_toa;
|
||||
/**
|
||||
* The uplink channel used for transmission.
|
||||
*/
|
||||
uint32_t channel;
|
||||
/**
|
||||
* The uplink datarate.
|
||||
*/
|
||||
uint8_t data_rate;
|
||||
/**
|
||||
* The transmission power.
|
||||
*/
|
||||
int8_t tx_power;
|
||||
/**
|
||||
* The uplink datarate.
|
||||
*/
|
||||
uint8_t data_rate;
|
||||
/**
|
||||
* Provides the number of retransmissions.
|
||||
*/
|
||||
uint8_t nb_retries;
|
||||
/**
|
||||
* The transmission time on air of the frame.
|
||||
* A boolean to mark if the meta data is stale
|
||||
*/
|
||||
uint32_t tx_toa;
|
||||
bool stale;
|
||||
} lorawan_tx_metadata;
|
||||
|
||||
/**
|
||||
|
@ -380,25 +380,21 @@ typedef struct {
|
|||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* A boolean to mark if the meta data is stale
|
||||
* The RSSI for the received packet.
|
||||
*/
|
||||
bool stale;
|
||||
int16_t rssi;
|
||||
/**
|
||||
* Data rate of reception
|
||||
*/
|
||||
uint8_t rx_datarate;
|
||||
/**
|
||||
* Frame pending status.
|
||||
*/
|
||||
uint8_t fpending_status;
|
||||
/**
|
||||
* The RSSI for the received packet.
|
||||
*/
|
||||
int16_t rssi;
|
||||
/**
|
||||
* The SNR for the received packet.
|
||||
*/
|
||||
uint8_t snr;
|
||||
/**
|
||||
* A boolean to mark if the meta data is stale
|
||||
*/
|
||||
bool stale;
|
||||
} lorawan_rx_metadata;
|
||||
|
||||
#endif /* MBED_LORAWAN_TYPES_H_ */
|
||||
|
|
Loading…
Reference in New Issue