1.系統啓動過程中RTC初始化
在WINCE6.0中,我們知道是通過OALIoCtlHalInitRTC()函數來設置RTC的時間的,但是如何調用到這個函數的呢?我們就從NKStartup()函數開始,但系統從nboot開始是如何執行到NKStartup()函數的呢?我後面會抽空寫關於eboot和nk的啓動過程中有涉及。
在SystemStartupFunc函數中,通過下面語句來創建一個內核線程RunApps:
hTh = CreateKernelThread (RunApps,0,THREAD_RT_PRIORITY_NORMAL,0);
接着就執行線程RunApps。在線程RunApps中,通過下面語句:
hFilesys = (HMODULE) NKLoadLibraryEx (L"filesys.dll", MAKELONG (LOAD_LIBRARY_IN_KERNEL, LLIB_NO_PAGING), NULL);
來加載filesys.dll,接着通過下面語句:
hTh = CreateKernelThread ((LPTHREAD_START_ROUTINE)pfnMain, hFilesys, THREAD_RT_PRIORITY_NORMAL, 0);
來創建filesys.dll的線程WinMain(),這個線程在/WINCE600/PRIVATE/TEST/BASEOS/FILESYS/GENFILE/genfile.cpp中定義,這樣就接着執行這個線程。
Filesys.dll的主要工作是初始化文件系統、對象存儲、註冊表、CEDB數據庫、設備通知以及其它一些工作:
⑴Filesys.dll檢測是冷啓動還是熱啓動
如果是冷啓動,對象儲存內存將被初始化並映射給Filesys.dll;對於熱啓動,不用初始化而直接映射給Filesys.dll。
⑵Filesys.dll從nandflash中加載OEM的certification DLL。
⑶如果必須他能夠必須是冷啓動,Filesys.dll調用OAL函數pNotifyForceCleanboot。
⑷對於冷啓動,Filesys.dll調用OEMIoControl函數,I/O控制代碼爲IOCTL_HAL_INIT_RTC,也就是初始化RT。
Filesys.dll還有很多的動作,再這裏就不介紹了,我們接下來看看OEMIoControl函數是如何一層層調用到OALIoCtlHalInitRTC的呢?接着往下看。
OEMIoControl():在/WINCE600/PLATFORM/COMMON/SRC/COMMON/IOCTL/ioctl.c下面定義
從上圖可以知道OEMIoControl函數通過傳遞進來的code來和數組g_oalIoCtlTable中的code成員比較,找到吻合的code後便跳出這個for循環,然後往下執行。而數組g_oalIoCtlTable是在/Src/Oal/Oallib/ioctl.c下定義,如下圖
接着看ioctl_tab.h的內容
到這裏我們還是沒有直觀看到IOCTL_HAL_INIT_RTC,接着往下看oal_ioctl_tab.h的內容:
在上圖的第31行可以看到IOCTL_HAL_INIT_RTC,那麼對應於IOCTL_HAL_INIT_RTC的處理函數是如何得到執行的呢?上面提到,OEMIoControl函數通過傳遞進來的code找到數組g_oalIoCtlTable中吻合的code後,通過下面的處理
會記下i的值,也就是IOCTL_HAL_INIT_RTC所在數組g_oalIoCtlTable的索引值,接着看OEMIoControl函數下面的處理
這段代碼就是根據上面確定的i的值,來執行對應的handler,在這裏就是調用OALIoCtlHalInitRTC()函數
2.RTC初始化存在的問題
從上面可知,系統啓動過程是通過調用函數OALIoCtlHalInitRTC()來初始化RTC的,這個函數體如下
從這個函數體可知是通過調用OEMSetRealTime()來設置RTC的,g_oalRtcResetTime的定義如下:
SYSTEMTIME g_oalRtcResetTime = {2010, 8, 5, 27, 12, 0, 0, 0};
因爲我們的系統每次關機後重啓都是冷啓動,所以每次啓動之後都會調用到OALIoCtlHalInitRTC函數,從而不管你之前設置的時間是多少,都會重新初始化爲g_oalRtcResetTime中的時間。我把上圖的第98行替換爲下面的函數就可以解決了這個問題:
3.BOOL OEMSetRealTime(LPSYSTEMTIME pTime)
OEMGetRealTime()用來獲得當前的時間。WinCE啓動以後,默認情況下,WinCE會每隔一段時間調用OEMGetRealTime()函數來獲得系統的時間,這種方式被稱爲hardware mode。WinCE還有另一種獲得系統時間的方法,被稱爲software mode,就是通過調用GetTickCount()函數跟蹤系統的timetick的變化來累加時間。如果要用software mode,那麼需要在註冊表中做如下的設置:
HKEY_LOCAL_MACHINE/Platform/"SoftRTC" = 1
我來談談我的看法,一般都要使用hardware mode,這樣獲得的系統時間比較準。software mode獲得系統時間不會很準的。
4.BOOL OEMGetRealTime(SYSTEMTIME *pTime)
OEMGetRealTime()用來獲得當前的時間。WinCE啓動以後,默認情況下,WinCE會每隔一段時間調用OEMGetRealTime()函數來獲得系統的時間,這種方式被稱爲hardware mode。WinCE還有另一種獲得系統時間的方法,被稱爲software mode,就是通過調用GetTickCount()函數跟蹤系統的timetick的變化來累加時間。如果要用software mode,那麼需要在註冊表中做如下的設置:
HKEY_LOCAL_MACHINE/Platform/"SoftRTC" = 1
我來談談我的看法,一般都要使用hardware mode,這樣獲得的系統時間比較準。software mode獲得系統時間不會很準的。
5.BOOL OEMSetRealTime(LPSYSTEMTIME pTime)
OEMSetRealTime()用來設置當前的時間。當WinCE啓動以後,我們會在界面的右下角看到時間顯示,我們可以直接在WinCE的界面裏面設置時間,這個時候,系統就會調用OEMSetRealTime()把你設置的時間寫到RTC模塊裏面。
6.LPSYSTEMTIME
LPSYSTEMTIME實際上是一個指向SYSTEMTIME結構的指針,關於SYSTEMTIME,定義如下:
typedef struct _SYSTEMTIME
{
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
} SYSTEMTIME;