@@ -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;
@@ -453,7 +453,8 @@ lorawan_status_t LoRaWANStack::set_device_class(const device_class_t &device_cla
453
453
if (device_class == CLASS_B) {
454
454
return LORAWAN_STATUS_UNSUPPORTED;
455
455
}
456
- _loramac.set_device_class (device_class, mbed::callback (this , &LoRaWANStack::handle_ack_expiry_for_class_c));
456
+ _loramac.set_device_class (device_class,
457
+ mbed::callback (this , &LoRaWANStack::post_process_tx_no_reception));
457
458
return LORAWAN_STATUS_OK;
458
459
}
459
460
@@ -563,7 +564,6 @@ void LoRaWANStack::process_transmission_timeout()
563
564
// this is a fatal error and should not happen
564
565
tr_debug (" TX Timeout" );
565
566
_loramac.on_radio_tx_timeout ();
566
- _ctrl_flags &= ~TX_ONGOING_FLAG;
567
567
_ctrl_flags &= ~TX_DONE_FLAG;
568
568
if (_device_current_state == DEVICE_STATE_JOINING) {
569
569
mlme_confirm_handler ();
@@ -579,39 +579,108 @@ void LoRaWANStack::process_transmission(void)
579
579
tr_debug (" Transmission completed" );
580
580
_loramac.on_radio_tx_done (_tx_timestamp);
581
581
582
- make_tx_metadata_available ();
583
-
584
582
if (_device_current_state == DEVICE_STATE_JOINING) {
585
583
_device_current_state = DEVICE_STATE_AWAITING_JOIN_ACCEPT;
586
584
}
587
585
588
586
if (_device_current_state == DEVICE_STATE_SENDING) {
589
587
if (_loramac.get_mcps_confirmation ()->req_type == MCPS_CONFIRMED) {
590
- _ctrl_flags |= TX_ONGOING_FLAG;
591
- _ctrl_flags &= ~TX_DONE_FLAG;
592
588
tr_debug (" Awaiting ACK" );
593
589
_device_current_state = DEVICE_STATE_AWAITING_ACK;
594
- } else if (_loramac.get_device_class () == CLASS_A) {
595
- // Class A unconfirmed message sent, TX_DONE event will be sent to
596
- // application when RX2 windows is elapsed, i.e., in process_reception_timeout()
597
- _ctrl_flags &= ~TX_ONGOING_FLAG;
590
+ }
591
+ }
592
+ }
593
+
594
+ void LoRaWANStack::post_process_tx_with_reception ()
595
+ {
596
+ if (_loramac.get_mcps_confirmation ()->req_type == MCPS_CONFIRMED) {
597
+ // if ack was not received, we will try retransmission after
598
+ // ACK_TIMEOUT. handle_data_frame() already disables ACK_TIMEOUT timer
599
+ // if ack was received. Otherwise, following method will be called in
600
+ // LoRaMac.cpp, on_ack_timeout_timer_event().
601
+ if (_loramac.get_mcps_indication ()->is_ack_recvd ) {
598
602
_ctrl_flags |= TX_DONE_FLAG;
599
- } else if (_loramac.get_device_class () == CLASS_C) {
600
- // In Class C, reception timeout never happens, so we handle the state
601
- // progression for TX_DONE in UNCONFIRMED case here
603
+ _ctrl_flags &= ~RETRY_EXHAUSTED_FLAG;
604
+ tr_debug (" Ack=OK, NbTrials=%d" ,
605
+ _loramac.get_mcps_confirmation ()->nb_retries );
606
+ _loramac.post_process_mcps_req ();
607
+ make_tx_metadata_available ();
608
+ state_controller (DEVICE_STATE_STATUS_CHECK);
609
+ } else {
610
+ if (!_loramac.continue_sending_process ()
611
+ && _loramac.get_current_slot () != RX_SLOT_WIN_1) {
612
+ tr_error (" Retries exhausted for Class %s device" ,
613
+ _loramac.get_device_class () == CLASS_A ? " A" : " C" );
614
+ _ctrl_flags &= ~TX_DONE_FLAG;
615
+ _ctrl_flags |= RETRY_EXHAUSTED_FLAG;
616
+ state_controller (DEVICE_STATE_STATUS_CHECK);
617
+ }
618
+ }
619
+ } else {
620
+ // handle UNCONFIRMED case here, RX slots were turned off due to
621
+ // valid packet reception.
622
+ uint8_t prev_QOS_level = _loramac.get_prev_QOS_level ();
623
+ uint8_t QOS_level = _loramac.get_QOS_level ();
624
+
625
+ // We will not apply QOS on the post-processing of the previous
626
+ // outgoing message as we would have received QOS instruction in response
627
+ // to that particular message
628
+ if (QOS_level > LORAWAN_DEFAULT_QOS && _qos_cnt < QOS_level
629
+ && (prev_QOS_level == QOS_level)) {
630
+ _ctrl_flags &= ~TX_DONE_FLAG;
631
+ const int ret = _queue->call (this , &LoRaWANStack::state_controller,
632
+ DEVICE_STATE_SCHEDULING);
633
+ MBED_ASSERT (ret != 0 );
634
+ (void ) ret;
635
+ _qos_cnt++;
636
+ tr_info (" QOS: repeated transmission #%d queued" , _qos_cnt);
637
+ } else {
602
638
_loramac.post_process_mcps_req ();
639
+ _ctrl_flags |= TX_DONE_FLAG;
640
+ make_tx_metadata_available ();
603
641
state_controller (DEVICE_STATE_STATUS_CHECK);
604
- state_machine_run_to_completion ();
605
642
}
606
643
}
607
644
}
608
645
609
- void LoRaWANStack::handle_ack_expiry_for_class_c ( void )
646
+ void LoRaWANStack::post_process_tx_no_reception ( )
610
647
{
611
- _ctrl_flags &= ~TX_DONE_FLAG;
612
- _ctrl_flags |= TX_ONGOING_FLAG;
613
- tr_error (" Retries exhausted for Class C device" );
648
+ if (_loramac.get_mcps_confirmation ()->req_type == MCPS_CONFIRMED) {
649
+ _loramac.post_process_mcps_req ();
650
+ if (_loramac.continue_sending_process ()) {
651
+ _ctrl_flags &= ~TX_DONE_FLAG;
652
+ _ctrl_flags &= ~RETRY_EXHAUSTED_FLAG;
653
+ return ;
654
+ }
655
+
656
+ tr_error (" Retries exhausted for Class %s device" ,
657
+ _loramac.get_device_class () == CLASS_A ? " A" : " C" );
658
+ _ctrl_flags &= ~TX_DONE_FLAG;
659
+ _ctrl_flags |= RETRY_EXHAUSTED_FLAG;
660
+ } else {
661
+ _ctrl_flags |= TX_DONE_FLAG;
662
+
663
+ uint8_t prev_QOS_level = _loramac.get_prev_QOS_level ();
664
+ uint8_t QOS_level = _loramac.get_QOS_level ();
665
+
666
+ if (QOS_level > LORAWAN_DEFAULT_QOS && (prev_QOS_level == QOS_level)) {
667
+ if (_qos_cnt < QOS_level) {
668
+ const int ret = _queue->call (this , &LoRaWANStack::state_controller,
669
+ DEVICE_STATE_SCHEDULING);
670
+ MBED_ASSERT (ret != 0 );
671
+ (void )ret;
672
+ _qos_cnt++;
673
+ tr_info (" QOS: repeated transmission #%d queued" , _qos_cnt);
674
+ state_machine_run_to_completion ();
675
+ return ;
676
+ }
677
+ }
678
+ }
679
+
680
+ _loramac.post_process_mcps_req ();
681
+ make_tx_metadata_available ();
614
682
state_controller (DEVICE_STATE_STATUS_CHECK);
683
+ state_machine_run_to_completion ();
615
684
}
616
685
617
686
void LoRaWANStack::handle_scheduling_failure (void )
@@ -621,16 +690,18 @@ void LoRaWANStack::handle_scheduling_failure(void)
621
690
state_machine_run_to_completion ();
622
691
}
623
692
693
+
624
694
void LoRaWANStack::process_reception (const uint8_t *const payload, uint16_t size,
625
695
int16_t rssi, int8_t snr)
626
696
{
627
697
_device_current_state = DEVICE_STATE_RECEIVING;
698
+
628
699
_ctrl_flags &= ~MSG_RECVD_FLAG;
700
+ _ctrl_flags &= ~TX_DONE_FLAG;
701
+ _ctrl_flags &= ~RETRY_EXHAUSTED_FLAG;
629
702
630
703
_loramac.on_radio_rx_done (payload, size, rssi, snr);
631
704
632
- make_rx_metadata_available ();
633
-
634
705
if (_loramac.get_mlme_confirmation ()->pending ) {
635
706
_loramac.post_process_mlme_request ();
636
707
mlme_confirm_handler ();
@@ -646,36 +717,10 @@ void LoRaWANStack::process_reception(const uint8_t *const payload, uint16_t size
646
717
return ;
647
718
}
648
719
649
- // if the outgoing message was of CONFIRMED type
650
- if (_loramac.get_mcps_confirmation ()->req_type == MCPS_CONFIRMED) {
651
- // if ack was not received, we will try retransmission after
652
- // ACK_TIMEOUT. handle_data_frame() already disables ACK_TIMEOUT timer
653
- // if ack was received. Otherwise, following method will be called in
654
- // LoRaMac.cpp, on_ack_timeout_timer_event().
655
- if (_loramac.get_mcps_indication ()->is_ack_recvd ) {
656
- tr_debug (" Ack=OK, NbTrials=%d" ,
657
- _loramac.get_mcps_confirmation ()->nb_retries );
658
- _loramac.post_process_mcps_req ();
659
- _ctrl_flags |= TX_DONE_FLAG;
660
- _ctrl_flags &= ~TX_ONGOING_FLAG;
661
- state_controller (DEVICE_STATE_STATUS_CHECK);
662
- } else {
663
- if (!_loramac.continue_sending_process () &&
664
- _loramac.get_current_slot () != RX_SLOT_WIN_1) {
665
- tr_error (" Retries exhausted for Class A device" );
666
- _ctrl_flags &= ~TX_DONE_FLAG;
667
- _ctrl_flags |= TX_ONGOING_FLAG;
668
- state_controller (DEVICE_STATE_STATUS_CHECK);
669
- }
670
- }
671
- } else if (_loramac.get_device_class () == CLASS_A) {
672
- // handle UNCONFIRMED case here, RX slots were turned off due to
673
- // valid packet reception. For Class C, an outgoing UNCONFIRMED message
674
- // gets its handling in process_transmission.
675
- _loramac.post_process_mcps_req ();
676
- _ctrl_flags |= TX_DONE_FLAG;
677
- state_controller (DEVICE_STATE_STATUS_CHECK);
678
- }
720
+ make_rx_metadata_available ();
721
+
722
+ // Post process transmission in response to the reception
723
+ post_process_tx_with_reception ();
679
724
680
725
// handle any pending MCPS indication
681
726
if (_loramac.get_mcps_indication ()->pending ) {
@@ -684,11 +729,8 @@ void LoRaWANStack::process_reception(const uint8_t *const payload, uint16_t size
684
729
state_controller (DEVICE_STATE_STATUS_CHECK);
685
730
}
686
731
687
- // change the state only if a TX cycle completes for Class A
688
- // For class C it's not needed as it will already be in receiving
689
- // state, no matter if the TX cycle completed or not.
690
- if (!(_ctrl_flags & TX_ONGOING_FLAG)) {
691
- // we are done here, update the state
732
+ // complete the cycle only if TX_DONE_FLAG is set
733
+ if (_ctrl_flags & TX_DONE_FLAG) {
692
734
state_machine_run_to_completion ();
693
735
}
694
736
@@ -729,18 +771,7 @@ void LoRaWANStack::process_reception_timeout(bool is_timeout)
729
771
* never occurs.
730
772
*/
731
773
if (slot == RX_SLOT_WIN_2) {
732
- _loramac.post_process_mcps_req ();
733
-
734
- if (_loramac.get_mcps_confirmation ()->req_type == MCPS_CONFIRMED) {
735
- if (_loramac.continue_sending_process ()) {
736
- return ;
737
- } else {
738
- tr_error (" Retries exhausted for Class A device" );
739
- }
740
- }
741
-
742
- state_controller (DEVICE_STATE_STATUS_CHECK);
743
- state_machine_run_to_completion ();
774
+ post_process_tx_no_reception ();
744
775
}
745
776
}
746
777
@@ -1091,8 +1122,7 @@ void LoRaWANStack::process_shutdown_state(lorawan_status_t &op_status)
1091
1122
_lw_session.active = false ;
1092
1123
_device_current_state = DEVICE_STATE_SHUTDOWN;
1093
1124
op_status = LORAWAN_STATUS_DEVICE_OFF;
1094
- _ctrl_flags &= ~CONNECTED_FLAG;
1095
- _ctrl_flags &= ~CONN_IN_PROGRESS_FLAG;
1125
+ _ctrl_flags = 0 ;
1096
1126
send_event_to_application (DISCONNECTED);
1097
1127
}
1098
1128
@@ -1108,20 +1138,15 @@ void LoRaWANStack::process_status_check_state()
1108
1138
// Another possibility is the case when the stack fails to schedule a
1109
1139
// deferred transmission and a scheduling failure handler is invoked.
1110
1140
_ctrl_flags &= ~TX_DONE_FLAG;
1111
- _ctrl_flags &= ~TX_ONGOING_FLAG;
1112
1141
_loramac.set_tx_ongoing (false );
1113
1142
_loramac.reset_ongoing_tx ();
1114
1143
mcps_confirm_handler ();
1115
1144
1116
1145
} else if (_device_current_state == DEVICE_STATE_RECEIVING) {
1117
1146
1118
- if ((_ctrl_flags & TX_DONE_FLAG) || (_ctrl_flags & TX_ONGOING_FLAG)) {
1119
- // for CONFIRMED case, ack validity is already checked
1120
- // If it was a successful transmission, TX_ONGOING_FLAG will not be set.
1121
- // If it was indeed set, that means the device was in Class C mode and
1122
- // CONFIRMED transmission was in place and the ack retries maxed out.
1147
+ if ((_ctrl_flags & TX_DONE_FLAG) || (_ctrl_flags & RETRY_EXHAUSTED_FLAG)) {
1123
1148
_ctrl_flags &= ~TX_DONE_FLAG;
1124
- _ctrl_flags &= ~TX_ONGOING_FLAG ;
1149
+ _ctrl_flags &= ~RETRY_EXHAUSTED_FLAG ;
1125
1150
_loramac.set_tx_ongoing (false );
1126
1151
_loramac.reset_ongoing_tx ();
1127
1152
// if an automatic uplink is ongoing, we should not send a TX_DONE
@@ -1153,7 +1178,6 @@ void LoRaWANStack::process_scheduling_state(lorawan_status_t &op_status)
1153
1178
1154
1179
op_status = _loramac.send_ongoing_tx ();
1155
1180
if (op_status == LORAWAN_STATUS_OK) {
1156
- _ctrl_flags |= TX_ONGOING_FLAG;
1157
1181
_ctrl_flags &= ~TX_DONE_FLAG;
1158
1182
_loramac.set_tx_ongoing (true );
1159
1183
_device_current_state = DEVICE_STATE_SENDING;
0 commit comments