最近碰到一个关于芯片测试过程中的问题,这颗芯片是用在笔记本端口上,笔记本客户那边会有一个压力测试,就是频繁的电脑电源状态切换,S0(正常使用的开机状态),S3(睡眠模式),S4(休眠模式)以及S5(关机模式)。 当然,主要是客户在压力测试过程中,发现了芯片会不正常的死锁,客户那边将机台寄回来,那么该如何复现呢?客户那边会有自己的一套压力测试系统,不过会测试很多东西,不太方便给我们,而且每一次循环耗时比较久。那么,能不能自己搭建一套控制电脑睡眠,休眠,关机以及唤醒的程序呢? 上面讲的是一个应用背景,告诉大家这其实也是有需求的,只是平时不太用而已,将其记录下来: 首先,从电脑开机状态S0切换到S3,S4甚至是S5,都是比较容易实现的,见下面代码:Application。SetSuspendState(PowerState。Suspend,false,false);从S0进入S3Application。SetSuspendState(PowerState。Hibernate,false,false);从S0进入S4Process。Start(shutdown,st0);参数s的意思是要关闭计算机参数t0的意思是告诉计算机0秒之后执行命令Process。Start(shutdown,rt0);参数r的意思是要重新启动计算机 只要调用上述语句即可实现从S0到其他的电源状态,那么反过来唤醒呢? 唤醒的难点在于:当处于S3,S4以及S5的状态下,我的上位机程序是不会运行的,因此,在上位机软件的定时唤醒也是没法工作的。那么笔记本客户那边是怎么操作的呢?他们会通过底层的EC控制来显示上述的功能,可是,我们是不知道底层EC的接口,而且,我们需要一个通用的程式,那要怎么实现呢? 在笔记本的设计中,在S3,S4,S5通常不是所有的东西都会关掉,通常会有一个硬件定时器还在开着,如果我们能操作这个定时器,那是不是就可以实现我们想要的功能呢? 可以调用下面的两个函数,即CreateWaitableTimer以及SetWaitableTimer,这两个函数就可以控制电脑里面开的硬件定时器,当然这个硬件定时器是CPU里面的还是EC里面的,我也不太清楚,没研究过,如果有大神研究过,可以留言,我也学习学习。〔DllImport(kernel32。dll)〕publicstaticexternSafeWaitHandleCreateWaitableTimer(IntPtrlpTimerAttributes,boolbManualReset,stringlpTimerName);〔DllImport(kernel32。dll,SetLastErrortrue)〕〔return:MarshalAs(UnmanagedType。Bool)〕publicstaticexternboolSetWaitableTimer(SafeWaitHandlehTimer,〔In〕reflongpDueTime,intlPeriod,IntPtrpfnCompletionRoutine,IntPtrlpArgToCompletionRoutine,boolfResume); 另外,需要说明的一点是,使用这个定时器也是有条件的,你需要先设置笔记本,ControlPanelPowerOptionsChangePlanSettingsChangeAdvancedPowerSettingsSleepAllowWakeTimers,使能定时器唤醒,还有就是,ControlPanelPowerOptionsChangePlanSettingsChangeAdvancedPowerSettingsBradAdditionalSettingsRequireapasswordonwakeup,关闭唤醒需要密码。 完成上面的设置,其实已经可以实现电脑从S3,S4,S5唤醒了,但在我使用的过程中,其实还碰到了一个问题,就是唤醒之后,屏幕不亮,你就会误认为没有唤醒,因此我增加了控制鼠标移动的命令,这样,唤醒之后,屏幕就会亮起。〔DllImport(user32。dll)〕publicstaticexternvoidmouseevent(Int32dwFlags,Int32dx,Int32dy,Int32dwData,UIntPtrdwExtraInfo);mouseevent(0x0001,0,1,0,UIntPtr。Zero);mouseevent(0x0001,0,1,0,UIntPtr。Zero); 另外还有一点需要注意,就是笔记本从S0S3S4S5S0这个循环里面,S0,S3S4S5这几个状态的停留时间一定要足够,因为,每个笔记本的完全进入各个状态的时间会不一样,比如,我用我自己的笔记本,这几个状态的停留时间要至少20s,否则,笔记本还没有完全进入就要退出,就会导致,电脑把WaitableTimer关掉,而笔记本还没有唤醒,导致程式死锁。而新的刚买的笔记本,只需要设置10s即可完全进入。 废话不多说,直接上代码:usingSusingSystem。Collections。GusingSystem。ComponentMusingSystem。DusingSystem。DusingSystem。LusingSystem。TusingSystem。Threading。TusingSystem。Windows。FusingSystem。TusingMicrosoft。Win32。SafeHusingSystem。Runtime。InteropSnamespaceAutoSwitchGUI{publicpartialclassAutoSwitchGUI:Form{〔DllImport(kernel32。dll)〕publicstaticexternSafeWaitHandleCreateWaitableTimer(IntPtrlpTimerAttributes,boolbManualReset,stringlpTimerName);〔DllImport(kernel32。dll,SetLastErrortrue)〕〔return:MarshalAs(UnmanagedType。Bool)〕publicstaticexternboolSetWaitableTimer(SafeWaitHandlehTimer,〔In〕reflongpDueTime,intlPeriod,IntPtrpfnCompletionRoutine,IntPtrlpArgToCompletionRoutine,boolfResume);〔DllImport(kernel32。dll)〕publicstaticexternuintSetThreadExecutionState(uintesFlags);〔DllImport(user32。dll)〕publicstaticexternvoidmouseevent(Int32dwFlags,Int32dx,Int32dy,Int32dwData,UIntPtrdwExtraInfo);publiceventEventHandlerWprivateBackgroundWorkerbgWorkernewBackgroundWorker();publicstructautoswitchguistatust{publicUInt64publicUInt64publicints0publicints3}publicAutoSwitchGUI(){InitializeComponent();bgWorker。DoWorknewDoWorkEventHandler(bgWorkerDowork);bgWorker。RunWorkerCompletednewRunWorkerCompletedEventHandler(bgWorkerRunWorkerCompleted);}privatevoidbgWorkerDowork(objectsender,DoWorkEventArgse){longwaketime(long)e。Ausing(SafeWaitHandlehandleCreateWaitableTimer(IntPtr。Zero,true,this。GetType()。Assembly。GetName()。Name。ToString()Timer)){if(SetWaitableTimer(handle,refwaketime,0,IntPtr。Zero,IntPtr。Zero,true)){using(EventWaitHandlewhnewEventWaitHandle(false,EventResetMode。AutoReset)){wh。SafeWaitHwh。WaitOne();}}else{thrownewWin32Exception(Marshal。GetLastWin32Error());}}}privatevoidbgWorkerRunWorkerCompleted(objectsender,RunWorkerCompletedEventArgse){mouseevent(0x0001,0,1,0,UIntPtr。Zero);mouseevent(0x0001,0,1,0,UIntPtr。Zero);autoswitchstatus。TestTimes。Textautoswitchstatus。testtimescnt。ToString();SystemTimer。Intervalautoswitchstatus。s0duration1000;SystemTimer。Start();}publicvoidSetWakeUpTime(UInt64time){bgWorker。RunWorkerAsync(System。DateTime。Now。AddSeconds(time)。ToFileTime());}privatevoidStartButtonClick(objectsender,EventArgse){try{autoswitchstatus。testtimesUInt64。Parse(SetTestTimes。Text);autoswitchstatus。s0durationint。Parse(S0Duration。Text);autoswitchstatus。s3durationint。Parse(S3Duration。Text);if(autoswitchstatus。testtimes0){SetThreadExecutionState(0x000000010x000000020x800000000x00000040);TestStatus。BackColorColor。Gautoswitchstatus。TestTimes。Text0;autoswitchstatus。testtimescnt0;SystemTimer。Intervalautoswitchstatus。s0duration1000;autoswitchstatus。curstate0;SystemTimer。Start();}}catch{}MessageBox。Show(ConfigurationFailed!);}privatevoidStopButtonClick(objectsender,EventArgse){SystemTimer。Stop();autoswitchstatus。TestStatus。BackColorColor。R}privatevoidSystemTimerTick(objectsender,EventArgse){if(autoswitchstatus。curstate0){autoswitchstatus。curstate0;SystemTimer。Stop();if(autoswitchstatus。testtimescntautoswitchstatus。testtimes){}else{SetWakeUpTime((UInt64)autoswitchstatus。s3duration);Application。SetSuspendState(PowerState。Suspend,false,false);Application。SetSuspendState(PowerState。Hibernate,false,false);}}elseif(autoswitchstatus。curstate1){autoswitchstatus。TestTimes。Textautoswitchstatus。testtimescnt。ToString();autoswitchstatus。curstate0;SendKeys。Send();MessageInfo。TextTEST1r;}}}} 另外声明,关于SetWaitableTimer和CreateWaitableTimer我是参考如下链接的: 希望可以帮到大家,上面代码在我自己的笔记本以及客户的笔记本是可以适用的。