【蓝牙开发】Android Bluedroid 源码学习之状态机设计

该博客介绍了如何从Android的Bluedroid框架中抽象出状态机,并在其他项目中复用。文章创建了一个名为BtifStateMachine的基类,并在btif_av.cc中展示了如何基于此基类实现具体的BtifAvStateMachine,用于AVDTP连接的管理。通过示例代码展示了状态的切换和事件处理过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文主要是抽离与Bluedroid(Android P - system/bt)中用到的状态机,将其抽离出来再其它的项目中也可以直接使用.

在指定的路径创建了statemachine目录,然后创建文件如下:

➜  statemachine tree    
.
├── btif_av.cc
└── btif_state_machine.h

btif_state_machine.h,

/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef BTIF_STATE_MACHINE_H
#define BTIF_STATE_MACHINE_H

#include <map>
#include <utility>


/**
 * State machine used by BTIF components.
 */
class BtifStateMachine {
 public:
  enum { kStateInvalid = -1 };

  /**
   * A class to represent the state in the State Machine.
   */
  class State {
    friend class BtifStateMachine;

   public:
    /**
     * Constructor.
     *
     * @param sm the State Machine to use
     * @param state_id the unique State ID. It should be a non-negative number.
     */
    State(BtifStateMachine& sm, int state_id) : sm_(sm), state_id_(state_id) {}

    virtual ~State() = default;

    /**
     * Process an event.
     * TODO: The arguments are wrong - used for backward compatibility.
     * Will be replaced later.
     *
     * @param event the event type
     * @param p_data the event data
     * @return true if the processing was completed, otherwise false
     */
    virtual bool ProcessEvent(uint32_t event, void* p_data) = 0;

    /**
     * Get the State ID.
     *
     * @return the State ID
     */
    int StateId() const { return state_id_; }

   protected:
    /**
     * Called when a state is entered.
     */
    virtual void OnEnter() {}

    /**
     * Called when a state is exited.
     */
    virtual void OnExit() {}

    /**
     * Transition the State Machine to a new state.
     *
     * @param dest_state_id the state ID to transition to. It must be one
     * of the unique state IDs when the corresponding state was created.
     */
    void TransitionTo(int dest_state_id) { sm_.TransitionTo(dest_state_id); }

    /**
     * Transition the State Machine to a new state.
     *
     * @param dest_state the state to transition to. It cannot be nullptr.
     */
    void TransitionTo(BtifStateMachine::State* dest_state) {
      sm_.TransitionTo(dest_state);
    }

   private:
    BtifStateMachine& sm_;
    int state_id_;
  };

  BtifStateMachine()
      : initial_state_(nullptr),
        previous_state_(nullptr),
        current_state_(nullptr) {}
  ~BtifStateMachine() {
    for (auto& kv : states_) delete kv.second;
  }

  /**
   * Start the State Machine operation.
   */
  void Start() { TransitionTo(initial_state_); }

  /**
   * Quit the State Machine operation.
   */
  void Quit() { previous_state_ = current_state_ = nullptr; }

  /**
   * Get the current State ID.
   *
   * @return the current State ID
   */
  int StateId() const {
    if (current_state_ != nullptr) {
      return current_state_->StateId();
    }
    return kStateInvalid;
  }

  /**
   * Get the previous current State ID.
   *
   * @return the previous State ID
   */
  int PreviousStateId() const {
    if (previous_state_ != nullptr) {
      return previous_state_->StateId();
    }
    return kStateInvalid;
  }

  /**
   * Process an event.
   * TODO: The arguments are wrong - used for backward compatibility.
   * Will be replaced later.
   *
   * @param event the event type
   * @param p_data the event data
   * @return true if the processing was completed, otherwise false
   */
  bool ProcessEvent(uint32_t event, void* p_data) {
    if (current_state_ == nullptr) return false;
    return current_state_->ProcessEvent(event, p_data);
  }

  /**
   * Transition the State Machine to a new state.
   *
   * @param dest_state_id the state ID to transition to. It must be one
   * of the unique state IDs when the corresponding state was created.
   */
  void TransitionTo(int dest_state_id) {
    auto it = states_.find(dest_state_id);

    State* dest_state = it->second;
    TransitionTo(dest_state);
  }

  /**
   * Transition the State Machine to a new state.
   *
   * @param dest_state the state to transition to. It cannot be nullptr.
   */
  void TransitionTo(BtifStateMachine::State* dest_state) {
    if (current_state_ != nullptr) {
      current_state_->OnExit();
    }
    previous_state_ = current_state_;
    current_state_ = dest_state;
    current_state_->OnEnter();
  }

  /**
   * Add a state to the State Machine.
   * The state machine takes ownership on the state - i.e., the state will
   * be deleted by the State Machine itself.
   *
   * @param state the state to add
   */
  void AddState(State* state) {
    states_.insert(std::make_pair(state->StateId(), state));
  }

  /**
   * Set the initial state of the State Machine.
   *
   * @param initial_state the initial state
   */
  void SetInitialState(State* initial_state) { initial_state_ = initial_state; }

 private:
  State* initial_state_;
  State* previous_state_;
  State* current_state_;
  std::map<int, State*> states_;
};

#endif  // BTIF_STATE_MACHINE_H

btif_state_machine.h 中实现了BtifStateMachine 这一状态机基类,接下来会有一个简单的示例来讲解如何基于BtifStateMachine进行具体场景的状态机实现.

btif_av.cc的实现,

#include "btif_state_machine.h"

#include <iostream>
 #include <unistd.h>

class BtifAvStateMachine : public BtifStateMachine {

public:
    enum {
        kStateIdle,     // AVDTP disconnected
        kStateOpening,  // Opening AVDTP connection 
    };

    class StateIdle : public State {
        public:
        StateIdle(BtifAvStateMachine& sm)
            : State(sm, kStateIdle) {}
        void OnEnter() override;
        void OnExit() override;
        bool ProcessEvent(uint32_t event, void* p_data) override;
    };

    class StateOpening : public State {
        public:
        StateOpening(BtifAvStateMachine& sm)
            : State(sm, kStateOpening) {}
        void OnEnter() override;
        void OnExit() override;
        bool ProcessEvent(uint32_t event, void* p_data) override;
    };

    BtifAvStateMachine() {
        state_idle_ = new StateIdle(*this);
        state_opening_ = new StateOpening(*this);

        AddState(state_idle_);
        AddState(state_opening_);
        SetInitialState(state_idle_);
    }
    
    private:
        StateIdle* state_idle_;
        StateOpening* state_opening_; 
};

void BtifAvStateMachine::StateIdle::OnEnter() {
    std::cout << __func__ << " : StateIdle : Hello" << std::endl; 
}

void BtifAvStateMachine::StateIdle::OnExit() {
    std::cout << __func__ << " : StateIdle : Hello" << std::endl; 
}

bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) {
    std::cout << __func__ << " : StateIdle : Hello" << std::endl; 
}


/**/
void BtifAvStateMachine::StateOpening::OnEnter() {
    std::cout << __func__ << " : StateOpening : Hello" << std::endl; 
}

void BtifAvStateMachine::StateOpening::OnExit() {
    std::cout << __func__ << " : StateOpening : Hello" << std::endl; 
}

bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, void* p_data) {
    std::cout << __func__ << " : StateOpening : Hello" << std::endl; 
}


int main(int argc, char **argv)
{
    std::cout << __func__ << ": Hi : Hello" << std::endl; 
    BtifAvStateMachine st_test;

    st_test.TransitionTo(BtifAvStateMachine::kStateIdle);
    st_test.ProcessEvent(1, NULL);

    sleep(2);

    st_test.TransitionTo(BtifAvStateMachine::kStateOpening);
    st_test.ProcessEvent(1, NULL);
}

编译运行:

➜  statemachine g++ btif_av.cc -I./
➜  statemachine ./a.out 
main: Hi : Hello
OnEnter : StateIdle : Hello
ProcessEvent : StateIdle : Hello
OnExit : StateIdle : Hello
OnEnter : StateOpening : Hello
ProcessEvent : StateOpening : Hello
总结

在嵌入式开发中,状态的切换和状态管理的实现是非常常见的,之前总是简单的s使用变量和if-else进行状态的处理,在学习了Bluedroid中的statemachine后,在以后遇到类似的场景时需要注意是否可以用上述的这种方式进行状态机的实现.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值