车联网Tbox电源模式管理

2018-02-01  本文已影响1198人  守拙圆

Tbox电源模式

当 Tbox 进行电源模式切换时应该通知 CSP。在车辆熄火(ignition off)后 Tbox 有不同的电源模式。在执行远程车辆信息服务时电源模式将对用户体验产生影响。

Tbox 应该支持下面的电源模式:
Tbox应该通知 CSP 如下信息:

电源模式状态转换图

事件清单

MCU 根据 CAN_bus Sleep && KL 15 Off && USB off 等满足休眠条件后通知 modem 进入 standby。

wakeup_in 包含了以下具体事件:
|| BTN pressed :XCALL案件,MCU唤醒;
|| Movement :MCU唤醒;
|| WAN Antenna removal :暂时不做;
|| KL30 removal :MCU处理
|| CAN_bus Normal :MCU硬件唤醒modem
|| KL15 On :MCU硬件唤醒modem
|| USB On (一体机是通过mcu控制hu电源模式,故hu开机时,mcu一定处于working状态,故此时也会唤醒模块,从而使 usb on)

mcu启动modem流程

代码实现

#include <iostream>
#include <boost/msm/back/state_machine.hpp>
 
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>
 
namespace
{
    namespace msm = boost::msm;
    namespace msmf = boost::msm::front;
    namespace mpl = boost::mpl;
 
    // ----- Events
    struct EventMCU {};
    struct EventSMS {};
    struct EventCall{};

    struct EventWrkToStby{};
    struct EventStbyToSubSleep {};
    struct EventSubWrkToSubSleep{};
    struct EventSubWrkToSleep{};

         
    // ----- State machine
    struct TemSm_:msmf::state_machine_def<TemSm_>
    {
        // InitStates
        struct Init:msmf::state<> {};
        
        //Choices
        struct Choice_:msmf::state<>{};
        
        //Working
        struct Working:msmf::state<> 
        {
            // Entry action
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) 
            {
                std::cout << "Working::on_entry()" << std::endl;
            }
            // Exit actions
            template <class Event,class Fsm>
            void on_exit(Event const&, Fsm&) 
            {
                std::cout << "Working::on_exit()" << std::endl;
            }
        };       

        //standby
        struct Standby:msmf::state<> 
        {
            // Entry action
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) 
            {
                std::cout << "Standby::on_entry()" << std::endl;
            }
            // Exit actions
            template <class Event,class Fsm>
            void on_exit(Event const&, Fsm&) 
            {
                std::cout << "Standby::on_exit()" << std::endl;
            }
        };       

        //Sleeping
        struct Sleeping:msmf::state<> 
        {
            // Entry action
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) 
            {
                std::cout << "Sleeping::on_entry()" << std::endl;
            }
            // Exit actions
            template <class Event,class Fsm>
            void on_exit(Event const&, Fsm&) 
            {
                std::cout << "Sleeping::on_exit()" << std::endl;
            }
        };       

        struct SleepPoll_:msmf::state_machine_def<SleepPoll_>
        {

            // Entry action
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) 
            {
                BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, TemSm_>::value));
                std::cout << "SleepPoll::on_entry()" << std::endl;
            }
            // Exit actions
            template <class Event,class Fsm>
            void on_exit(Event const&, Fsm&) 
            {
                BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, TemSm_>::value));
                std::cout << "SleepPoll::on_exit()" << std::endl;
            }

            //SubSleep
            struct SubSleep:msmf::state<> 
            {
                // Entry action
                template <class Event,class Fsm>
                void on_entry(Event const&, Fsm&) 
                {
                    BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, SleepPoll_>::value));
                    std::cout << "SubSleep::on_entry()" << std::endl;
                }
                // Exit actions
                template <class Event,class Fsm>
                void on_exit(Event const&, Fsm&) 
                {
                    BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, SleepPoll_>::value));
                    std::cout << "SubSleep::on_exit()" << std::endl;
                }
            };

            //Sleeping
            struct SubWork:msmf::state<> 
            {
                // Entry action
                template <class Event,class Fsm>
                void on_entry(Event const&, Fsm&) 
                {
                    BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, SleepPoll_>::value));
                    std::cout << "SubWork::on_entry()" << std::endl;
                }
                // Exit actions
                template <class Event,class Fsm>
                void on_exit(Event const&, Fsm&) 
                {
                    BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, SleepPoll_>::value));
                    std::cout << "SubWork::on_exit()" << std::endl;
                }
            };       

            struct Entry:msmf::entry_pseudo_state<> {}; 
            struct ExitRTC:msmf::exit_pseudo_state< EventSubWrkToSleep > {};
            struct ExitSMS:msmf::exit_pseudo_state< EventSMS > {};
            struct ExitCall:msmf::exit_pseudo_state< EventCall > {};

            typedef mpl::vector<SubWork> initial_state;

            struct transition_table:mpl::vector<
                                    msmf::Row< Entry, boost::any, SubSleep, msmf::none, msmf::none >,
                                    msmf::Row< SubWork, EventSubWrkToSubSleep, SubSleep, msmf::none, msmf::none >,
                                    msmf::Row< SubWork, EventSubWrkToSleep, ExitRTC, msmf::none, msmf::none >,
                                    msmf::Row< SubWork, EventCall, ExitCall, msmf::none, msmf::none >,
                                    msmf::Row< SubWork, EventSMS, ExitSMS, msmf::none, msmf::none >
                                    >{};
            
        };
        // Set initial SourceState
        typedef Init initial_state;                                                     

        typedef msm::back::state_machine<SleepPoll_> SleepPoll;

        struct GuardCondition
        {
            template <class Event, class Fsm, class SourceState, class TargetState>
            bool operator()(Event const&, Fsm& f, SourceState&, TargetState&) const
            {
                if(1 == f.condition)    return true;
                return false;
            }
        };
        // Actions
        struct ActionAssign 
        {
            template <class Event, class Fsm, class SourceState, class TargetState>
            void operator()(Event const&, Fsm& f, SourceState&, TargetState&) const
            {
                f.condition = 0;
                std::cout << "ActionAssign()" << std::endl;
            }
        };

        struct  ActionInitToWorking
        {
            template <class Event, class Fsm, class SourceState, class TargetState>
            void operator()(Event const&, Fsm& f, SourceState&, TargetState&) const
            {
                std::cout << "ActionInitToWorking() condition = " << f.condition << std::endl;
            }
        };
        
        struct ActionInitToSleepPoll
        {

            template <class Event, class Fsm, class SourceState, class TargetState>
            void operator()(Event const&, Fsm& f, SourceState&, TargetState&) const
            {
                std::cout << "ActionInitToSleepPoll() condition = " << f.condition << std::endl;
            }
        };
        // Transition transition_table
        struct transition_table:mpl::vector<
                      //Start       Event       Next        Action         Guard
            msmf::Row < Init,    msmf::none, Working,    ActionInitToWorking,    msmf::none >,
            msmf::Row< Working,     EventWrkToStby, Standby, msmf::none,    msmf::none >,
            msmf::Row< Standby,    EventStbyToSubSleep, SleepPoll::entry_pt<SleepPoll_::Entry>, msmf::none, msmf::none>,
            msmf::Row< SleepPoll::exit_pt<SleepPoll_::ExitRTC>, EventSubWrkToSleep, Sleeping, msmf::none, msmf::none>,
            msmf::Row< SleepPoll::exit_pt<SleepPoll_::ExitSMS>, EventSMS, Working, msmf::none, msmf::none>,
            msmf::Row< SleepPoll::exit_pt<SleepPoll_::ExitCall>, EventCall, Working, msmf::none, msmf::none>,
            msmf::Row< SleepPoll,   EventMCU, Working, msmf::none,    msmf::none >

        > {};

        //template <class Event,class Fsm>
        ~TemSm_()
        {
            std::cout << "hello" << std::endl;
        }

        private:
            int condition;
    };

    // Pick a back-end
    typedef msm::back::state_machine<TemSm_> TemSm;
    
    void test() 
    {        
        TemSm sm1;
        sm1.start(); 
        std::cout << "send EventWrkToStby" << std::endl;
        sm1.process_event(EventWrkToStby());
        std::cout << "send EventStbyToSubSleep" << std::endl;
        sm1.process_event(EventStbyToSubSleep());
        //std::cout << "send EventSubWrkToSleep" << std::endl;
       // sm1.process_event(EventSubWrkToSleep());
        //std::cout << "send EventCall" << std::endl;
       // sm1.process_event(EventCall());
        std::cout << "send EventMCU" << std::endl;
        sm1.process_event(EventMCU());
    }

}

int main()
{

    test();

    return 0;
}

几个注意事项

由于tbox状态机就运行在tbox上,故相关tbox异常场景需要考虑。

  1. 在tbox的电源模式中 sleep 模式中,各个进程都停止运行,从sleep模式中恢复时需要重启进程,要使状态机在sleep后能够延续,需要将状态机持久化。
 //保存状态机到本地
#define POWERMODE_PATH "/oemimage/oemdata/PowerMode.fsm"
std::ofstream ofs(POWERMODE_PATH);
boost::archive::text_oarchive oa(ofs);
oa << sm;

//从本地文件中恢复状态机
std::ifstream ifs(POWERMODE_PATH);
boost::archive::text_iarchive ia(ifs);
ia >> sm;

2.为了区分进程异常退出还是正常退出:

  1. 场景考虑:
  • 场景1:若不进行持久化的话,由于sleep和subsleep状态实际上就是定时关机与关机的区别,故无法恢复到对应的subsleep状态。
    方案: 状态机持久化

  • 场景2:若在整个状态机变化的过程中都持久化状态机,当状态机处于standby时(此时状态机已经完成持久化),若在stanby时正常断电,异常断电关机,则此时开启系统将到standby状态,而实际处于work状态,故造成了状态不一致。
    方案:此异常场景的解决方案是:不区分异常与正常断电,重启后都从初始working状态开始。则要求不对状态机进行持久化。

  • 场景3:若在进入sleep与subsleep都进行持久化,若正常关机,则启动后恢复状态机,需要区分当前状态处于sleep还是subsleep,若处于subsleep则切换到subwork,若处于sleep,则切换到working。若是在subsleep期间异常关机,则异常重启后首先还是会进入subworking,此时则不对。
    方案:此时虽然错误处于subworking状态,但在此时只要mcu通知modem切换到working状态,都会使状态机切换到working,从而恢复正常。

综上所述:此处处理的最佳方式是,状态机进入subsleep状态时,持久化状态机,状态机恢复完成后删除此持久化文件;则正常关机后,重新启动,状态为subsleep状态主动切换到subworking。若在sleep状态,无论正常关机还是异常关机,重新启动后都处于working状态。

上一篇 下一篇

猜你喜欢

热点阅读