@@ -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 RETRY_EXHAUSTED_FLAG 0x00000001
43
+ #define TX_ONGOING_FLAG 0x00000001
44
44
#define MSG_RECVD_FLAG 0x00000002
45
45
#define CONNECTED_FLAG 0x00000004
46
46
#define USING_OTAA_FLAG 0x00000008
@@ -68,7 +68,6 @@ LoRaWANStack::LoRaWANStack()
68
68
_tx_metadata(),
69
69
_rx_metadata(),
70
70
_num_retry(1 ),
71
- _qos_cnt(1 ),
72
71
_ctrl_flags(IDLE_FLAG),
73
72
_app_port(INVALID_PORT),
74
73
_link_check_requested(false ),
@@ -275,6 +274,7 @@ lorawan_status_t LoRaWANStack::stop_sending(void)
275
274
276
275
if (_loramac.clear_tx_pipe () == LORAWAN_STATUS_OK) {
277
276
_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,8 +449,7 @@ 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,
453
- mbed::callback (this , &LoRaWANStack::post_process_tx_no_reception));
452
+ _loramac.set_device_class (device_class, mbed::callback (this , &LoRaWANStack::handle_ack_expiry_for_class_c));
454
453
return LORAWAN_STATUS_OK;
455
454
}
456
455
@@ -560,6 +559,7 @@ void LoRaWANStack::process_transmission_timeout()
560
559
// this is a fatal error and should not happen
561
560
tr_debug (" TX Timeout" );
562
561
_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,110 +573,41 @@ 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 ();
576
579
577
580
if (_device_current_state == DEVICE_STATE_JOINING) {
578
581
_device_current_state = DEVICE_STATE_AWAITING_JOIN_ACCEPT;
579
582
}
580
583
581
584
if (_device_current_state == DEVICE_STATE_SENDING) {
582
585
if (_loramac.get_mcps_confirmation ()->req_type == MCPS_CONFIRMED) {
586
+ _ctrl_flags |= TX_ONGOING_FLAG;
587
+ _ctrl_flags &= ~TX_DONE_FLAG;
583
588
tr_debug (" Awaiting ACK" );
584
589
_device_current_state = DEVICE_STATE_AWAITING_ACK;
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 ) {
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;
599
594
_ctrl_flags |= TX_DONE_FLAG;
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 {
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
635
598
_loramac.post_process_mcps_req ();
636
- _ctrl_flags |= TX_DONE_FLAG;
637
- make_tx_metadata_available ();
638
599
state_controller (DEVICE_STATE_STATUS_CHECK);
600
+ state_machine_run_to_completion ();
639
601
}
640
602
}
641
603
}
642
604
643
- void LoRaWANStack::post_process_tx_no_reception ( )
605
+ void LoRaWANStack::handle_ack_expiry_for_class_c ( void )
644
606
{
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 ();
607
+ _ctrl_flags &= ~TX_DONE_FLAG;
608
+ _ctrl_flags |= TX_ONGOING_FLAG;
609
+ tr_error (" Retries exhausted for Class C device" );
678
610
state_controller (DEVICE_STATE_STATUS_CHECK);
679
- state_machine_run_to_completion ();
680
611
}
681
612
682
613
void LoRaWANStack::handle_scheduling_failure (void )
@@ -686,18 +617,16 @@ void LoRaWANStack::handle_scheduling_failure(void)
686
617
state_machine_run_to_completion ();
687
618
}
688
619
689
-
690
620
void LoRaWANStack::process_reception (const uint8_t *const payload, uint16_t size,
691
621
int16_t rssi, int8_t snr)
692
622
{
693
623
_device_current_state = DEVICE_STATE_RECEIVING;
694
-
695
624
_ctrl_flags &= ~MSG_RECVD_FLAG;
696
- _ctrl_flags &= ~TX_DONE_FLAG;
697
- _ctrl_flags &= ~RETRY_EXHAUSTED_FLAG;
698
625
699
626
_loramac.on_radio_rx_done (payload, size, rssi, snr);
700
627
628
+ make_rx_metadata_available ();
629
+
701
630
if (_loramac.get_mlme_confirmation ()->pending ) {
702
631
_loramac.post_process_mlme_request ();
703
632
mlme_confirm_handler ();
@@ -713,10 +642,36 @@ void LoRaWANStack::process_reception(const uint8_t *const payload, uint16_t size
713
642
return ;
714
643
}
715
644
716
- make_rx_metadata_available ();
717
-
718
- // Post process transmission in response to the reception
719
- post_process_tx_with_reception ();
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
+ }
720
675
721
676
// handle any pending MCPS indication
722
677
if (_loramac.get_mcps_indication ()->pending ) {
@@ -725,13 +680,15 @@ void LoRaWANStack::process_reception(const uint8_t *const payload, uint16_t size
725
680
state_controller (DEVICE_STATE_STATUS_CHECK);
726
681
}
727
682
728
- // complete the cycle only if TX_DONE_FLAG is set
729
- if (_ctrl_flags & TX_DONE_FLAG) {
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
730
688
state_machine_run_to_completion ();
731
689
}
732
690
733
- // suppress auto uplink if another auto-uplink is in AWAITING_ACK state
734
- if (_loramac.get_mlme_indication ()->pending && !_automatic_uplink_ongoing) {
691
+ if (_loramac.get_mlme_indication ()->pending ) {
735
692
tr_debug (" MLME Indication pending" );
736
693
_loramac.post_process_mlme_ind ();
737
694
tr_debug (" Immediate Uplink requested" );
@@ -767,7 +724,18 @@ void LoRaWANStack::process_reception_timeout(bool is_timeout)
767
724
* never occurs.
768
725
*/
769
726
if (slot == RX_SLOT_WIN_2) {
770
- post_process_tx_no_reception ();
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 ();
771
739
}
772
740
}
773
741
@@ -1056,15 +1024,11 @@ void LoRaWANStack::mcps_indication_handler()
1056
1024
|| (_loramac.get_device_class () == CLASS_C
1057
1025
&& mcps_indication->type == MCPS_CONFIRMED)) {
1058
1026
#if (MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE)
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
- }
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;
1068
1032
#else
1069
1033
send_event_to_application (UPLINK_REQUIRED);
1070
1034
#endif
@@ -1118,7 +1082,8 @@ void LoRaWANStack::process_shutdown_state(lorawan_status_t &op_status)
1118
1082
_lw_session.active = false ;
1119
1083
_device_current_state = DEVICE_STATE_SHUTDOWN;
1120
1084
op_status = LORAWAN_STATUS_DEVICE_OFF;
1121
- _ctrl_flags = 0 ;
1085
+ _ctrl_flags &= ~CONNECTED_FLAG;
1086
+ _ctrl_flags &= ~CONN_IN_PROGRESS_FLAG;
1122
1087
send_event_to_application (DISCONNECTED);
1123
1088
}
1124
1089
@@ -1134,15 +1099,20 @@ void LoRaWANStack::process_status_check_state()
1134
1099
// Another possibility is the case when the stack fails to schedule a
1135
1100
// deferred transmission and a scheduling failure handler is invoked.
1136
1101
_ctrl_flags &= ~TX_DONE_FLAG;
1102
+ _ctrl_flags &= ~TX_ONGOING_FLAG;
1137
1103
_loramac.set_tx_ongoing (false );
1138
1104
_loramac.reset_ongoing_tx ();
1139
1105
mcps_confirm_handler ();
1140
1106
1141
1107
} else if (_device_current_state == DEVICE_STATE_RECEIVING) {
1142
1108
1143
- if ((_ctrl_flags & TX_DONE_FLAG) || (_ctrl_flags & RETRY_EXHAUSTED_FLAG)) {
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.
1144
1114
_ctrl_flags &= ~TX_DONE_FLAG;
1145
- _ctrl_flags &= ~RETRY_EXHAUSTED_FLAG ;
1115
+ _ctrl_flags &= ~TX_ONGOING_FLAG ;
1146
1116
_loramac.set_tx_ongoing (false );
1147
1117
_loramac.reset_ongoing_tx ();
1148
1118
// if an automatic uplink is ongoing, we should not send a TX_DONE
@@ -1174,6 +1144,7 @@ void LoRaWANStack::process_scheduling_state(lorawan_status_t &op_status)
1174
1144
1175
1145
op_status = _loramac.send_ongoing_tx ();
1176
1146
if (op_status == LORAWAN_STATUS_OK) {
1147
+ _ctrl_flags |= TX_ONGOING_FLAG;
1177
1148
_ctrl_flags &= ~TX_DONE_FLAG;
1178
1149
_loramac.set_tx_ongoing (true );
1179
1150
_device_current_state = DEVICE_STATE_SENDING;
0 commit comments