Showing posts with label Application Programming. Show all posts
Showing posts with label Application Programming. Show all posts

Thursday, October 11, 2007

Mapping physical to virtual address

PVOID MmMapIoSpace(
   IN PHYSICAL_ADDRESS PhysicalAddress,
   IN ULONG NumberOfBytes,
   IN MEMORY_CACHING_TYPE CacheType
);

//----example:
PHYSICAL_ADDRESS RegPA;
ULONG uBase;

RegPA.QuadPart = 0xA0000000;
uBase = (ULONG)MmMapIoSpace(RegPA, 4, 0);

//----

//Header: CEDDK.h
//Link Library: CEDDK.lib

出現link error的話,把ceddk.lib的path加到
Project -> Settings -> Link的object/library modules應該就可以過了


from WinCE driver and BSP Develop blog
驅動開發過程中可能遇到以下幾種與內在訪問相關的情況:

1.CPU訪問設備寄存器:
在ARM中可以直接將設備的寄存器映射到ARM的存儲空間中,我們需要使用幾個函數將硬體寄存器位址映射到系統空間:
如果已知硬體的虛擬位址,可以使用VirtualAlloc,VirtualCopy,
如果已知硬體的物理位址,需要使用MmMapIoSpace映射.

2.CPU與DMA或其他硬體交換資料。
DMA需要使用物理位址,因為DMA訪問記憶體時不會向CPU一樣先經過MMU,所以它使用物理位址。如果硬體需要與CPU交互資料,比如CPU需要將圖像畫到LCD控制器使用的記憶體中,LCD才會將其顯示出來。我們在設置硬體硬體時需要將CPU使用的虛擬位址轉換成物理位址,再告訴硬體物理位址。通常有以下幾種辦法:

1. 為該硬體保留一塊記憶體空間。一般用於記憶體使用量比較大的,且位址不再改變的設備,例如LCD控制器。
記錄下該塊記憶體的物理位址給硬體使用,計算出該塊記憶體的虛擬位址位址給CPU使用。

2. 當驅動需要訪問硬體時才將虛擬位址轉換成物理位址,一般用在記憶體空間經常變化的場合。例如塊設備的驅動,檔系統或者其他上層程式讀寫資料時並不會保證每次使用同一段位址。這種情況下,可以使用LockPages函數將虛擬位址轉換成物理位址。

3. 分配一塊物理位址,這可以用在記憶體位址不需要變化,且用量不大的情況,這時可以用AllocPhysMem分配一塊位址,同時得到物理位址與虛擬位址。

Wednesday, October 3, 2007

CString

總算找到一篇比較完整的介紹文
有關CString轉換
int to string
string to int(signed, unsigned) 等等...
CString Management from Code Project
翻譯篇


Generic Text Mapping的觀念
字集設定 ANSI / UNICODE (窄字元 / 寬字元 / neutral)

Wednesday, August 1, 2007

在CE下自動開啟目錄

沒想到msdn library有CreateDirectory, RemoveDirectory
但就是沒有OpenDirectory
還好達哥之前有寫過
不然這個方法我大概要找很久吧 orz

void OpenFolder()
{
HWND hwnd;
SHELLEXECUTEINFO si;

memset (&si, 0, sizeof (si));
si.cbSize = sizeof (si);
si.fMask = 0;
si.hwnd = hwnd;
si.lpFile = TEXT ("\\My Flash Disk\\PEtestfolder"); //要開啟的資料夾
si.lpVerb = TEXT ("explore"); //特定參數

ShellExecuteEx (&si);
}

lpVerb
Long pointer to a string specifying the name of a verb. The verb specifies an action for the application to perform. The set of available verbs depends on the particular file or folder. It includes the commands listed in the context menu and the registry. The following table shows verbs that are usually valid.
Value Description
Edit The function opens an editor.
Find The function initiates a search starting from the specified directory.
Open The function opens the file specified by the lpFile parameter. The file can be an executable file or a document file. It can also be a folder. This is the default verb if no verb is specified.
Print The function prints the document file specified by lpFile.

其他的verbs要參考registry的HKEY_CLASSES_ROOT\object_name\Shell\verb

不懂的是explore這個參數是哪來的,如果設Open會不會有一樣的結果?
試了之後發現
也是可以的!

Friday, July 20, 2007

Loading Stream driver from ap

如果不想要系統啟動時由DeviceManager自動載入我們寫的driver,而是經由上層ap呼叫去load的話,則在platform.reg有一個地方要改 : 就是把[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Cin]的BuiltIn拿掉,系統就不會自動載入了,路徑可自定,不要在BuiltIn底下即可。
e.g. [HKEY_LOCAL_MACHINE\Drivers\Cin]


//cintest.cpp - demo ap to load driver
//---------------------------------------------------------------------------------
HANDLE hDevice; //handle to initialize the driver
HANDLE hSerial; //handle to open the driver, used by write, read, seek and ioctrl

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {
DWORD cBytes_out, cBytes_in;

char cBuffer_out[] = "\f\n Hello WORLD! \n\r";
TCHAR cBuffer_in[80];

printf("\n CinTest Demo driver \n");

//使用ActivateDeviceEx時,lpszDevKey 路徑不用加上 HKEY_LOCAL_MACHINE,加的話driver叫不起來
hDevice = ActivateDeviceEx(L"Drivers\\Cin", NULL, 0, 0);
if (hDevice == INVALID_HANDLE_VALUE) { printf("file init errors \n", "%X", hDevice); return 0; }

hSerial = CreateFile(_T("CIN1:"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);

if (hSerial == INVALID_HANDLE_VALUE) { printf("file open errors \n", "%X", hSerial); Sleep(4000); return 0; }

if (!WriteFile(hSerial, cBuffer_out, strlen(cBuffer_out), &cBytes_out, NULL))
{ printf("file write errors\n"); Sleep(4000); return 0; }
cBuffer_in[0] = 0;


if (ReadFile(hSerial, cBuffer_in, 1, &cBytes_in, NULL))
{
if (!WriteFile(hSerial, cBuffer_in, cBytes_in, &cBytes_out, NULL))
{ printf("\rfile write errors\n"); Sleep(4000); return 0; }
}

CloseHandle(hSerial);
DeactivateDevice(hDevice);
return 0;
}

Result :

Tuesday, June 5, 2007

MEDC 2007

APP321
Building World-Ready Windows Mobile© Applications by Mel Sampat

這堂演講的主題是寫程式的人該如何撰寫
讓application在轉換語言及使用設定(ex 時間日期格式)時可以輕鬆移植

Design strategies

  • Larger Text Fields -> 30% larger is a general rule.
  • Avoid Run-time string composition (各國語法不同 )
ex:
"are you sure you want to delete file?"
"are you sure you want to delete directory?"
"are you sure you want to delete subdirectory?"

char String[] = "are you sure you want to delete";
char FinalString[] = String + object + "?";

  • Avoid reusing resources (指重複相同的名詞但意義上不同會造成翻譯人員的困擾 orz)
  • Use FORMATMESSAGE instead of wsprintf (避免格式化時data buffer不足)
  • Use MUI DLLs (multilingual user interface DLLs)
  • Use NLS APIs (national language support APIs)

International API

Thursday, May 17, 2007

KernelIOControl function

Parameter Bits Win32 Type Managed Type Typical Value
dwIoControlCode 32 DWORD Int32 IOCTL_HAL_GET_DEVICEID
lpInBuf 32 LPVOID IntPtr IntPtr.Zero (no input data required)
nInBufSize 32 DWORD Int32 0 (no input data required)
lpOutBuf 32 DEVICE_ID* byte[] byte[20] (20 bytes is the size of the DEVICE_ID structure)
nOutBufSize 32 DWORD Int32 20
lpBytesReturned 32 LPDWORD ref Int32 0

On Windows CE, the Platform ID and Preset ID can be any length.
e.g. int = KernelIoControl(IOCTL_HAL_GET_DEVICEID, NULL,
sizeof(DWORD), (VOID*)val, sizeof(DEVICE_ID), NULL);


Get Device ID

Tuesday, May 15, 2007

SendMessage & PostMessage

BOOL PostMessage(

... );

LRESULT SendMessage(

... );

SendMessage的傳回值是LRESULT、PostMessage的傳回直是bool

PostMessage 是將一個訊息送往某一個視窗 handle 的Message Queue,
所以應用程式本身並不會知道也不想知道這個
Message的處理結果,
但是SendMessage便不同了,
應用程式可以由傳回值知道這個Message的處理結果
那麼, 在程式發出 SendMessage 的請求時,
我們程式便將控制權移交給接受該Message的視窗,
等待他處理結束該
Message
所以該Message並不會送往 Message Queue,
而是直接執行該處理訊息函示

PostMessage和SendMessage的區別
Message Queue


差別在於同步跟非同步...

接收broadcast訊息

how to broadcast:

#define WM_HOLDKEY_ON (WM_USER+3041)
....
void InitThread()
{
WNDCLASS wndclass;
HANDLE hEvent[n]={0};
DWORD dwStatus;

hEvent[0] = CreateEvent(NULL, FALSE, FALSE, kHoldKeyEventName);
....
while(TRUE)
{
dwStatus = WaitForMultipleObjects(n, hEvent, FALSE, INFINITE);

switch(dwStatus)
{
case (WAIT_OBJECT_0 + 0):
SendMessage(HWND_BROADCAST,WM_HOLDKEY_ON,0,0);
break;
....}
}
}

catch broadcast message using MFC:

#define WM_HOLDKEY_ON (WM_USER+3041)
....
BEGIN_MESSAGE_MAP(CCatchBroadcast, CDialog)
ON_MESSAGE(WM_HOLDKEY_ON, OnHOLDKEY_ON)
END_MESSAGE_MAP()

....
LRESULT CCatchBroadcast::OnHOLDKEY_ON(WPARAM wParam, LPARAM lParam)
{
//do whatever
return 0;
}

using WIN API(not MFC):

#define WM_HOLDKEY_ON (WM_USER+3041)
....
LRESULT CALLBACK xxxMainProc (HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
switch (iMessage)
{
....
case WM_HOLDKEY_ON:
//do whatever
break;}
return FALSE;
}


The WM_USER constant is used by applications to help define private messages for use by private window classes, usually of the form WM_USER+X, where X is an integer value.
WM_HOLDKEY_ON, 3041 是自己定義的,建立溝通可用這個方式傳送及接收自己定義的訊息

MFC message map 簡單明瞭的解釋處理訊息的三種方式~ 只有MFC的寫法

Wednesday, April 25, 2007

如何讓APP跟Driver同步

//以HOLD KEY為例
//Driver side create event

#define kHoldKeyEventName TEXT("HoldKey")
#define kUnHoldKeyEventName TEXT("UnHoldKey")
HANDLE hHoldKeyEvent;
HANDLE hUnHoldKeyEvent;

IniTFunction() {
...
...
hHoldKeyEvent = CreateEvent(NULL, FALSE, FALSE, kHoldKeyEventName);
hUnHoldKeyEvent = CreateEvent(NULL, FALSE, FALSE, kUnHoldKeyEventName);
...
...
}


HandlerFunction() {
...
if(holdkey) {
...
SetEvent(hHoldKeyEvent);
... }
else {
SetEvent(hUnHoldKeyEvent);
... }
}

---------------------------------------------------------------------
//Application side
#define kHoldKeyEventName TEXT("HoldKey")
#define kUnHoldKeyEventName TEXT("UnHoldKey")

int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow) {
...
InitThread();
...
}

//Single thread
void InitThread() {
HANDLE hEvent[2]={0};
DWORD dwStatus;

hEvent[0] = CreateEvent(NULL, FALSE, FALSE, kHoldKeyEventName);
hEvent[1] = CreateEvent(NULL, FALSE, FALSE, kUnHoldKeyEventName);

while(TRUE) {
dwStatus = WaitForMultipleObjects(2, hEvent, FALSE, INFINITE);

switch(dwStatus) {
case (WAIT_OBJECT_0 + 0):
break;

case (WAIT_OBJECT_0 + 1):
break; } }
}

Wednesday, March 28, 2007

problem: cannot open COM port

scene: xDevice --(I2C)--> xDriver --(stream interface)--> OS --(file object)--> Application

xDriver provides stream interface for COM port driver to the OS, and the OS provides file objects of a COM port device to applications. The application obtains information from xDriver through file objects to the COM port.

for example: (sample code on application layer)

BOOL xDriver::Open()
{
m_Handle = CreateFile( _T("COM7:"),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);

if(m_Handle == INVALID_HANDLE_VALUE) return FALSE;
return TRUE;
}

如果return false, 一個原因可能是與registry記錄的"Index"值不同而無法開啟。
in my case,
到 "...PLATFORM\PROJECT\FILES" -> PLATFORM.REG
然後查是否有 跟ap code 相對應的driver的 registry
如果有相對應的driver存在,檢查
"Prefix"="COM"
"Index"=dword:6
可以看到此driver是透過COM6,因此只要把sample code的 COM7 改成 COM6 就可以溝通了