Skip to content

Commit 26b28f7

Browse files
author
Hasnain Virk
committed
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.
1 parent 8363311 commit 26b28f7

File tree

8 files changed

+127
-29
lines changed

8 files changed

+127
-29
lines changed

features/lorawan/LoRaWANBase.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,19 @@ class LoRaWANBase {
389389
*
390390
*/
391391
virtual lorawan_status_t get_backoff_metadata(int& backoff) = 0;
392+
393+
/** Cancel outgoing transmission
394+
*
395+
* This API is used to cancel any outstanding transmission in the TX pipe.
396+
* If an event for transmission is not already queued at the end of backoff timer,
397+
* the system can cancel the outstanding outgoing packet. Otherwise, the system is
398+
* busy sending and can't be held back.
399+
*
400+
* @return LORAWAN_STATUS_OK if the sending is cancelled.
401+
* LORAWAN_STATUS_BUSY otherwise.
402+
*
403+
*/
404+
virtual lorawan_status_t cancel_sending(void) = 0;
392405
};
393406

394407
#endif /* LORAWAN_BASE_H_ */

features/lorawan/LoRaWANInterface.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,12 @@ int16_t LoRaWANInterface::send(uint8_t port, const uint8_t* data, uint16_t lengt
122122
return _lw_stack.handle_tx(port, data, length, flags);
123123
}
124124

125+
lorawan_status_t LoRaWANInterface::cancel_sending(void)
126+
{
127+
Lock lock(*this);
128+
return _lw_stack.stop_sending();
129+
}
130+
125131
lorawan_status_t LoRaWANInterface::get_tx_metadata(lorawan_tx_metadata& metadata)
126132
{
127133
Lock lock(*this);

features/lorawan/LoRaWANInterface.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,20 @@ class LoRaWANInterface: public LoRaWANBase {
488488
*/
489489
virtual lorawan_status_t get_backoff_metadata(int& backoff);
490490

491+
/** Cancel outgoing transmission
492+
*
493+
* This API is used to cancel any outstanding transmission in the TX pipe.
494+
* If an event for transmission is not already queued at the end of backoff timer,
495+
* the system can cancel the outstanding outgoing packet. Otherwise, the system is
496+
* busy sending and can't be held back. The system will not try to re-send if the
497+
* outgoing message was a CONFIRMED message even if the ack is not received.
498+
*
499+
* @return LORAWAN_STATUS_OK if the sending is cancelled.
500+
* LORAWAN_STATUS_BUSY otherwise.
501+
*
502+
*/
503+
virtual lorawan_status_t cancel_sending(void);
504+
491505
void lock(void) { _lw_stack.lock(); }
492506
void unlock(void) { _lw_stack.unlock(); }
493507

features/lorawan/LoRaWANStack.cpp

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,21 @@ lorawan_status_t LoRaWANStack::enable_adaptive_datarate(bool adr_enabled)
257257
return LORAWAN_STATUS_OK;
258258
}
259259

260+
lorawan_status_t LoRaWANStack::stop_sending(void)
261+
{
262+
if (_loramac.clear_tx_pipe() == LORAWAN_STATUS_OK) {
263+
if (_device_current_state == DEVICE_STATE_SENDING) {
264+
_ctrl_flags &= ~TX_DONE_FLAG;
265+
_ctrl_flags &= ~TX_ONGOING_FLAG;
266+
_loramac.set_tx_ongoing(false);
267+
_device_current_state = DEVICE_STATE_IDLE;
268+
return LORAWAN_STATUS_OK;
269+
}
270+
}
271+
272+
return LORAWAN_STATUS_BUSY;
273+
}
274+
260275
int16_t LoRaWANStack::handle_tx(const uint8_t port, const uint8_t* data,
261276
uint16_t length, uint8_t flags,
262277
bool null_allowed, bool allow_port_0)
@@ -517,8 +532,8 @@ void LoRaWANStack::process_transmission_timeout()
517532
// this is a fatal error and should not happen
518533
tr_debug("TX Timeout");
519534
_loramac.on_radio_tx_timeout();
520-
_ctrl_flags &= ~TX_ONGOING_FLAG;
521-
_ctrl_flags |= TX_DONE_FLAG;
535+
_ctrl_flags |= TX_ONGOING_FLAG;
536+
_ctrl_flags &= ~TX_DONE_FLAG;
522537
state_controller(DEVICE_STATE_STATUS_CHECK);
523538
state_machine_run_to_completion();
524539
}
@@ -576,12 +591,21 @@ void LoRaWANStack::process_reception(const uint8_t* const payload, uint16_t size
576591
if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED) {
577592
// if ack was not received, we will try retransmission after
578593
// ACK_TIMEOUT. handle_data_frame() already disables ACK_TIMEOUT timer
579-
// if ack was received
594+
// if ack was received. Otherwise, following method will be called in
595+
// LoRaMac.cpp, on_ack_timeout_timer_event().
580596
if (_loramac.get_mcps_indication()->is_ack_recvd) {
581597
tr_debug("Ack=OK, NbTrials=%d", _loramac.get_mcps_confirmation()->nb_retries);
582598
_loramac.post_process_mcps_req();
583599
_ctrl_flags |= TX_DONE_FLAG;
600+
_ctrl_flags &= ~TX_ONGOING_FLAG;
584601
state_controller(DEVICE_STATE_STATUS_CHECK);
602+
} else {
603+
if (!_loramac.continue_sending_process()) {
604+
tr_error("Retries exhausted for Class A device");
605+
_ctrl_flags &= ~TX_DONE_FLAG;
606+
_ctrl_flags |= TX_ONGOING_FLAG;
607+
state_controller(DEVICE_STATE_STATUS_CHECK);
608+
}
585609
}
586610
} else {
587611
// handle UNCONFIRMED, PROPRIETARY case here, RX slots were turned off due to
@@ -636,13 +660,19 @@ void LoRaWANStack::process_reception_timeout(bool is_timeout)
636660
* of UNCONFIRMED message after RX windows are done with.
637661
* For a CONFIRMED message, it means that we have not received
638662
* ack (actually nothing was received), and we should retransmit if we can.
663+
*
664+
* NOTE: This code block doesn't get hit for Class C as in Class C, RX2 timeout
665+
* never occurs.
639666
*/
640667
if (slot == RX_SLOT_WIN_2) {
641668
_loramac.post_process_mcps_req();
642669

643-
if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED
644-
&& _loramac.continue_sending_process()) {
645-
return;
670+
if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED) {
671+
if (_loramac.continue_sending_process()) {
672+
return;
673+
} else {
674+
tr_error("Retries exhausted for Class A device");
675+
}
646676
}
647677

648678
state_controller(DEVICE_STATE_STATUS_CHECK);
@@ -666,7 +696,6 @@ void LoRaWANStack::make_tx_metadata_available(void)
666696
void LoRaWANStack::make_rx_metadata_available(void)
667697
{
668698
_rx_metadata.stale = false;
669-
_rx_metadata.fpending_status = _loramac.get_mcps_indication()->fpending_status;
670699
_rx_metadata.rx_datarate = _loramac.get_mcps_indication()->rx_datarate;
671700
_rx_metadata.rssi = _loramac.get_mcps_indication()->rssi;
672701
_rx_metadata.snr = _loramac.get_mcps_indication()->snr;
@@ -972,7 +1001,7 @@ void LoRaWANStack::process_status_check_state()
9721001
// we may or may not have a successful UNCONFIRMED transmission
9731002
// here. In CONFIRMED case this block is invoked only
9741003
// when the MAX number of retries are exhausted, i.e., only error
975-
// case will fall here.
1004+
// case will fall here. Moreover, it will happen for Class A only.
9761005
_ctrl_flags &= ~TX_DONE_FLAG;
9771006
_ctrl_flags &= ~TX_ONGOING_FLAG;
9781007
_loramac.set_tx_ongoing(false);
@@ -981,8 +1010,11 @@ void LoRaWANStack::process_status_check_state()
9811010

9821011
} else if (_device_current_state == DEVICE_STATE_RECEIVING) {
9831012

984-
if (_ctrl_flags & TX_DONE_FLAG) {
1013+
if ((_ctrl_flags & TX_DONE_FLAG) || (_ctrl_flags & TX_ONGOING_FLAG)) {
9851014
// for CONFIRMED case, ack validity is already checked
1015+
// If it was a successful transmission, TX_ONGOING_FLAG will not be set.
1016+
// If it was indeed set, that means the device was in Class C mode and
1017+
// CONFIRMED transmission was in place and the ack retries maxed out.
9861018
_ctrl_flags &= ~TX_DONE_FLAG;
9871019
_ctrl_flags &= ~TX_ONGOING_FLAG;
9881020
_loramac.set_tx_ongoing(false);

features/lorawan/LoRaWANStack.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,16 @@ class LoRaWANStack: private mbed::NonCopyable<LoRaWANStack> {
415415
*/
416416
lorawan_status_t acquire_backoff_metadata(int& backoff);
417417

418+
/** Stops sending
419+
*
420+
* Stop sending any outstanding messages if they are not yet queued for
421+
* transmission, i.e., if the backoff timer is nhot elapsed yet.
422+
*
423+
* @return LORAWAN_STATUS_OK if the transmission is cancelled.
424+
* LORAWAN_STATUS_BUSY otherwise.
425+
*/
426+
lorawan_status_t stop_sending(void);
427+
418428
void lock(void) { _loramac.lock(); }
419429
void unlock(void) { _loramac.unlock(); }
420430

features/lorawan/lorastack/mac/LoRaMac.cpp

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ void LoRaMac::on_radio_tx_done(void)
208208
_lora_time.start(_params.timers.rx_window2_timer, _params.rx_window2_delay);
209209
}
210210

211-
if (_params.is_node_ack_requested == true) {
211+
if (_params.is_node_ack_requested) {
212212
_lora_time.start(_params.timers.ack_timeout_timer,
213213
_params.rx_window2_delay + _lora_phy.get_ack_timeout());
214214
}
@@ -1013,6 +1013,22 @@ int LoRaMac::get_backoff_timer_event_id(void)
10131013
return _params.timers.backoff_timer.timer_id;
10141014
}
10151015

1016+
lorawan_status_t LoRaMac::clear_tx_pipe(void)
1017+
{
1018+
// check if the event is not already queued
1019+
if (_ev_queue->time_left(get_backoff_timer_event_id()) > 0) {
1020+
_lora_time.stop(_params.timers.backoff_timer);
1021+
_lora_time.stop(_params.timers.ack_timeout_timer);
1022+
memset(_params.tx_buffer, 0, sizeof _params.tx_buffer);
1023+
_params.tx_buffer_len = 0;
1024+
reset_ongoing_tx(true);
1025+
tr_debug("Sending Cancelled");
1026+
return LORAWAN_STATUS_OK;
1027+
}
1028+
1029+
return LORAWAN_STATUS_BUSY;
1030+
}
1031+
10161032
lorawan_status_t LoRaMac::schedule_tx()
10171033
{
10181034
channel_selection_params_t next_channel;
@@ -1085,6 +1101,12 @@ lorawan_status_t LoRaMac::schedule_tx()
10851101
+ _params.rx_window2_config.window_offset;
10861102
}
10871103

1104+
// handle the ack to the server here so that if the sending was cancelled
1105+
// by the user in the backoff period, we would still ack the previous frame.
1106+
if (_params.is_srv_ack_requested) {
1107+
_params.is_srv_ack_requested = false;
1108+
}
1109+
10881110
return send_frame_on_channel(_params.channel);
10891111
}
10901112

@@ -1488,7 +1510,6 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr,
14881510
}
14891511

14901512
if (_params.is_srv_ack_requested == true) {
1491-
_params.is_srv_ack_requested = false;
14921513
fctrl->bits.ack = 1;
14931514
}
14941515

features/lorawan/lorastack/mac/LoRaMac.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,12 @@ class LoRaMac {
447447
*/
448448
int get_backoff_timer_event_id(void);
449449

450+
/**
451+
* Clears out the TX pipe by discarding any outgoing message if the backoff
452+
* timer is still running.
453+
*/
454+
lorawan_status_t clear_tx_pipe(void);
455+
450456
/**
451457
* These locks trample through to the upper layers and make
452458
* the stack thread safe.

features/lorawan/lorawan_types.h

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -350,55 +350,51 @@ typedef struct lora_channelplan {
350350
*/
351351
typedef struct {
352352
/**
353-
* A boolean to mark if the meta data is stale
353+
* The transmission time on air of the frame.
354354
*/
355-
bool stale;
355+
uint32_t tx_toa;
356356
/**
357357
* The uplink channel used for transmission.
358358
*/
359359
uint32_t channel;
360-
/**
361-
* The uplink datarate.
362-
*/
363-
uint8_t data_rate;
364360
/**
365361
* The transmission power.
366362
*/
367363
int8_t tx_power;
364+
/**
365+
* The uplink datarate.
366+
*/
367+
uint8_t data_rate;
368368
/**
369369
* Provides the number of retransmissions.
370370
*/
371371
uint8_t nb_retries;
372372
/**
373-
* The transmission time on air of the frame.
373+
* A boolean to mark if the meta data is stale
374374
*/
375-
uint32_t tx_toa;
375+
bool stale;
376376
} lorawan_tx_metadata;
377377

378378
/**
379379
* Meta-data collection for the received packet
380380
*/
381381
typedef struct {
382382
/**
383-
* A boolean to mark if the meta data is stale
383+
* The RSSI for the received packet.
384384
*/
385-
bool stale;
385+
int16_t rssi;
386386
/**
387387
* Data rate of reception
388388
*/
389389
uint8_t rx_datarate;
390-
/**
391-
* Frame pending status.
392-
*/
393-
uint8_t fpending_status;
394-
/**
395-
* The RSSI for the received packet.
396-
*/
397-
int16_t rssi;
398390
/**
399391
* The SNR for the received packet.
400392
*/
401393
uint8_t snr;
394+
/**
395+
* A boolean to mark if the meta data is stale
396+
*/
397+
bool stale;
402398
} lorawan_rx_metadata;
403399

404400
#endif /* MBED_LORAWAN_TYPES_H_ */

0 commit comments

Comments
 (0)