LCOV - code coverage report
Current view: top level - src - node_state_machine.cpp (source / functions) Coverage Total Hit
Test: ESP-NOW Manager Unified Coverage Lines: 100.0 % 42 42
Test Date: 2026-04-21 02:14:32 Functions: 100.0 % 11 11
Branches: 100.0 % 30 30

             Branch data     Line data    Source code
       1                 :             : #include "node_state_machine.hpp"
       2                 :             : #include "esp_log.h"
       3                 :             : 
       4                 :             : /**
       5                 :             :  * State Transition Table
       6                 :             :  * ----------------------
       7                 :             :  * | Current State   | Event                      | New State     | Condition / Rationale | | :-------------- |
       8                 :             :  * :------------------------- | :------------ | :-------------------------------------------------------- | |
       9                 :             :  * UNINITIALIZED   | on_init(is_hub, has_peers) | OPERATIONAL   | has_peers == true | | UNINITIALIZED   |
      10                 :             :  * on_init(is_hub, has_peers) | PAIRING       | has_peers == false && is_hub == true                      | |
      11                 :             :  * UNINITIALIZED   | on_init(is_hub, has_peers) | PAIRING_SCAN  | has_peers == false && is_hub == false | | IDLE |
      12                 :             :  * on_pairing_requested       | PAIRING       | is_hub == true || has_peers == true                       | | IDLE |
      13                 :             :  * on_pairing_requested       | PAIRING_SCAN  | is_hub == false && has_peers == false                     | |
      14                 :             :  * OPERATIONAL     | on_pairing_requested       | PAIRING       | is_hub == true || has_peers == true | | OPERATIONAL |
      15                 :             :  * on_pairing_requested       | PAIRING_SCAN  | is_hub == false && has_peers == false                     | |
      16                 :             :  * OPERATIONAL     | on_scan_requested          | RECOVERY_SCAN | Link lost, try to find channel | | PAIRING         |
      17                 :             :  * on_scan_requested          | RECOVERY_SCAN | Scan requested during pairing                             | | IDLE |
      18                 :             :  * on_scan_requested          | RECOVERY_SCAN | Scan requested from idle                                  | |
      19                 :             :  * PAIRING_SCAN    | on_channel_found           | PAIRING       | Channel found, ready to pair | | RECOVERY_SCAN   |
      20                 :             :  * on_channel_found           | OPERATIONAL   | Back to normal                                            | |
      21                 :             :  * PAIRING_SCAN    | on_scan_failed(has_peers)  | IDLE          | No HUB found. App can retry. | | RECOVERY_SCAN   |
      22                 :             :  * on_scan_failed(has_peers)  | IDLE          | Channel lost and not rediscovered.                        | | PAIRING |
      23                 :             :  * on_pairing_timeout         | OPERATIONAL   | has_peers == true                                         | | PAIRING |
      24                 :             :  * on_pairing_timeout         | IDLE          | has_peers == false                                        |
      25                 :             :  */
      26                 :             : 
      27                 :             : static const char* TAG = "NodeStateMachine";
      28                 :             : 
      29                 :          36 : NodeStateMachine::NodeStateMachine()
      30                 :          36 :     : state_(NodeState::UNINITIALIZED)
      31                 :             : {
      32                 :          36 : }
      33                 :             : 
      34                 :          39 : NodeState NodeStateMachine::get_state() const
      35                 :             : {
      36                 :          39 :     return state_.load();
      37                 :             : }
      38                 :             : 
      39                 :           1 : void NodeStateMachine::reset()
      40                 :             : {
      41                 :           1 :     state_.store(NodeState::UNINITIALIZED);
      42                 :           1 : }
      43                 :             : 
      44                 :          32 : esp_err_t NodeStateMachine::on_init(bool is_hub, bool has_peers)
      45                 :             : {
      46         [ +  + ]:          32 :     if (state_.load() != NodeState::UNINITIALIZED) {
      47                 :             :         return ESP_ERR_INVALID_STATE;
      48                 :             :     }
      49         [ +  + ]:          31 :     if (has_peers) {
      50                 :          10 :         return transition_to(NodeState::OPERATIONAL);
      51                 :             :     }
      52                 :             :     // HUB without peers goes directly to PAIRING — already on the correct channel
      53                 :             :     // NODE without peers needs to find the HUB channel first
      54         [ +  + ]:          40 :     return transition_to(is_hub ? NodeState::PAIRING : NodeState::PAIRING_SCAN);
      55                 :             : }
      56                 :             : 
      57                 :           1 : esp_err_t NodeStateMachine::on_deinit()
      58                 :             : {
      59                 :             :     // state_.store(NodeState::UNINITIALIZED);
      60                 :           1 :     return transition_to(NodeState::UNINITIALIZED);
      61                 :             : }
      62                 :             : 
      63                 :           9 : esp_err_t NodeStateMachine::on_pairing_requested(bool is_hub, bool has_peers)
      64                 :             : {
      65         [ +  + ]:           9 :     NodeState current = state_.load();
      66         [ +  + ]:           9 :     if (current != NodeState::IDLE && current != NodeState::OPERATIONAL) {
      67                 :             :         return ESP_ERR_INVALID_STATE;
      68                 :             :     }
      69                 :             :     // HUB never scans — already on the correct channel
      70                 :             :     // NODE without peers needs to find the HUB channel first
      71         [ +  + ]:           5 :     if (is_hub || has_peers) {
      72                 :           3 :         return transition_to(NodeState::PAIRING);
      73                 :             :     }
      74                 :           2 :     return transition_to(NodeState::PAIRING_SCAN);
      75                 :             : }
      76                 :             : 
      77                 :           6 : esp_err_t NodeStateMachine::on_pairing_timeout(bool has_peers)
      78                 :             : {
      79         [ +  + ]:           6 :     if (state_.load() != NodeState::PAIRING) {
      80                 :             :         return ESP_ERR_INVALID_STATE;
      81                 :             :     }
      82                 :             : 
      83         [ +  + ]:           4 :     return transition_to(has_peers ? NodeState::OPERATIONAL : NodeState::IDLE);
      84                 :             : }
      85                 :             : 
      86                 :           9 : esp_err_t NodeStateMachine::on_scan_requested()
      87                 :             : {
      88         [ +  + ]:           9 :     NodeState current = state_.load();
      89         [ +  + ]:           9 :     if (current != NodeState::OPERATIONAL && current != NodeState::PAIRING && current != NodeState::IDLE) {
      90                 :             :         return ESP_ERR_INVALID_STATE;
      91                 :             :     }
      92                 :           7 :     return transition_to(NodeState::RECOVERY_SCAN);
      93                 :             : }
      94                 :             : 
      95                 :          11 : esp_err_t NodeStateMachine::on_channel_found()
      96                 :             : {
      97         [ +  + ]:          11 :     NodeState current = state_.load();
      98         [ +  + ]:          11 :     if (current == NodeState::PAIRING_SCAN) {
      99                 :           7 :         return transition_to(NodeState::PAIRING);
     100                 :             :     }
     101         [ +  + ]:           4 :     else if (current == NodeState::RECOVERY_SCAN) {
     102                 :           1 :         return transition_to(NodeState::OPERATIONAL);
     103                 :             :     }
     104                 :             : 
     105                 :             :     return ESP_ERR_INVALID_STATE;
     106                 :             : }
     107                 :             : 
     108                 :          12 : esp_err_t NodeStateMachine::on_scan_failed()
     109                 :             : {
     110         [ +  + ]:          12 :     NodeState current = state_.load();
     111                 :             : 
     112         [ +  + ]:          12 :     if (current == NodeState::PAIRING_SCAN || current == NodeState::RECOVERY_SCAN) {
     113                 :           8 :         return transition_to(NodeState::IDLE);
     114                 :             :     }
     115                 :             : 
     116                 :             :     return ESP_ERR_INVALID_STATE;
     117                 :             : }
     118                 :             : 
     119                 :          63 : esp_err_t NodeStateMachine::transition_to(NodeState new_state)
     120                 :             : {
     121                 :          63 :     ESP_LOGI(TAG, "NodeState: %d -> %d", static_cast<int>(state_.load()), static_cast<int>(new_state));
     122                 :          63 :     state_.store(new_state);
     123                 :          63 :     return ESP_OK;
     124                 :             : }
        

Generated by: LCOV version 2.0-1