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