屏幕常亮状态下,当我们锁车门发生Acc断电的,最终到车进入休眠状态,需要发生三次状态迁移
public void onBcmPowerModeChange(PowerMode newMode) {
if (newMode.mMode < 0 || newMode.mMode > 2 ||
newMode.mSrc < 0 || newMode.mSrc > 1 ||
newMode.mFlag < 0 || newMode.mFlag > 1) {
Log.d(TAG, "Invalid power mode(" + newMode.mMode + ", "
+ newMode.mSrc + ", " + newMode.mFlag + "). DROP !!!");
return;
}
mLooper.addEvent(() -> {
if (mCurrentMode.equals(newMode)) {
return;
}
mCurrentMode = newMode;
Log.d(TAG, "Power mode change: " + newMode);
switch (newMode.mMode) {
case CarPowerHalService.BCM_PWR_OFF:
mCore.powerOff(newMode.mSrc, newMode.mFlag);
break;
case CarPowerHalService.BCM_PWR_ACC:
case CarPowerHalService.BCM_PWR_ON:
mCore.powerOn(newMode.mSrc, newMode.mFlag);
break;
}
}, 1);
}
1.首先获取BcmPowerMode,由MCU上报提供.根据PowerMode的状态,进行状态迁移,由于收到的状态 OFF, HL, LOCAL
ACC
ACC模式时,整车接通动力电池,全部ECU唤醒。
ON
ON模式时,整车接通动力电池,全部ECU唤醒。
OFF
OFF模式下,整车切断动力电池,部分ECU断电,其余长电ECU均由蓄电池进行供电。
整车电源模式获取策略
整车电源模式可通过两种方式获取,分别为从CAN总线获取及从物理硬线获取。其中以CAN总线获取方式为准,
当CAN总线异常或获取的整车电源模式为无效时通过物理硬线方式获取。通过物理硬线获取时,高电平代表线有效。
现方案中,ACC硬线连接到820A-MCU,IGN硬线连接到J6-MCU。
CAN
can总线策略
HL
硬线策略
整车电源模式标志位
整车电源模式标志位由BCM生成,只能通过CAN总线获取,是HMI电源管理的重要标志,此标志位共有两种,分别为本地供电模式及远程供电模式
LOCAL
当整车电源模式切换原因为非远程控制时BCM生成本地供电模式标志,此时显示屏可被点亮。
REMOTE
当整车电源模式切换原因为远程控制时BCM生成远程供电模式标志,此时不允许特殊显示需求之外任何显示屏点亮。
接下来继续分析Poweroff方法
@Override
protected void powerOff(PowerStateMachine context, int src, int flag)
{
Log.d(" shiph "," PowerStateMachineMap_PM_STATE_NORMAL powerOff src "+src +" flag ");
PowerStateMachineImpl ctxt = context.getOwner();
(context.getState()).exit(context);
context.clearState();
try
{
//释放所有三方应用
ctxt.freezeAll3rdApps();
//设置关屏幕接口
ctxt.turnOffDisplayInternal(null, POWER, PM_PID_SELF);
ctxt.enclose(PowerStateMachine::deferredAction, "deferredAction");
}
finally
{
context.setState(PowerStateMachineMap.PM_STATE_PARTLYWORK);
(context.getState()).entry(context);
}
return;
}
接下来看下partywork的状态迁移逻辑
@Override
protected void deferredAction(PowerStateMachine context)
{
PowerStateMachineImpl ctxt = context.getOwner();
PowerStateMachineImplState endState = context.getState();
context.clearState();
try
{
ctxt.pubSleepProcessingOrFSMTransitionBack();
ctxt.blockSuspendIfNecessaryInternel();
ctxt.resetOrRestartTimer(PM_TIMER_SLPBLK, 2, PowerStateMachine::sleepBlockerTimeout);
ctxt.startTimer(PM_TIMER_NM, 100, PowerStateMachine::timeout);
ctxt.goToTargetIfNecessary();
}
finally
{
context.setState(endState);
}
return;
}
NM报文每10秒上传一次
@Override
protected void recvNm(PowerStateMachine context, int mode)
{
PowerStateMachineImpl ctxt = context.getOwner();
if (mode == MCU_NM_SLEEP)
{
(context.getState()).exit(context);
context.clearState();
try
{
Log.d("shiph","PowerStateMachineMap_PM_STATE_PARTLYWORK recvNm mode "+mode);
ctxt.stopTimerIfNecessary(PM_TIMER_NM);
ctxt.enclose(PowerStateMachine::deferredAction, "deferredAction");
}
finally
{
context.setState(PowerStateMachineMap.PM_STATE_PRESLEEP);
(context.getState()).entry(context);
}
}
else
{
PowerStateMachineImplState endState = context.getState();
context.clearState();
try
{
ctxt.resetOrRestartTimer(PM_TIMER_NM, 100, PowerStateMachine::timeout);
}
finally
{
context.setState(endState);
}
}
return;
}
NM mode 状态
如果NM mode接受的值为3, 所以看下timeout的状态逻辑
@Override
protected void timeout(PowerStateMachine context)
{
PowerStateMachineImpl ctxt = context.getOwner();
(context.getState()).exit(context);
context.clearState();
try
{
ctxt.stopTimer(PM_TIMER_NM);
ctxt.enclose(PowerStateMachine::deferredAction, "deferredAction");
}
finally
{
context.setState(PowerStateMachineMap.PM_STATE_PRESLEEP);
(context.getState()).entry(context);
}
return;
}
1.上报NMmode的定时器为10秒,当10秒以后,NM上报超时进入PM_STATE_PRESLEEP状态。
@Override
protected void recvMcuPowerQuery(PowerStateMachine context, int mode)
{
PowerStateMachineImpl ctxt = context.getOwner();
if (mode == MCU_PWR_QUERY_SLEEP)
{
PowerStateMachineImplState endState = context.getState();
context.clearState();
try
{ //强制激活MCU
ctxt.forceMcuAlive();
//1秒后调用postpone方法
ctxt.startTimerIfNecessary(PM_TIMER_POSTPONE, 1, PowerStateMachine::postpone);
}
finally
{
context.setState(endState);
}
}
else
{
PowerStateMachineImplState endState = context.getState();
context.clearState();
try
{
ctxt.ackMcuKickOff(mode);
}
finally
{
context.setState(endState);
}
}
return;
}
MCU power query状态为slee状态时候,进入postpone状态,1s,并进行循环处理
@Override
protected void postpone(PowerStateMachine context)
{
PowerStateMachineImpl ctxt = context.getOwner();
PowerStateMachineImplState endState = context.getState();
context.clearState();
try
{
ctxt.forceMcuAlive();
ctxt.resetOrRestartTimer(PM_TIMER_POSTPONE, 1, PowerStateMachine::postpone);
}
finally
{
context.setState(endState);
}
return;
}
设置MCU强制激活
重新重置postpone定时器,1s后再次进入postpone状态
postpone意义就是强制激活MCU,防止MCU提前睡下去,因为状态机目前在PartyWork状态,接下来看下partywork下
向presleep的状态迁移
当NM mode为0,或者NM mode发送超时,会发生partywork向presleep状态迁移
@Override
protected void deferredAction(PowerStateMachine context)
{
PowerStateMachineImpl ctxt = context.getOwner();
PowerStateMachineImplState endState = context.getState();
context.clearState();
try
{
ctxt.pubSleepProcessingOrFSMTransitionBack();
ctxt.startTimer(PM_TIMER_PRESLEEP, 600, PowerStateMachine::timeout);
ctxt.triggerHome();
ctxt.goToSleepIfNoLock(PM_WAKELOCK_HIGH + PM_WAKELOCK_NORMAL);
}
finally
{
context.setState(endState);
}
return;
}
先看下timeout的状态逻辑
@Override
protected void timeout(PowerStateMachine context)
{
PowerStateMachineImpl ctxt = context.getOwner();
PowerStateMachineImplState endState = context.getState();
context.clearState();
try
{
ctxt.goToSleepIfNoLock(PM_WAKELOCK_HIGH);
}
finally
{
context.setState(endState);
}
return;
}
1.调用goToSleepIfNoLock进入wakeLock的检查,检查高权锁的集合是否为0
然后看下goToSleepIfNoLock逻辑
public void goToSleepIfNoLock(int lockMask) {
boolean isAnyLockHeld = false;
switch (lockMask) {
case PM_WAKELOCK_HIGH:
case PM_WAKELOCK_NORMAL:
isAnyLockHeld = mWakelocks[lockMask >> 1].size() != 0;
break;
case PM_WAKELOCK_HIGH + PM_WAKELOCK_NORMAL:
isAnyLockHeld = (mWakelocks[0].size() + mWakelocks[1].size()) != 0;
break;
}
if (isAnyLockHeld) {
Log.d(TAG, "HIGH[" + mWakelocks[0].size() + "], NORMAL[" + mWakelocks[1].size() + "]");
return;
}
stopTimer(PM_TIMER_PRESLEEP);
enclose(PowerStateMachine::sleep, "sleep");
}
@Override
protected void sleep(PowerStateMachine context)
{
PowerStateMachineImpl ctxt = context.getOwner();
(context.getState()).exit(context);
context.clearState();
try
{
ctxt.enclose(PowerStateMachine::deferredAction, "deferredAction");
}
finally
{
context.setState(PowerStateMachineMap.PM_STATE_SLEEP);
(context.getState()).entry(context);
}
return;
}
最后看下sleep的状态迁移
@Override
protected void deferredAction(PowerStateMachine context)
{
PowerStateMachineImpl ctxt = context.getOwner();
PowerStateMachineImplState endState = context.getState();
context.clearState();
try
{
ctxt.pubSleepProcessingOrFSMTransitionBack();
ctxt.forceTurnOffDisplayIfNecessary();
ctxt.startTimer(PM_TIMER_SLEEP, 2, PowerStateMachine::sleep);
ctxt.forceRebootIfScheduled();
ctxt.stopTimerIfNecessary(PM_TIMER_POSTPONE);
ctxt.forceMcuSleep();
}
finally
{
context.setState(endState);
}
return;
}
1.检查HU状态
2.关闭屏幕
3.设置2秒定时期,2秒后调用sleep方法
4.是否需要重启
5.停止postpone
6.强制关闭MCU模式,中间有耗时500毫秒
接下来看下sleep方法
@Override
protected void sleep(PowerStateMachine context)
{
PowerStateMachineImpl ctxt = context.getOwner();
(context.getState()).exit(context);
context.clearState();
try
{
ctxt.stopTimer(PM_TIMER_SLEEP);
ctxt.scheduleRtcAlarmIfNecessary();
ctxt.hostUSB();
ctxt.pubNormalSleep();
ctxt.suspendToRam();
ctxt.pubSystemWakeUp();
ctxt.pubWakeUpProcessing();
ctxt.kickOffMcu();
ctxt.obtainWakeupReason(WAKEUP_WAKE_LOCK_TIMEOUT);
ctxt.peripheralUSB();
ctxt.pubWakeUpComplete();
ctxt.enableDisplayCtrl();
ctxt.enclose(PowerStateMachine::deferredAction, "deferredAction");
}
finally
{
context.setState(PowerStateMachineMap.PM_STATE_PARTLYWORK);
(context.getState()).entry(context);
}
return;
}