@@ -40,7 +40,7 @@ SPDX-License-Identifier: BSD-3-Clause
40
40
* Control flags for transient states
41
41
*/
42
42
#define IDLE_FLAG 0x00000000
43
- #define TX_ONGOING_FLAG 0x00000001
43
+ #define RETRY_EXHAUSTED_FLAG 0x00000001
44
44
#define MSG_RECVD_FLAG 0x00000002
45
45
#define CONNECTED_FLAG 0x00000004
46
46
#define USING_OTAA_FLAG 0x00000008
@@ -68,6 +68,7 @@ LoRaWANStack::LoRaWANStack()
68
68
_tx_metadata(),
69
69
_rx_metadata(),
70
70
_num_retry(1 ),
71
+ _qos_cnt(1 ),
71
72
_ctrl_flags(IDLE_FLAG),
72
73
_app_port(INVALID_PORT),
73
74
_link_check_requested(false ),
@@ -274,7 +275,6 @@ lorawan_status_t LoRaWANStack::stop_sending(void)
274
275
275
276
if (_loramac.clear_tx_pipe () == LORAWAN_STATUS_OK) {
276
277
_ctrl_flags &= ~TX_DONE_FLAG;
277
- _ctrl_flags &= ~TX_ONGOING_FLAG;
278
278
_loramac.set_tx_ongoing (false );
279
279
_device_current_state = DEVICE_STATE_IDLE;
280
280
return LORAWAN_STATUS_OK;
@@ -449,7 +449,8 @@ lorawan_status_t LoRaWANStack::set_device_class(const device_class_t &device_cla
449
449
if (device_class == CLASS_B) {
450
450
return LORAWAN_STATUS_UNSUPPORTED;
451
451
}
452
- _loramac.set_device_class (device_class, mbed::callback (this , &LoRaWANStack::handle_ack_expiry_for_class_c));
452
+ _loramac.set_device_class (device_class,
453
+ mbed::callback (this , &LoRaWANStack::post_process_tx_no_reception));
453
454
return LORAWAN_STATUS_OK;
454
455
}
455
456
@@ -559,7 +560,6 @@ void LoRaWANStack::process_transmission_timeout()
559
560
// this is a fatal error and should not happen
560
561
tr_debug (" TX Timeout" );
561
562
_loramac.on_radio_tx_timeout ();
562
- _ctrl_flags &= ~TX_ONGOING_FLAG;
563
563
_ctrl_flags &= ~TX_DONE_FLAG;
564
564
if (_device_current_state == DEVICE_STATE_JOINING) {
565
565
mlme_confirm_handler ();
@@ -573,41 +573,110 @@ void LoRaWANStack::process_transmission_timeout()
573
573
void LoRaWANStack::process_transmission (void )
574
574
{
575
575
tr_debug (" Transmission completed" );
576
- _loramac.on_radio_tx_done (_tx_timestamp);
577
-
578
- make_tx_metadata_available ();
579
576
580
577
if (_device_current_state == DEVICE_STATE_JOINING) {
581
578
_device_current_state = DEVICE_STATE_AWAITING_JOIN_ACCEPT;
582
579
}
583
580
584
581
if (_device_current_state == DEVICE_STATE_SENDING) {
585
582
if (_loramac.get_mcps_confirmation ()->req_type == MCPS_CONFIRMED) {
586
- _ctrl_flags |= TX_ONGOING_FLAG;
587
- _ctrl_flags &= ~TX_DONE_FLAG;
588
583
tr_debug (" Awaiting ACK" );
589
584
_device_current_state = DEVICE_STATE_AWAITING_ACK;
590
- } else if (_loramac.get_device_class () == CLASS_A) {
591
- // Class A unconfirmed message sent, TX_DONE event will be sent to
592
- // application when RX2 windows is elapsed, i.e., in process_reception_timeout()
593
- _ctrl_flags &= ~TX_ONGOING_FLAG;
585
+ }
586
+ }
587
+
588
+ _loramac.on_radio_tx_done (_tx_timestamp);
589
+ }
590
+
591
+ void LoRaWANStack::post_process_tx_with_reception ()
592
+ {
593
+ if (_loramac.get_mcps_confirmation ()->req_type == MCPS_CONFIRMED) {
594
+ // if ack was not received, we will try retransmission after
595
+ // ACK_TIMEOUT. handle_data_frame() already disables ACK_TIMEOUT timer
596
+ // if ack was received. Otherwise, following method will be called in
597
+ // LoRaMac.cpp, on_ack_timeout_timer_event().
598
+ if (_loramac.get_mcps_indication ()->is_ack_recvd ) {
594
599
_ctrl_flags |= TX_DONE_FLAG;
595
- } else if (_loramac.get_device_class () == CLASS_C) {
596
- // In Class C, reception timeout never happens, so we handle the state
597
- // progression for TX_DONE in UNCONFIRMED case here
600
+ _ctrl_flags &= ~RETRY_EXHAUSTED_FLAG;
601
+ tr_debug (" Ack=OK, NbTrials=%d" ,
602
+ _loramac.get_mcps_confirmation ()->nb_retries );
603
+ _loramac.post_process_mcps_req ();
604
+ make_tx_metadata_available ();
605
+ state_controller (DEVICE_STATE_STATUS_CHECK);
606
+ } else {
607
+ if (!_loramac.continue_sending_process ()
608
+ && _loramac.get_current_slot () != RX_SLOT_WIN_1) {
609
+ tr_error (" Retries exhausted for Class %s device" ,
610
+ _loramac.get_device_class () == CLASS_A ? " A" : " C" );
611
+ _ctrl_flags &= ~TX_DONE_FLAG;
612
+ _ctrl_flags |= RETRY_EXHAUSTED_FLAG;
613
+ state_controller (DEVICE_STATE_STATUS_CHECK);
614
+ }
615
+ }
616
+ } else {
617
+ // handle UNCONFIRMED case here, RX slots were turned off due to
618
+ // valid packet reception.
619
+ uint8_t prev_QOS_level = _loramac.get_prev_QOS_level ();
620
+ uint8_t QOS_level = _loramac.get_QOS_level ();
621
+
622
+ // We will not apply QOS on the post-processing of the previous
623
+ // outgoing message as we would have received QOS instruction in response
624
+ // to that particular message
625
+ if (QOS_level > LORAWAN_DEFAULT_QOS && _qos_cnt < QOS_level
626
+ && (prev_QOS_level == QOS_level)) {
627
+ _ctrl_flags &= ~TX_DONE_FLAG;
628
+ const int ret = _queue->call (this , &LoRaWANStack::state_controller,
629
+ DEVICE_STATE_SCHEDULING);
630
+ MBED_ASSERT (ret != 0 );
631
+ (void ) ret;
632
+ _qos_cnt++;
633
+ tr_info (" QOS: repeated transmission #%d queued" , _qos_cnt);
634
+ } else {
598
635
_loramac.post_process_mcps_req ();
636
+ _ctrl_flags |= TX_DONE_FLAG;
637
+ make_tx_metadata_available ();
599
638
state_controller (DEVICE_STATE_STATUS_CHECK);
600
- state_machine_run_to_completion ();
601
639
}
602
640
}
603
641
}
604
642
605
- void LoRaWANStack::handle_ack_expiry_for_class_c ( void )
643
+ void LoRaWANStack::post_process_tx_no_reception ( )
606
644
{
607
- _ctrl_flags &= ~TX_DONE_FLAG;
608
- _ctrl_flags |= TX_ONGOING_FLAG;
609
- tr_error (" Retries exhausted for Class C device" );
645
+ if (_loramac.get_mcps_confirmation ()->req_type == MCPS_CONFIRMED) {
646
+ if (_loramac.continue_sending_process ()) {
647
+ _ctrl_flags &= ~TX_DONE_FLAG;
648
+ _ctrl_flags &= ~RETRY_EXHAUSTED_FLAG;
649
+ return ;
650
+ }
651
+
652
+ tr_error (" Retries exhausted for Class %s device" ,
653
+ _loramac.get_device_class () == CLASS_A ? " A" : " C" );
654
+ _ctrl_flags &= ~TX_DONE_FLAG;
655
+ _ctrl_flags |= RETRY_EXHAUSTED_FLAG;
656
+ } else {
657
+ _ctrl_flags |= TX_DONE_FLAG;
658
+
659
+ uint8_t prev_QOS_level = _loramac.get_prev_QOS_level ();
660
+ uint8_t QOS_level = _loramac.get_QOS_level ();
661
+
662
+ if (QOS_level > LORAWAN_DEFAULT_QOS && (prev_QOS_level == QOS_level)) {
663
+ if (_qos_cnt < QOS_level) {
664
+ const int ret = _queue->call (this , &LoRaWANStack::state_controller,
665
+ DEVICE_STATE_SCHEDULING);
666
+ MBED_ASSERT (ret != 0 );
667
+ (void )ret;
668
+ _qos_cnt++;
669
+ tr_info (" QOS: repeated transmission #%d queued" , _qos_cnt);
670
+ state_machine_run_to_completion ();
671
+ return ;
672
+ }
673
+ }
674
+ }
675
+
676
+ _loramac.post_process_mcps_req ();
677
+ make_tx_metadata_available ();
610
678
state_controller (DEVICE_STATE_STATUS_CHECK);
679
+ state_machine_run_to_completion ();
611
680
}
612
681
613
682
void LoRaWANStack::handle_scheduling_failure (void )
@@ -617,16 +686,18 @@ void LoRaWANStack::handle_scheduling_failure(void)
617
686
state_machine_run_to_completion ();
618
687
}
619
688
689
+
620
690
void LoRaWANStack::process_reception (const uint8_t *const payload, uint16_t size,
621
691
int16_t rssi, int8_t snr)
622
692
{
623
693
_device_current_state = DEVICE_STATE_RECEIVING;
694
+
624
695
_ctrl_flags &= ~MSG_RECVD_FLAG;
696
+ _ctrl_flags &= ~TX_DONE_FLAG;
697
+ _ctrl_flags &= ~RETRY_EXHAUSTED_FLAG;
625
698
626
699
_loramac.on_radio_rx_done (payload, size, rssi, snr);
627
700
628
- make_rx_metadata_available ();
629
-
630
701
if (_loramac.get_mlme_confirmation ()->pending ) {
631
702
_loramac.post_process_mlme_request ();
632
703
mlme_confirm_handler ();
@@ -642,36 +713,10 @@ void LoRaWANStack::process_reception(const uint8_t *const payload, uint16_t size
642
713
return ;
643
714
}
644
715
645
- // if the outgoing message was of CONFIRMED type
646
- if (_loramac.get_mcps_confirmation ()->req_type == MCPS_CONFIRMED) {
647
- // if ack was not received, we will try retransmission after
648
- // ACK_TIMEOUT. handle_data_frame() already disables ACK_TIMEOUT timer
649
- // if ack was received. Otherwise, following method will be called in
650
- // LoRaMac.cpp, on_ack_timeout_timer_event().
651
- if (_loramac.get_mcps_indication ()->is_ack_recvd ) {
652
- tr_debug (" Ack=OK, NbTrials=%d" ,
653
- _loramac.get_mcps_confirmation ()->nb_retries );
654
- _loramac.post_process_mcps_req ();
655
- _ctrl_flags |= TX_DONE_FLAG;
656
- _ctrl_flags &= ~TX_ONGOING_FLAG;
657
- state_controller (DEVICE_STATE_STATUS_CHECK);
658
- } else {
659
- if (!_loramac.continue_sending_process () &&
660
- _loramac.get_current_slot () != RX_SLOT_WIN_1) {
661
- tr_error (" Retries exhausted for Class A device" );
662
- _ctrl_flags &= ~TX_DONE_FLAG;
663
- _ctrl_flags |= TX_ONGOING_FLAG;
664
- state_controller (DEVICE_STATE_STATUS_CHECK);
665
- }
666
- }
667
- } else if (_loramac.get_device_class () == CLASS_A) {
668
- // handle UNCONFIRMED case here, RX slots were turned off due to
669
- // valid packet reception. For Class C, an outgoing UNCONFIRMED message
670
- // gets its handling in process_transmission.
671
- _loramac.post_process_mcps_req ();
672
- _ctrl_flags |= TX_DONE_FLAG;
673
- state_controller (DEVICE_STATE_STATUS_CHECK);
674
- }
716
+ make_rx_metadata_available ();
717
+
718
+ // Post process transmission in response to the reception
719
+ post_process_tx_with_reception ();
675
720
676
721
// handle any pending MCPS indication
677
722
if (_loramac.get_mcps_indication ()->pending ) {
@@ -680,15 +725,13 @@ void LoRaWANStack::process_reception(const uint8_t *const payload, uint16_t size
680
725
state_controller (DEVICE_STATE_STATUS_CHECK);
681
726
}
682
727
683
- // change the state only if a TX cycle completes for Class A
684
- // For class C it's not needed as it will already be in receiving
685
- // state, no matter if the TX cycle completed or not.
686
- if (!(_ctrl_flags & TX_ONGOING_FLAG)) {
687
- // we are done here, update the state
728
+ // complete the cycle only if TX_DONE_FLAG is set
729
+ if (_ctrl_flags & TX_DONE_FLAG) {
688
730
state_machine_run_to_completion ();
689
731
}
690
732
691
- if (_loramac.get_mlme_indication ()->pending ) {
733
+ // suppress auto uplink if another auto-uplink is in AWAITING_ACK state
734
+ if (_loramac.get_mlme_indication ()->pending && !_automatic_uplink_ongoing) {
692
735
tr_debug (" MLME Indication pending" );
693
736
_loramac.post_process_mlme_ind ();
694
737
tr_debug (" Immediate Uplink requested" );
@@ -724,18 +767,7 @@ void LoRaWANStack::process_reception_timeout(bool is_timeout)
724
767
* never occurs.
725
768
*/
726
769
if (slot == RX_SLOT_WIN_2) {
727
- _loramac.post_process_mcps_req ();
728
-
729
- if (_loramac.get_mcps_confirmation ()->req_type == MCPS_CONFIRMED) {
730
- if (_loramac.continue_sending_process ()) {
731
- return ;
732
- } else {
733
- tr_error (" Retries exhausted for Class A device" );
734
- }
735
- }
736
-
737
- state_controller (DEVICE_STATE_STATUS_CHECK);
738
- state_machine_run_to_completion ();
770
+ post_process_tx_no_reception ();
739
771
}
740
772
}
741
773
@@ -1024,11 +1056,15 @@ void LoRaWANStack::mcps_indication_handler()
1024
1056
|| (_loramac.get_device_class () == CLASS_C
1025
1057
&& mcps_indication->type == MCPS_CONFIRMED)) {
1026
1058
#if (MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE)
1027
- tr_debug (" Sending empty uplink message..." );
1028
- _automatic_uplink_ongoing = true ;
1029
- const int ret = _queue->call (this , &LoRaWANStack::send_automatic_uplink_message, mcps_indication->port );
1030
- MBED_ASSERT (ret != 0 );
1031
- (void )ret;
1059
+ // Do not queue an automatic uplink of there is one already outgoing
1060
+ // This means we have not received an ack for the previous automatic uplink
1061
+ if (!_automatic_uplink_ongoing) {
1062
+ tr_debug (" Sending empty uplink message..." );
1063
+ _automatic_uplink_ongoing = true ;
1064
+ const int ret = _queue->call (this , &LoRaWANStack::send_automatic_uplink_message, mcps_indication->port );
1065
+ MBED_ASSERT (ret != 0 );
1066
+ (void )ret;
1067
+ }
1032
1068
#else
1033
1069
send_event_to_application (UPLINK_REQUIRED);
1034
1070
#endif
@@ -1082,8 +1118,7 @@ void LoRaWANStack::process_shutdown_state(lorawan_status_t &op_status)
1082
1118
_lw_session.active = false ;
1083
1119
_device_current_state = DEVICE_STATE_SHUTDOWN;
1084
1120
op_status = LORAWAN_STATUS_DEVICE_OFF;
1085
- _ctrl_flags &= ~CONNECTED_FLAG;
1086
- _ctrl_flags &= ~CONN_IN_PROGRESS_FLAG;
1121
+ _ctrl_flags = 0 ;
1087
1122
send_event_to_application (DISCONNECTED);
1088
1123
}
1089
1124
@@ -1099,20 +1134,15 @@ void LoRaWANStack::process_status_check_state()
1099
1134
// Another possibility is the case when the stack fails to schedule a
1100
1135
// deferred transmission and a scheduling failure handler is invoked.
1101
1136
_ctrl_flags &= ~TX_DONE_FLAG;
1102
- _ctrl_flags &= ~TX_ONGOING_FLAG;
1103
1137
_loramac.set_tx_ongoing (false );
1104
1138
_loramac.reset_ongoing_tx ();
1105
1139
mcps_confirm_handler ();
1106
1140
1107
1141
} else if (_device_current_state == DEVICE_STATE_RECEIVING) {
1108
1142
1109
- if ((_ctrl_flags & TX_DONE_FLAG) || (_ctrl_flags & TX_ONGOING_FLAG)) {
1110
- // for CONFIRMED case, ack validity is already checked
1111
- // If it was a successful transmission, TX_ONGOING_FLAG will not be set.
1112
- // If it was indeed set, that means the device was in Class C mode and
1113
- // CONFIRMED transmission was in place and the ack retries maxed out.
1143
+ if ((_ctrl_flags & TX_DONE_FLAG) || (_ctrl_flags & RETRY_EXHAUSTED_FLAG)) {
1114
1144
_ctrl_flags &= ~TX_DONE_FLAG;
1115
- _ctrl_flags &= ~TX_ONGOING_FLAG ;
1145
+ _ctrl_flags &= ~RETRY_EXHAUSTED_FLAG ;
1116
1146
_loramac.set_tx_ongoing (false );
1117
1147
_loramac.reset_ongoing_tx ();
1118
1148
// if an automatic uplink is ongoing, we should not send a TX_DONE
@@ -1144,7 +1174,6 @@ void LoRaWANStack::process_scheduling_state(lorawan_status_t &op_status)
1144
1174
1145
1175
op_status = _loramac.send_ongoing_tx ();
1146
1176
if (op_status == LORAWAN_STATUS_OK) {
1147
- _ctrl_flags |= TX_ONGOING_FLAG;
1148
1177
_ctrl_flags &= ~TX_DONE_FLAG;
1149
1178
_loramac.set_tx_ongoing (true );
1150
1179
_device_current_state = DEVICE_STATE_SENDING;
0 commit comments