wince流驱动入门讲解

wince流驱动入门讲解
wince流驱动入门讲解

第一章驱动的准备

1. 驱动程序完成以下功能:

对设备初始化和释放;

把数据从内核传送到硬件和从硬件读取数据;

读取应用程序传送给设备文件的数据和回送应用程序请求的数据;

检测和处理设备出现的错误。

2. 整个硬件系统资源在驱动程序面前是赤裸裸的,驱动可以使用所有系统资源,编写驱动程序时我们必须格外小心驱动代码的边界条件,确保它们不会损坏整个操作系统。

3. WinCE毕竟是一个嵌入式系统,有其自身的特殊性,为了提高运行效率,所有驱动皆为动态链接库,驱动实现中可以调用所有标准的API。而在其他Windows系统中可能的驱动文件还有.vxd,.sys和动态链接库。

4. Windows支持的驱动:

1)虚拟设备驱动程序(V irtual Device Driver):Windows3.1(Windows95/98/Me)

2)内核模式驱动程序(Kernel Mode Driver):Windows NT

3)Win32驱动程序模型(Win32 Driver Mode):从Windows98开始使用。

其中WDM是目前主流,然而在WinCE系统中,由于硬件资源有限和嵌入式系统的特点,对其的支持非常有限。

第二章WINCE驱动

1.WINCE驱动模型

目前Windows CE提供了4种设备模型,其中2种专门用于Windows CE 模型,另外2种模型来自于其它的操系统,如图1所示:

图1 Windows CE 各种驱动模型的关系

2.我们的工作

为了帮助开发者快速地开发Windows CE 驱动程序,微软在Platform Builder 中提供了大量的驱动程序例源代码,同时,芯片厂商或OEM 厂商有时也提供一些设备的驱动程序源代码,这些驱动程序源代码在多数情况下可以直接拿来使用,但是在少数情况下需要开发者根据自己的设备硬件特性做一些移植的工作,修改例源代码,重新编译和调试驱动程序。移植工作虽然没有像开发一个全新的驱动程序那样富有挑战性,但它仍具有相当大的难度,其原因如下:

移植工作仍然要求开发者具有良好的软、硬件基础,熟悉驱动程序的基本开发和调试方法,并要求具有一定的开发环境和测试手段。

移植工作仍然需要了解驱动程序的架构,需要确切知道驱动程序对外暴露哪些接口,微软提供了哪些接口,还必须实现哪些接口等。

对于同一设备的驱动程序,其源代码往往位于Platform Builder 多个不同的安装目录,移植工作首先需要找出所移植驱动程序的所有源代码的位置。

移植工作需要在所移植驱动程序的所有源代码中区分出与硬件有关的代码和独立于硬件的代码,熟悉每个软件模块的大致功能,找出需要更改的与特定硬件有关的代码,并详细分析这些代码。

大部分驱动程序的代码放在目录%_WINCEROOT%\public\COMMON\oak\drivers\下,这些驱动程序都是与平台无关的。此外,对于不同的平台,在BSP 目录中也有一些驱动程序的代码,它们在%_WINCEROOT%platform\\src \drivers\中,这些驱动都是与平台相关的。

移植工作所修改的源代码有可能仅仅只有几十行甚至几行代码,但在修改之前却需要花费大量的时间了解驱动架构、熟悉驱动接口、分析源程序代码、找出需要修改的位置。本质上讲,移植与从头开发一个驱动的差别仅仅在于少写了很多程序。省去了编写这部分程序外部驱动模型

流接口驱动程序 本机驱动程序 NDIS 驱动程序 USB 驱动程序

设备管理器 GWES 系统引导时间 设备加载时间 应用程序加载时间

基于Windows CE 的驱动模型

的时,但对驱动程序开发者的水平要求似乎并没有丝毫的降低。

第三章流接口函数

流接口函数也称作流接口驱动程序的入口点,每个流接口驱动程序必须实现一组标准的函数,用来实现标准的文件I/O函数和电源管理函数,这些函数提供给Windows CE操作系统的内核使用。这些函数通常叫做流接口驱动程序的DLL接口。以下介绍几个主要的流接口驱动接口函数。

(1)DWORD XXX_Open(DWORD hDeviceContext,

DWORD AccessCode,

DWORD ShareMode)

参数:

DWORD hDeviceContext,设备驱动的句柄,由XXX_ Init函数创建的时候返回。

DWORD AccessCode,传给驱动程序使用的地址,这个地址跟读和写有关。

DWORD ShareMode,共享模式,这个参数用于一些特殊的设备。例如一些PC卡的设备读或写的时候是否可以共享。

返回值:返回驱动程序引用事例句柄。

描述:这个函数用于打开一个设备驱动程序,当应用程序准备对某一个设备进行读或写操作时,系统必须先执行CreateFile( )这个函数用于打开这个设备。这个函数执行以后系统才能够执行读和写操作。

(2)BOOL XXX _ Close(DWORD hOpenContext)

参数:

DWORD hOpenCnntext,设备驱动的引用事例句柄,由XXX_Open创建。

返回值:调用成功返回TRUE ,失败返回FALSE口

描述:这个函数用于关闭一个驱动程序的引用实例。应用程序通过CloseHandle()来调用这个函数,当执行完这个函数的时候驱动程序引用的事例,hOpenContext将不再有效。

(3)DWORD XXX_ Init(DWORD dwContext)

参数:

DWORD dwContext,指向字符串的指针。通常这个参数都为一个流接口驱动在注册表内的设置。

返回值:如果调用成功返回一个驱动程序的句柄。

描述:当用户开始使用一个设备的时候,例如,当PC卡初始化的时候,设备管理器调用这个函数来初始化PC卡设备。这个函数并不是由应用程序直接调用的,而是通过设备管理器提供的ActivateDeviceEx( )函数来调用的。函数执行后如果成功则返回一个设备的句柄。

(4)BDOL XXX_ Deinit(DWORD hDeviceContext)

参数:

DWORD hDeviceContext,由xxx_ Init创建时生成的设备句柄。

返回值:调用成功返回TRUE ,失败返回FALSE。

描述:当一个用户需要卸载一个驱动程序的时候,设备管理器调用这个函数来卸载这个驱动程序,应用程序不能够直接调用这个函数,设备管理器通过DeactivateDeviec()函数调用这个函数。

(5)DWORD XXX_ Read(DWORD hOpenContext,

LPVOID pBuffer,

DWORD Count)

参数:

DWORD hOpenContext, CreateFile()函数返回的句柄。

LPVOID pBuffer,一个缓冲区地址用于从驱动读数据。

DWORD Count,需要读缓冲区的长度。

返回值:实际读取字节的长度。

描述:这个函数与ReadFile很相似,当一个流接口驱动程序已经被打开后,应用程序可以使用ReadFile( )函数对这个设备进行读操作,ReadFile()里面的hFile参数就是这个设备的引用实例句柄hOpenContext,而参数lpBuffer将传给pBuffer,用于表示要读/写缓冲区的地址。参数nNumberofBytesToRead将传送给Count,用于表示要读写缓冲区的长度。同样,返回的参数,如果操作成功则返回实际读/写的地址,如果操作失败则返回值为-1。

(6)DWORD XXX_Write (DWDRD hOpenContext,

LPCVOID puffer,

DWDRD Count)

参数:

DWDRD hOpenContext,由CreateFile()函数返回的句柄。

LPVOID pBuffer,一个缓冲区地址,用于从驱动写数据。

DWORD Count,需要写缓冲区的长度。

返回值:实际写入字节的长度。

描述:当一个流接口驱动程序打开以后,应用程序可以使用WriteFile ()函数进行写操作。

(7)BOOL XXX_ IOControl (DWORD hQpenContext.

WORD dwCode,

PBYTE pBufIn,

DWORD dwLenIn,

PBYTE pBufOut,

DWORD dwLenDut,

PDWORD pdwActualOut )

参数:

DWORD hOpenContext,由CreateFile()函数返回的句柄。

WORD dwCode,特殊的WORD 型用于描述这次IOControl操作的语义,一般这个都由用户自己定义。

PBYTE pBufIn,缓冲区指针指向需要传送给驱动程序使用的数据。

DWORD dwLenIn,要传送给驱动程序使用数据的长度。

PI3YTE pBufOut,缓冲区指针指向驱动程序传给应用程序使用的数据:

DWDRD dwLEnOut,要传送给应用程序使用数据的长度。

PDWORD pdwActualOut,DWORD型指针用于返回实际处理数据的长度。

返回值:调用成功返回TRUE,调用失败返回FALSE。

描述:这个函数通常用于向设备发送命令。应用程序使用DeviceIOControl函数来通知操作系统调用这个函数。通过参数dwCode来通知驱动程序要执行的操作。这个函数扩展了流接口驱动程序的功能

(8)VOID XXX_ PowerDown (DWORD hDeviceContext)

参数:DWORD hDeviceContext,由XXX_ Init创建时生成的设备句柄。

返回值:无返回值。

(9)VOID XXX_PowerUp ( DWORD hDeviceContext )

参数:WORD hDeviceContext,由XXX_ init创建时生成的设备句柄。

返回值:无返回值。

描述:PowerDown和PowerUp这两个函数通常都必须要硬件的支持才能够有效,也是说相关的硬件必须支持PowerDown和PowerUp这两个模式。

(10)VOID XXX_Seek(hDeviceContext,

Long Amount,

WORD Type)

参数:

hDeviceContext,由XXX_ init创建时生成的设备句柄。

Long Amount 定义要移动的设备数据的指针的字节数

WORD Type 定义数据指针的起始点

返回值:无返回值

描述:当一个应用程序调用SetFilePointer函数移动设备数据指针时,操作系统会调用XXX_Seek函数。如果一个设备可以被多次打开,这个函数只修改由hDeviceContext定义的设备实例的数据指针。

第四章最简单的流接口函数

对于一个驱动我们要认清楚里面到底有哪些文件,他们的作用又是干什么的呢?下面以 SimpleDriver为例,进行第一个简单流接口驱动的讲解。

* 1.Makefile文件

这里的Makefile文件请不要和其他环境下(GCC,VS2005)的Makefile文件弄混,它是BSP里面的Makefile。Windows CE中的Makefile比较特别,它包含对所有项目都通用的配置信息。

其内容很简单,只有一句话:

!INCLUDE $(_MAKEENVROOT)\makefile.def

当build.exe查找dirs和source文件之后,它就会设置一个内部环境变量。这个环境变量可以被Nmake.exe传递给编译器、连接器或其他工具。

* 2.source文件

source也是一个文本文件,它为子目录中的源代码设置了不少宏定义。TARGETNAME=SimpleDriver

RELEASETYPE=PLA TFORM

TARGETTYPE=DYNLINK

TARGETLIBS=$(_COMMONSDKROOT)\lib\$(_CPUINDPA TH)\coredll.lib

DEFFILE=$(TARGETNAME).def

DLLENTRY=DllEntry

SOURCES=SimpleDriver.c

以上是simpledriver里面source的内容,具体解释如下:

TARGETNAME=SimpleDriver;指定生成最终生成的.exe,.lib,.dll文件的名称,这里是SimpleDriver.dll

RELEASETYPE=PLATFORM;它设置两种旗标:RELEASEDIR和RELEASELIBDIR,用于指定编译生成二进制和库文件存放的目录。默认情况下,为目标生成的二进制和库文件存放在目录%_PROJECTROOT%\oak下,这里存放在

D:\WINCE600\PLATFORM\Mini2440\target\ARMV4I\retail目录下。

TARGETTYPE=DYNLINK;这个宏定义指定构建文件的最终类型,可以把TARGETTYPE 类型设置为以下四种类型中的任意一种。

1)MANAGED_EXE;

2) MANAGED_DLL;

3) MANAGED_WINEXE;

4) MANAGED_MODULE;

这里设置的最终类型为dll。

TARGETLIBS=$(_COMMONSDKROOT)\lib\$(_CPUINDPATH)\coredll.lib;

_COMMONSDKROOT等价于\WINCE600\public\common\sdk

它指定了额外的库文件(.lib)和目标文件(.Obj)链接为目标可执行文件(.exe 或.dll).这里将 coredll.lib 链接生成最终的目标文件SimpleDriver.dll

DEFFILE=$(TARGETNAME).def;它指定模块定义文件(.def)的名称,这里指定了模块定义文件的名称为SimpleDriver.def

DLLENTRY=DllEntry;它为一个DLL文件指定DLL的入口函数,此时TARGETTYPE 被设置为DYNLINK。如果 DLLENTRY对应的值没有被设置时,那么DllMainCRTStartUp是DLL的C程序运行入口点。这里DLLENTRY的入口函数被指定为DllEntry,因而,上面的 TARGETTYPE被设置成DYNLINK;

SOURCES=SimpleDriver.c;它包含编译过程的文件列表,这些列表中包含汇编文件和源文件,这些文件的类型

有.cxx,.cpp,.c,.asm,.s,.src,.rc,.obj,.ire,.res,.odl,.tlb,.i,.cs,.resx 等。这些文件编译之后可能是静态库文件(.lib),也有可能是动态库文件(.dll)。这里编译过程中需要用到的源文件有SimpleDriver.c,编译之后的生成SimpleDriver.dll的动态链接库文件。

* 3.SimpleDriver.def文件

.def文件定义了DLL的导出函数列表。

这里包括的内容如下:

LIBRARY SimpleDriver

EXPORTS

SPL_Init

SPL_Deinit

SPL_Open

SPL_Close

SPL_Read

SPL_Write

SPL_Seek

SPL_IOControl

SPL_PowerDown

SPL_PowerUp

主要是针对当前流接口函数,将相应的函数导出。

* 4. SimpleDriver.h

这个而就不用多介绍了吧,主要是一些头文件的声明,定义等等

* 5.SimpleDriver.c

下面给出基本的代码,有些函数给出了空定义,方便以后实现,同时方便理解。

* 6. platform.reg

配置文件的编写。涉及到的文件

有.platform.bib,platform.reg,dirs,source,SimpleDriver.def,其中后面两个文件在前文已有绍,这里就以前两个配置文件为主。

首先,从注册表说起,先简单的介绍一下注册表:Makeimg.exe使用.reg文件来为CE镜像建立注册表并添加默认的键值。也就是说,在.reg中写入的注册表的键值会被默认地放入CE镜像的初始化注册表中。其中Platform.reg定义了目标设备硬件的注册表设置,Project.reg定义基于Windows CE项目工程的注册表设置。注册表键值的类型如下:

1.REG_SZ表示一个字符串类型,如reg_sz:”my string”。

2.REG_DWORD表示一个双字节类型,如dword:12345678(十六进制数)。

3.REG_MULTI_SZ表示多字符串类型,如multi_sz:“my string”,“my

string”。

4.REG_BINARY 二进制类型。

在实际应用中可以使用IF/ENDIF关键字来引入一个注册表设置块,通过设置一个环境变量或一个特殊的值来达到这个目的。

为了包含一个注册表设置块,当一个环境变量没有被设置或者没有等于一个特定的值的时候,引入的注册表设置块的行尾应使用一个空格和“!”。

这里比较好找,一目了然,在目录

D:\WINCE600\PLATFORM\SMDKXXXX\Files\platform.reg下添加:

[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\SPL]

"Prefix"="SPL"

"Dll"="SimplDriver.Dll"

"FriendlyName"="Simple Driver"

"Order"=dword:0//驱动安装顺序

"Index"=dword:0 //驱动名的数字部分

注:

Order

给所有的驱动设置相对安装顺序。Order 为0的驱动先安装,依次安装Order

为1,2,…的驱动。Oder可以让开发者保证有相到依赖关系的多个驱动以适当的顺序进行安装。

Index

指定在文件系统中的驱动名的数字部分。在默认情况下,带有前缀COM的驱动在文件系统中分配名字为 COM1,下一个即为COM2。为了保证驱动总是安装成COM2,必须提供Index = 2。

这样在WINCE启动时,就自动加载该驱动了。

* 7. platform.bib

接着我们介绍platform.bib文件,关于bib文件,这里做一个简要的介绍:二进制镜像文件构建文件(.bib)定义了哪个模块或者文件被包含到运行时的CE镜像中。在编译期间,makeimg.exe使若干个.bib文件合并成ce.bib文件,然后,romimage.exe使用ce.bib决定哪些文件应该被打包进运行时CE镜像中,它同时还使用ce.bib来决定如何加载模块和文件到CE镜像(下载到目标设备的CE镜像)所在的内存中。

按照功能划分,.bib文件可以分为如下几种类型。

(1)Platform.bib。Platform.bib位于目录

D:\WINCE600\PLATFORM\SMDK6410\Files,它包含硬件平台相关的

模块和文件,如目标设备的驱动文件。这些模块和文件是CE镜像

的入口,比如.exe文件,如波形音频文件(.wav)等。

(2)Project.bib。Project.bib 位于目录

D:\WINCE600\PUBLIC\CEBASE\OAK\FILES,如果我们新建一个工程

项目(OSDesign1)则这个工程位于目录:

D:\WINCE600\OSDesigns\OSDesign1\OSDesign1\Wince600\SMDK64

10_ARMV4I\OAK\files下。Project.bib文件定义与创建CE镜像的

工程相关的模块,如果在OSDesign1中创建了一个自己的模块或者

应用程序,那么就要把它们添加到Project.bib文件中的MODILES

部分。

(3)Common.bib。Common.bib位于目录

D:\WINCE600\PUBLIC\COMMON\OAK\FILES下,它定义了CE镜像文

件包含的通用显示驱动和核心系统模块。

(4)Config.bib。Config.bib位于目录

D:\WINCE600\PLATFORM\SMDK6410\Files下,它定义了ROM和RAM

的配置信息。它同样包含了CE镜像文件的MEMORY和CONFIG部分。

Config.bib的MEMORY部分定义了运行时CE镜像内存分配表,指

定了名称、地址、大小和MEMORY区域的类型。

.bib文件可以被分为四个部分,分别是MEMORY、CONFIG、MODULES和FILES。

下面将分别说明这四个部分各自的含义。

(1)MEMORY。定义可用的物理内存,包括起始地址、大小和内存类型。

(2)CONFIG。定义romimage.exe输出的配置选项。默认情况下,这个区域是在config.bib文件中。不过,也并不是.bib文件中必须要包含

CONFIG部分。

(3)FILES。指定放在CE镜像中的文件列表。

(4)MODULES。指定放在CE镜像总的模块列表,包括EXE和DLL文件,与FILES的区别是放在MODULES中的文件通常是代码文件,并且构

建系统时不会压缩这些文件。

这里我们主要介绍Modules部分。

Modules部分指定了哪些基于Windows CE的模块包含到CE镜像中,以及如何给加载到config.bib文件中的MEMORY部分建立内存表。这个部分可以包含200个模块,这些模块有源代码和数据两个部分组成。

MODULES的语法格式如下:

; Name Path Memory block Section override Memory Type

; --- ----- ------------ --------- --------

各参数之间用空格分隔。

NAME:这个参数指定了MODULES模块的名称。通常情况下,它就像被路径引用的文件名称一样。

PATH:指定要打包进CE镜像的MODULES模块的完整路径。

MEMORY BLOCK:这个参数指定romimage.exe加载目标模块到内存区域的ramimage(镜像)部分。这个内存位于config.bib文件中memory 部分指定的某一段内存。

SECTION OVERRIDE:这个参数的设置时可选的,它可以为modules、files 或者空。如果设置了这个参数,那么构建系统就会根据它来决定这一项是modules还是files。

TYPE:这个参数指定文件的类型,主要有以下几种类型,在实际的使用中可以选用其中的一种或者多种组合。

1.S:定义一个系统文件

2.H:定义一个隐藏文件

3.R:压缩资源,只应用于MODULES部分

4.C:如果应用于一个模块,则压缩全部内容

5.D:运行时不允许调试。

6.N:标记一个模块为不可信任的,只应用MODULES部分。

7.K:指定romimage.exe必须修正模块到一个内核地址。在这个过程

中,romimage.exe分配一个固定的虚拟地址给DLL,设置了此标志的

模块只可以被loadKernelLibrary()函数加载。

8.P:指定romimage.exe禁止在头文件中检查指定的CPU类型。这个

旗标只用于资源dll,可以在一种CPU伤编译,在不同CPU上使用。

9.M:表示对此页禁止按序调页。

10.U:表示不压缩此文件。

在目录D:\WINCE600\PLATFORM\SMDKXXXX\Files\platform.bib文件中有如下定义:

; Name Path Memory Type

; -------------- ---------------- ------------------

;-----------Simple Driver (caichang714@https://www.360docs.net/doc/e09940003.html,)-------------------

simpledriver.dll $(_FLATRELEASEDIR)\simpledriver.dll NK SHK

; @CESYSGEN ENDIF CE_MODULES_DEVICE

;--------------------------------------------------------------------

其中,_$(_FLATRELEASEDIR)\ 指的是生成的镜像所在目录,即

D:\WINCE600\OSDesigns\SMDKXXXX\SMDKXXXX\RelDir

结合上面的说明,我们可以知道,上面的语句的意思是将编译生成的simpledriver.dll模块加载到CE运行时镜像NK中。它的文件属性是系统文件,隐藏文件和内核模块,由romimage.exe分配一个固定的虚拟地址给simpledriver.DLL。

接着在D:\WINCE600\PLATFORM\SMDKXXXX\Src\Drivers目录下找到dirs文件,在里面添加:SimpleDriver\

最后点击build或者在dos环境下 build -c

OK!

到这里点击编译就可以了。这个新驱动程序的动态链接库将会被编译进内核。当调用CreateFile()函数(第一个参数是SPL)时就搜索注册表,设备管理器可以找到这个驱动,驱动的入口点可以用到其他程序。

第五章需要注意的事项

1.驱动程序的内存访问及函数入口

当要在内核模式下执行代码时,必要时需访问整个物理内存空间,这一点与用户模式下执行是截然不同的。因为一个在用户模式运行的IST需要通过访问一个物理内存块来与一个设备进行交互,所以必须要把这个物理内存块映射到IST运行的地址空间。把一个物理内存块映射到执行IST的地址空间有两种方法:V irtualAlloc()申请虚拟内存块和VirtualCopy()绑定物理内存块与虚拟内存块

1)申请一个虚拟内存块

LPVOID VirtualAlloc

(

LPVOID lpAdress, //申请虚拟内存块的起始地址

DWORD dwsize, //申请内存块的大小,以B为单位,不能设为0

DWORD flAllocationType, //申请的类型,分为COMMIT和RESERVE

//COMMIT:在内存或者磁盘上为指定的页面区域分配物理存储

//RESERVE:保留一定范围的IST进程的虚拟地址空间不分配物理存储

DWORD flProtect //访问权限

);如果调用成功,返回分配的首地址,调用失败,返回NULL你可以通过GetLastError函数来获取错误信息。

注:VirtualAlloc()函数对虚拟内存块的申请分为两步,首先是执行保留动作,它在此期间做的工作只是在进程的虚拟地址空间内保留一段空间,并没有分配实际的物理内存,保留的虚拟内存并不能被应用程序直接使用。其次,执行提交动作后,这样后才真正的为虚拟内存块映射一段物理内存。执行成功之后,将返回一个内存块指针给用户。

2)一个物理地址块与一个虚拟内存块的绑定

BOOL VirtualCopy

(

LPVOID lpvDest, //绑定目的地址:虚拟内存块

LPVOID lpvSrc, //绑定源地址:物理内存块

DWORD cbSize, //要绑定的大小

DWORD fdwProject //访问权限

)返回值:成功返回TRUE,失败返回FALSE

注:当虚拟内存所要的工作处理完成,需要调用VirtualFree()函数来释放此虚拟内存。

VirtualCopy()函数支持PAGE_PHYSICAL旗标,当映射驻留在512MB之外的物理内存时,也就是在物理地址大于0x1FFFFFFF时,必须设置此标志。

3)释放内存

BOOL VirtualFree(

LPVOID lpAddress, // 区域地址

SIZE_T dwSize, // 区域大小,字节

DWORD dwFreeType // 类型

);

LPVOID lpAddress, 要释放的页的区域的地址,如果dwFreeType指定为MEM_RELEASE且这个区域是被保留的话,那么这个地址就要指定为分配区域的首地址

SIZE_T dwSize, 要释放页的大小,如果dwFreeType类型中包含了MEM_RELEASE,则dwSize必须为0 DWORD dwFreeType类型说明

MEM_DECOMMIT 消VirtualAlloc提交的页

MEM_RELEASE指定页,如果指定了这个类型,则dwSize应设置为0, 否则函数会调用失败

返回值:

如果调用成功,返回一个非0值

调用失败,返回0

4)BOOL WINAPI DllEntry(HINSTANCE DllInstance, INT Reason, LPVOID Reserved )

这个函数是动态链接库的入口,每个动态链接库都需要输出这个函数,它只在动态库被加载和卸载时被调用,也就是设备管理器调用LoadLibrary而引起它被装入内存和调用UnloadLibrary将其从内存释放时被调用,因而它是每个动态链接库最早被调用的函数,一般用它做一些全局变量的初始化。

参数:

DllInstance:DLL的句柄,与一个EXE文件的句柄功能类似,一般可以通过它在得到DLL中的一些资源,例如对话框,除此之外一般没什么用处。

Reason:一般我们只关心两个值:DLL_PROCESS_ATTACH与DLL_PROCESS_DETACH,Reason等于前者是动态库被加载,等于后者是动态库被释放。所以,我们可以在Reason等于前者是初始化一些资源,等于后者时将其释放。

2.MDD与PDD

一个驱动程序通常会被分成硬件相关(PDD)与硬件无关(MDD)层两部分。

当然,这种分层不是必须的,只是采用这种分层以后可以少写很多代码,因为微软提供了很多驱动程序的MDD。即使CE中没有我们所写的驱动程序的样例,采用这种结构以后,当需要写第二个程序时,就可以重用它的代码,就可以提高开发效率。

MDD是提供同类型的设备(比如串口)都会有的功能,这样PDD基本上就只有寄存器操作了。像串口的中断处理,Read/Write函数,其大部分代码都是在MDD中实现的,不同的串口实现中只需要提供一些实际操作寄存器的函数。不同的驱动程序,其MDD与PDD 的接口不尽相同,所以,当我们面对一个具体的驱动程序时,需要查帮助弄清楚需要提供哪些函数

3 XXX_Init函数的返回句柄

通常,这个句柄是驱动程序自己保存数据的一个指针,我们在Init返回时告诉上层程序,以后上层调用其它函数(例如Open)时,会将这个值传入,这样,我们就可以访问自己的一些私有数据。当然,也可以返回一个任意的非0值。对于一个设备驱动程序,系统不用的层会有不同的句柄。我们在XXX_Init中返回的句柄保存在设备管理器中,别的程序中应

该是看不到的,而用CreateFile也会得到一个文件句柄,这个保存在哪我不知道。但和前者是不一样的。也就是说不同层的软件所关心的句柄也会不一样

4.DEBUGMSG与RETAILMSG的区别

它们都是输出调试信息用的,区别是:

DEBUGMSG只在DEBUG版中有效,RELEASE版中它被定义成了NULL。RETAILMSG在DEBUG和RELEASE版中都可以输出。

而且DEBUGMSG可以在运行时刻用DEBUZONE控制要不要输出信息。在ship build 时,RETAILMSG 和DEBUGMSG都无效

5.物理基地址到虚拟地址的映射:

在进行硬件设计的时候,每个外围设备相对CPU都有一个物理基地址及一段可寻址的地址空间,驱动程序需要访问这段地址空间以和设备进行通信,所以,驱动程序必须将这个物理的内存块映射到IST(中断服务线程)正在运行的的地址空间(虚拟地址空间),完成从物理地址到虚拟地址的映射。

通过执行下列两步可以完成这个映射:

(1)保留一个虚拟内存块。为此,调用VirtualAlloc函数,并必须传递MEM_RESERVE 值作为这个函数的一个参数。

(2)Windows CE分配内存并返回一个指向这个内存块的指针,然后需要将这个块与一个实际的物理内存块对应。为此调用VirtualCopy函数,并定义PAGE_NOCACHE参数以便在这个块里存储的数据不能够被缓冲,这个标志迫使系统不优化读操作。

6.基本调试方法

一般驱动程序可以用DEBUG版来调试,也可以用输出调试信息的方法。我们一般用这两个函数输出调试信息:RETAILMSG和DEBUGMS,后者只能在DEBUG版中输出,而前者在RELEASE和DEBUG版中都可以输出,而且,可以在系统运行时刻根据Debug Zone选择让DEBUGMSG输出哪些调试信息。

驱动程序的调试一般可以分为以下几步:

1.看驱动程序的DllEntry是否被调用。如果这个函数被调用,说明驱动程序的文件已经在CE的image中,而且与注册表中设置的文件名相同。

2.看Init 函数是否被调用。如果它被调用,刚说明注册表设置正确。如果它没有被调用,一般是因为注册表中的Prefix设置与Init函数前面那三个字符不相同。或者def文件中没有定义Init函数。如果这个函数能够被调用,但驱动程序还是不能正确加载,请详细检查代码。

实验五WinCE中的驱动程序开发

WinCE中的驱动程序开发 一.实验目的 1、熟悉WinCE中流式接口驱动程序的12个接口的功能。 2、掌握流式驱动程序的工作过程。 3、能够编写出流式接口的驱动程序。 二.实验内容 使用VS2005的智能设备应用程序开发方法,进行网络通信的编程,并通信多线程技术实现服务器与客户端之间的文件传输。 三.实验设备及工具 硬件:PC机一台; 软件:Windows XP操作系统,VS2005开发环境,WinCE 6.0开发环境,或Windows Mobile 5.0 SDK 四.实验步骤及说明 (1)写出流式接口驱动程序的12个接口,及每个接口的功能。 答:见教材515页 (2)写出流式驱动程序的工作过程。 答:第一步:加载驱动程序,主要有两种加载方式:(1)当系统启动时,设备管理器搜寻注册表的HKEY_LOCAL_MACHINE\Drivers\BuiltIn键下面的子键,并逐一加载该子键下的每一个驱动,此过程称为BusEnum;(2)应用程序可调用ActivateDeviceEx()函数动态地加载驱动程序。 第二步:设备管理器从注册表的dll键值中获取驱动程序所在的DLL文件名。 第三步:设备管理器调用LoadDriver()函数把该DLL加载到自己的虚拟地址空间中。 第四步:设备管理器在注册表的HKEY_LOCAL_MACHINE\Drivers\Active下,记录所有已经加载的驱动程序。 第五步:设备管理器调用驱动程序中的COM_Init函数,并把上一步中添加的注册表项的完整路径作为COM_Init函数的第1个参数传入驱动程序内。 第六步:在COM_Init中,通常须对硬件进行一些最基本的初始化操作。 通过以上的操作完成流式驱动程序的加载任务。 对驱动程序的操作: 第一步:应用程序使用该设备。首先,应用程序调用CreateFile(TEXT(“COM1”)….)打开设备。然后,文件系统判断打开的是文件还是设备。最后,如果打开的是设备,就将控制权交回设备管理器。 第二步:设备管理器调用驱动程序的COM_Open()函数打开设备。 第三步:COM_Open()函数把打开设备的结果返回给设备管理器。 第四步:设备管理器把SMP_open()的返回结果,返回给应用程序的CreateFile()函数调用。 通过第七步到第十步,设备已被成功打开,接下来可对设备进行读/写和控制操作。下面将以从设备中读取数据为例。 第一步:应用程序使用CreateFile()调用返回的句柄,调用函数ReadFile(),向设备发送读请求。

wince6.0_开发环境搭建

Window CE6.0开发平台搭建详解 2011年08月29日 Windows CE6.0的开发无非两大方面:操作系统开发和应用程序开发,操作系统开发包括系统的定制,驱动开发和其他需要完成的底层工作。应用程序开发主要是与实际应用结合紧密的程序开发。 要搭建这样的开发环境,至少要包括两部分,一个是硬件平台,一个是软件平台,在Windows CE6.0的开发中,微软公司把这些开发软件集成到了vs2005中。 Windows CE6.0开发环境需要安装的软件比较多、比较大,至少要10GB的空间,而且有着严格的安装顺序要求,一旦其中某一个环节出错,都会导致软件运行出现故障,为确保安装顺利,请仔细阅读本文,按照步骤一步一步进行安装。 一、所需安装软件 1、Visual Studio 2005 2、Visual Studio 2005 Service Pack 1 3、MSDN 4、platform builder for Windows Embedded CE6.0 5、Windows Embedded CE 6.0 Platform Builder Service Pack 1 6、Windows mobile 6的sdk 二、所用磁盘空间 在安装之前,请检查电脑的磁盘空间,VS2005和Windows Embedded CE6.0均是比较大 的软件,要占硬盘好10G多的空间,建议不要装在C盘,但是我装Windows Embedded CE6.0的时候,发现不能更改安装路径,没办法,只能把Windows Embedded CE6.0装在 C盘。 三、安装顺序 1.安装Visual Studio 2005 最好选择自定义安装方式,把不用的一些组件都删掉,这样会节省不少的磁盘空间。WINCE6.0的Platform Builder不像WINCE5.0是独立的,而是作为VS2005的插件,以后建立和定制OS、编译调试全部在VS2005里完成。 2.安装Visual Studio 2005 Service Pack 1

WINCE驱动开发中几个内存分配函数比较

【转】LocalAlloc,VirtualAlloc,malloc,new的异同首先明白几个概念:虚拟内存是从硬盘置换出来的,堆本身就是内存,程序运行时,可用内存=物理内存+虚拟内存。虚拟内存一般用文件来保存数据,虚拟内存的出现主要是因为以前内存不够(16M的内存刚出来的时候可是天价啊),磁盘相对便宜一些,所以聪明的系统设计者就把设计了虚拟内存,在程序运行的时候把那些很久没有被访问过的(可能以后也不会用到)内存映射到文件里面去(以后需要的时候再读进内存),把内存腾出来给真正需要执行的代码和数据,这样看起来可用内存就比物理内存多了。 HeapAlloc()是堆分配内存函数,查看c,c++的malloc,new函数的代码,可以看到就是对HeapAlloc()函数的封装,在堆上可以动态分配内存。 1. 首先我们来看HeapAlloc: MSDN上的解释为:HeapALloc是从堆上分配一块内存,且分配的内存是不可移动的(即如果没有连续的空间能满足分配的大小,程序不能将其他零散的空间利用起来,从而导致分配失败),该分配方法是从一指定地址开始分配,而不像GloabalAlloc是从全局堆上分配,这个有可能是全局,也有可能是局部。函数原型为: LPVOID HeapAlloc( HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes ); hHeap是进程堆内存开始位置。 dwFlags是分配堆内存的标志。包括HEAP_ZERO_MEMORY,即使分配的空间清零。 dwBytes是分配堆内存的大小。 其对应的释放空间函数为HeapFree。 2. 再看GlobalAlloc:该函数用于从全局堆中分配出内存供程序使用,函数原型为: HGLOBAL GlobalAlloc( UINT uFlags, SIZE_T dwBytes ); uFlags参数含义 GHND GMEM_MOVEABLE和GMEM_ZEROINIT的组合 GMEM_FIXED 分配固定内存,返回值是一个指针 GMEM_MOVEABLE 分配活动内存,在Win32中,内存块不能在物理内存中移动,但能在默认的堆中移动。返回值是内存对象的句柄,用函数GlobalLock可将句柄转化为指针 GMEM_ZEROINIT 将内存内容初始化为零 GPTR GMEM_FIXED和GMEM_ZEROINIT的组合

面向对象设计之定义领域服务

面向对象设计之定义领域服务 若遵循基于面向对象设计范式的领域驱动设计,并用以应对纷繁复杂的业务逻辑,则强调领域模型的充血设计模型已成为社区不争事实。我将Eric提及的战术设计要素如EnTIty、Value Object、Domain Service、Aggregate、Repository与Factory视为设计模型。这其中,只有EnTIty、Value Object和Domain Service才能表达领域逻辑。 为避免贫血模型,在封装领域逻辑时,考虑设计要素的顺序为: Value Object -》EnTIty -》Domain Service 切记,我们必须将Domain Service作为承担业务逻辑的最后的救命稻草。之所以把Domain Service放在最后,是因为我太清楚领域服务的强大魔力了。开发人员总会有一种惰性,很多时候不愿意仔细思考所谓职责(封装领域逻辑的行为)的正确履行者,而领域服务恰恰是最便捷的选择。 就我个人的理解,只有满足如下三个特征的领域行为才应该放到领域服务中: 领域行为需要多个领域实体参与协作 领域行为与状态无关 领域行为需要与外部资源(尤其是DB)协作 假设某系统的合同管理功能允许客户输入自编码,该自编码需要遵循一定的编码格式。在创建新合同时,客户输入自编码,系统需要检测该自编码是否在已有合同中已经存在。针对该需求,可以提炼出两个领域行为: 验证输入的自编码是否符合业务规则 检查自编码是否重复 在寻找职责的履行者时,我们应首先遵循信息专家模式,即拥有信息的对象就是操作该信息的专家,因此可以提出一个问题:领域行为要操作的数据由谁拥有?针对第一个领域行为,就是要确认谁拥有自编码格式的验证规则?有两个候选: 拥有自编码信息的合同(Contract)对象

WinCE驱动开发流程

wince驱动开发学习笔记 嵌入式技术/walking_man 发表于2007-03-20, 20:03 首先是wince驱动的分类问题。按照书上讲的说CE下驱动分成单体驱动和分层驱动,而看到另一种说法是本机驱动和流式驱动。经过microsun大哥的指点,把这两种分类法分开了。在这里引用一下:“单体与分层只是从代码的形式上做的分类.分层驱动代码上分为PD D与MDD,一般的微软已经实现了MDD,可能也实现了PDD,我们只需要对PDD做些修改就能使用,比如音频的驱动,显示的驱动。单层驱动是把PDD与MDD写在一起,没有做严格的区分,通常这种驱动比较简单,比如:ATADISK。 至于本地驱动和流式驱动是从驱动与系统其它模块(调用者)的接口 形式上做的分类.其实,本地驱动这个名称不大恰当,可能叫专用驱动或其它名字更为合适.它是指调用它的模块给它有特定的接口,比如电源驱动和通用LED驱动。而串口,网卡等就是流接口驱动程序. 所以,一个驱动程序可以是单体的流式驱动,例如:ATADISK.也可以 是分层的流式: 如OHCI ” 按照我的理解,单体和分层是驱动实现方式上的分类,而本地和流式则是驱动模型上的分类,所谓本地驱动就是操作系统有保留专门的接口,所谓流式是指编写的DLL文件里可以导出各种流式接口函数。 第二点:驱动的功能属性。设备驱动程序是操作系统内核和硬件的接口,操作系统定义了一组标准的接口,编写驱动的过程也就是实现这些接口。从应用程序到具体硬件间有如下这些环节起作用:

应用程序-调用OS函数-操作系统-驱动接口-驱动程序-硬件操作函数-硬件。在wince里驱动都以用户态的DLL存在,需要通过进程加载到slot里。共有三类系统进程用来加载:Device.exe,GWES.exe,File Sys.exe.绝大多数设备驱动都是通过Device.exe加载的。需要注意的是,不同的OS保留的设备驱动接口是不一样的,如桌面windows 和wince就不同。 第三点:wince下设备的初始化分为两个阶段:Device.exe的初始化;外设的枚举和加载。其流程是:上电-启动bootloader-启动N K-启动注册表init键(Device.exe启动)-初始化数据结构,I/O,电源管理等-加载BusEnum.dll(总线枚举器)-枚举注册表下Driver/buil din的所有子键。这里的枚举过程就是循环调用ActivateDeviceEx()函数加载驱动的过程。在OS启动完毕后,我们可以用PB的Remot e Registry Tool查看H_L_M/drivers/active包含的子键,看哪些驱动随启动而加载。 第四点:流接口驱动的概念。暴露流式接口函数的驱动即是流驱动,它把外设抽象成一个文件。过程是:应用程序使用文件API 对设备进行访问,OS接受API调用FileSys.exe,转到device.exe,调用流接口,与硬件交互。所谓流接口函数有十个,包括XXX_Init、XXX_Deinit、XXX_Open、XXX_Close、XXX_Read、XXX_Write、XXX_P owerUp、XXX_PowerDown、XXX_Seek、XXX_IOControl,在wince5.0中 增加le了XXX_PreClose,XXX_PreDeinit.而我们在应用程序里对应的文件A PI有CreateFile、DeviceIoControl、 ReadFile、 WriteFile,CloseHan dle,SetFilePointer. 第五点:编写流驱动的步骤。有两种实现途径:1。写DLL,做

WinCETouchPanel驱动详解

WinCEWinCEIWinCE Touch Panel 驱动详解 WinCE中的Touch Panel驱动是由GWE模块来管理的,Touch Panel驱动接收用户的触摸信息,并将其转换为屏幕上的坐标信息,传给GWE模块。在WinCE中, Touch Panel 驱动是分层的,分为MDDg和PDD层,这和其他WinCE设备驱动是一样的。MDDI由微软提供,用户只需要实现MD床口PDD层间的DDSI函数就可以了。如图 WinCE中的GWE模块负责加载和管理Touch Panel驱动,Touch Panel的MDD 层向上提供DDI接口,PDD层是针对硬件的实现,对MDD g提供DDSI接口。文档收集自网络,仅用于个人学习 1 Touch Panel驱动中的数据结构 ⑴ TOUCH _P ANEL_SA MP LE_FLAGS 用于描述一个采样点的信息,这些信息被定义在一个枚举结构中: enum enu mTouch Pan elSa mp leFlags { TouchSa mp leValidFlag = 0x01, TouchSa mp leDow nF lag = 0x02, TouchSa mp lelsCalibratedFlag = 0x04, TouchSa mpleP reviousDow nF lag = 0x08, TouchSa mp lelg nore = 0x10, TouchSa mp leMouse = 0x40000000 }; TouchSampleValidFlag :—个有效的采样值 TouchSa mp leDow nF lag:第一次按触摸屏时,返回该flag

技术讲解:嵌入式智能人机界面与PLC的通讯

技术讲解:嵌入式智能人机界面与PLC的通讯 1、引言近年来,嵌入式一词越来越多的被人们提及,嵌入式产品被应用到各行各业。与嵌入式相关的技术如嵌入式产品,嵌入式系统的研究等也被列为十五家发展的重点方向。 嵌入式系统(Embedded System)被定义为:以应用为中心,以计算机技术为基础,软件硬件可裁剪,适应对功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。 随着工业自动化的发展,基于PLC,单片机等设备的自动化系统,自动化设备越来越普及,几乎遍布所有自动化领域,与之相应的人机交互系统也应运而生,并得到同步发展。基于嵌入式技术的工业人机界面是人机交互系统中一颗耀眼的明星。高可靠,寿命,体积小,高性能,多线程,多任务,强实时等特点使嵌入式工业人机界面越来越受到自动化系统集成商,自动化设备制造商的青睐。它能够理想,生动地显示PLC,单片机等工业设备上的数据信息,功能强大,使用方便。它作为PLC等控制设备的上端设备在用户和机器之间架设了一条桥梁。该产品目前广泛应用在工业自动化系统,医疗,金融等行业的自动化设备。 随着越来越多的工程项目采用了嵌入式人机界面,相应的,用户对与嵌入式硬件配套使用的监控系统(SupervisoryControlandDataAcquisiTIon,SCADA)等应用软件的需求也在增加。这也正是本文所要讨论的问题。这里讲的嵌入式监控系统,其硬件为嵌入式智能人机界面;其软件为嵌入式操作系统,另加自己开发的应用程序。本文后面主要介绍这个监控应用程序,重点介绍应用程序中通讯部分的实现原理。 当今,已发展有多种嵌入式操作系统,如Linux,VxWorks,WinCE等,完全可在其上开发出图文并茂、界面友好的应用,以满足监控系统的种种要求。只是由于嵌入式技术相对是一门新兴的领先技术,涉足的人相对还比较少,所以这样的应用目前还比较少。本文介绍的嵌入式监控系统算是一个实例吧。 2、系统组成我们所开发的这套嵌入式监控系统,上位机是沈阳鹭岛资讯科技有限公司开发的嵌入式智能工业控制人机界面(以下简称人机界面)。其嵌入式工业控制器是以

Wince6.0驱动开发

Wince6.0驱动开发 (1) 在WINCE600\PLATFORM\LPC32XX \SRC\DRIVERS目录下新建一个目录MyDriver. (2) 在MyDriver目录下新建5个文件。 a) MyDriver.c 实现流接口函数的具体代码。 b) MyDriver.h 为MyDriver.h的头文件。 c) MyDriver.def 定义导出的函数名称。 d) makefile 与其它驱动的相同,不用改。 e) sources 链接和编绎文件。 (3) 前缀定义为MYD (4)文件内容完成后,在平台的“解决方案”的界面下,寻找FLATFORM\LPC32XX\src\drivers\MyDriver,然后单击鼠标右键,在弹出的菜单中选择“Build”,开始编绎驱动,完成后,在WINCE600\PLATFORM\LPC321XX\target\ARMV4I\retail下可找到MyDriver.dll. (5) 驱动加载的方法:手动,自动。 这里介绍自动加载的方法: a) 在MyDriver目录的位置找到dirs文件,在该文件中插入一行mydriver (都为小写),并在上一行后加“\”。 b) 在平台的“解决方案”的界面下,寻找FLATFORM\LPC32XX\Parameter Files\platform.bib.打开此文件,在相关位置添加mydriver(_FLATRELEASEDIR)\mydriver.dll NK SHK SHK指明该文件的属性,S—系统文件,H—隐藏文件,K—在内核中的位置固定。 c) 在Platform.req文件中相关位置添加程序如下: ;MyDriver [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\MYD] “Prefix”=”MYD”

WinCE中串口驱动及接口函数介绍

WinCE中串口驱动及接口函数介绍 串口驱动本身分为MDD层和PDD层。MDD层对上层的Device Manager提供了标准的流设备驱动接口(COM_***),PDD层实现了HWOBJ结构及结构中若干针对于串口硬件操作的函数指针,这些函数指针将指向PDD层中的串口操作函数。DDSI是指MDD层与PDD层的接口,在串口驱动中实际上就是指HWOBJ,PDD层会传给MDD层一个HWOBJ结构的指针,这样MDD层就可以调用PDD层的函数来操作串口。 微软针对于串口驱动提供了参考源代码,可以在下面的目录下找到:”\WINCE600\PUBLIC\COMMON\OAK\DRIVERS\SERIAL”。 串口驱动的结构也就是这样了,下面介绍相关的驱动中的接口。 1. HWOBJ结构 在串口驱动中,HWOBJ结构中的函数实现了对串口硬件的操作,并在MDD层被调用。可以说,该结构描述了串口设备的所有特性,先来介绍一下该结构,具体定义如下: typedef struct __HWOBJ { ULONG BindFlags; DWORD dwIntID; PHW_VTBL pFuncTbl; } HWOBJ, *PHWOBJ; BindFlags:用于控制MDD层如何来处理IST,具体值如下: THREAD_IN_PDD:MDD层不处理,中断在PDD层处理。 THREAD_AT_INIT:在驱动初始化的时候,MDD层启动IST。 THREAD_AT_OPEN:在驱动被Open的时候,MDD层启动IST。 dwInitID:系统的中断号 pFuncTbl:指向一个PHW_VTBL结构,该结构中包含一个函数指针列表,这些函数指针指向串口硬件操作函数,用于操作串口。 view plaincopy to clipboardprint? typedef struct __HW_VTBL { PVOID (*HWInit)(ULONG Identifier, PVOID pMDDContext); ULONG (*HWDeinit)(PVOID pHead); BOOL (*HWOpen)(PVOID pHead);

领域驱动设计(DDD)架构的实践

领域驱动设计(DDD)架构的实践

前言 至少30年以前,一些软件设计人员就已经意识到领域建模和设计的重要性,并形成一种思潮,Eric Evans将其定义为领域驱动设计(Domain-Driven Design,简称DDD)。在互联网开发“小步快跑,迭代试错”的大环境下,DDD似乎是一种比较“古老而缓慢”的思想。 然而,由于互联网公司也逐渐深入实体经济,业务日益复杂,我们在开发中也越来越多地遇到传统行业软件开发中所面临的问题。本文就先来讲一下这些问题,然后再尝试在实践中用DDD的思想来解决这些问题。 问题 过度耦合 业务初期,我们的功能大都非常简单,普通的CRUD就能满足,此时系统是清晰的。随着迭代的不断演化,业务逻辑变得越来越复杂,我们的系统也越来越冗杂。模块彼此关联,谁都很难说清模块的具体功能意图是啥。修改一个功能时,往往光回溯该功能需要的修改点就需要很长时间,更别提修改带来的不可预知的影响面。

下图是一个常见的系统耦合病例。 订单服务接口中提供了查询、创建订单相关的接口,也提供了订单评价、支付、保险的接口。同时我们的表也是一个订单大表,包含了非常多字段。在我们维护代码时,牵一发而动全身,很可能只是想改下评价相关的功能,却影响到了创单核心路径。虽然我们可以通过测试保证功能完备性,但当我们在订单领域有大量需求同时并行开发时,改动重叠、恶性循环、疲于奔命修改各种问题。 上述问题,归根到底在于系统架构不清晰,划分出来的模块内聚度低、高耦合。

有一种解决方案,按照演进式设计的理论,让系统的设计随着系统实现的增长而增长。我们不需要作提前设计,就让系统伴随业务成长而演进。这当然是可行的,敏捷实践中的重构、测试驱动设计及持续集成可以对付各种混乱问题。重构——保持行为不变的代码改善清除了不协调的局部设计,测试驱动设计确保对系统的更改不会导致系统丢失或破坏现有功能,持续集成则为团队提供了同一代码库。 在这三种实践中,重构是克服演进式设计中大杂烩问题的主力,通过在单独的类及方法级别上做一系列小步重构来完成。我们可以很容易重构出一个独立的类来放某些通用的逻辑,但是你会发现你很难给它一个业务上的含义,只能给予一个技术维度描绘的含义。这会带来什么问题呢?新同学并不总是知道对通用逻辑的改动或获取来自该类。显然,制定项目规范并不是好的idea。我们又闻到了代码即将腐败的味道。 事实上,你可能意识到问题之所在。在解决现实问题时,我们会将问题映射到脑海中的概念模型,在模型中解决问题,再将解决方案转换为实际的代码。上述问题在于我们解决了设计到代码之间的重构,但提炼出来的设计模型,并不具有实际的业务含义,这就导致在开发新需求时,其他同学并不能很自然地将业务问题映射到该设计模型。设计似乎变成了重构者的自娱自乐,代码继续腐败,重新重构……无休止的循环。 用DDD则可以很好地解决领域模型到设计模型的同步、演化,最后再将反映了领域的设计模型转为实际的代码。

嵌入式组态王Wince运行环境的安装与演示过程

嵌入式组态王在Wince 平台下的安装与演示过程 陕西威蓝工业自动化有限公司 2011.07.20

1.前期准备工作: (1)注册MSCOMM32.OCX控件: 打开组态王使用说明文档,把MSCOMM32.OCX控件拷贝到PC计算机的C 盘目录下,再打开开始运行cmd,进入命令环境 在C:\Documents and Settings\su>下编辑cd .. 直至切换到C:\> ,如下图

然后,编辑regsvr32 MSCOMM32.OCX,注册成功,如下图所示: (2)串口选择 RS232模块插入计算机后,在计算机设备管理器里确认端口,本例子使用串口5,如下图所示: 打开组态王使用说明文档里kingview com.exe可执行文件,在串口设置中选

择COM5,并点击“请选择串口”打开串口,如下图所示: (3)板子连线说明: 电源接直流5V电源,鼠标和USB线接USB2口(注意USB线上的三角箭头端与板子USB2三角箭头端对应),串口线接板子的COM1口(串口线三角箭头端靠网口那端),具体接法如下图所示:

2.安装组态王嵌入版运行系统: 第一步:将安装有组态王嵌入版开发系统的PC机和嵌入式系统连接在同一个局域网的同一个网段中。(如果采用网线直接将PC机和嵌入式系统设备连接的话,需要使用交叉网线)。 第二步:上电启动预先安装在系统上的WinCE系统,设置WinCE上的网络和拨号连接,给这个设备分配一个IP地址。 第三步:在嵌入式平台NandFlash目录下,建立一个文件夹kingview。 第三步:在PC机下将组态王嵌入版安装目录的ARMV4文件夹里面的全部内容(除了Driver文件夹)拷贝到U盘,再将此内容全部拷贝到嵌入式平台新建的kingview目录,同时在kingview目录下新建一个文件夹project。 第四步:在kingview目录下打开KV_FTP_SERVER.EXE,此时该界面显示IP地址: 如192.168.1.82

开发wince驱动步骤

开发wince驱动步骤: software:VS20005+wince6.0+BSP hardware:AT91SAM9261开发板(MCUZONE)1在vs2005新建一个驱动工程DemoDrv。

2编写好所有DemoDrv的源文件,例如“.cpp”or“.c”or“.REG”文件,特别注意source文件编写,然后单独编译DemoDrv看有无错误,这样避免全部编译NK导致时间太久。然后立即看到编译结果。若编译成功,会在$:\WINCE600\PLATFORM\AT91SAM9261EK\target目录有相应的DemoDrv.dll文件。(在实现文件“.c”需添加串口抛出信息以便调试)在如图所示:

3在目录$:\WINCE600\PLATFORM\AT91SAM9261EK\FILES找到配置文件:platform.reg 和platform.bib文件。 platform.bib文件添加: IF BSP_AT91SAM9261EK_DemoDrv DemoDrv.dll$(_FLATRELEASEDIR)\DemoDrv.dll NK SHK ENDIF BSP_AT91SAM9261EK_LED platform.reg文件添加: IF BSP_AT91SAM9261EK_DemoDrv #include"$(_TARGETPLATROOT)\SRC\DRIVERS\DemoDrv\DemoDrv.reg" ENDIF BSP_AT91SAM9261EK_LED 添加后分别保存。 4在$:\WINCE600\PLATFORM\AT91SAM9261EK\CATALOG目录下at91sam9261ek.PbcXml 文件打开: 添加文件: Item:ADENEO:BSP_AT91SAM9261EK_ DemoDrv Driver DemoDrv Driver for AT91SAM9261EK boards DemoDrv Driver for AT91SAM9261EK boards BspSpecific BSP_AT91SAM9261EK_DemoDrv Cpu:ARMV4I DemoDrv.dll Device Drivers\DemoDrv 保存文件 5新建NK工程文件或者手动方式更改之前NK工程文件,例如之前工程文件:E:\BSP\BSP\trunk\sample9261\Wince600\AT91SAM9261EK_ARMV4I\PBInitEnv.bat添加 set BSP_AT91SAM9261EK_DemoDrv=1

[教程]-领域驱动设计(DDD)

本文内容提要: 1. 领域驱动设计之领域模型 2. 为什么建立一个领域模型是重要的 3. 领域通用语言(Ubiquitous Language) 4.将领域模型转换为代码实现的最佳实践 5. 领域建模时思考问题的角度 6.领域驱动设计的标准分层架构 7. 领域驱动设计过程中使用的模式 关联的设计 实体(Entity) 值对象(Value Object) 领域服务(Domain Service) 聚合及聚合根(Aggregate,Aggregate Root) 工厂(Factory) 仓储(Repository) 8. 设计领域模型的一般步骤 9. 领域驱动设计的其他一些主题 10. 一些相关的扩展阅读 领域驱动设计之领域模型 2004年Eric Evans发表Domain-Driven Design – Tackling Complexity in the Heart of Software (领域驱动设计),简称Evans DDD。领域驱动设计分为两个阶段: 1. 以一种领域专家、设计人员、开发人员都能理解的―通用语言‖作为相互交流的工具,在不断交流的过程中不断发现一些主要的领域概念,然后将这些概念设计成一个领域模型; 2. 由领域模型驱动软件设计,用代码来表现该领域模型。 由此可见,领域驱动设计的核心是建立领域模型。领域模型在软件架构中处于核心地位;软件开发过程中,必须以建立领域模型为中心。 为什么建立一个领域模型是重要的 领域驱动设计告诉我们,在通过软件实现一个业务系统时,建立一个领域模型是非常重要和必要的,因为领域模型具有以下特点: 1. 领域模型是对具有某个边界的领域的一个抽象,反映了领域内用户业务需求的本质;领域模型是有边界的,只反应了我们在领域内所关注的部分;

Lazarus实战开发之串口通信(WINCE-WIN32)

Lazarus实战开发之串口通信(WINCE/WIN32) Lazarus最吸引人的地方就是她的开发方式类似Delphi,支持超好用的RAD开发方式,并且最厉害的地方是她还支持多个平台,多个CPU,例如ARM9的WINCE。 本文要讲述的就是“如何使用LAZARUS开发Wince上的串口程序”,并且,本文的串口程序同时支持WINCE和WINXP系统,当然编译时要选择平台啦。WINCE与WINXP 在本文中的代码区别只是OpenPort(‘COM1:’,CBR_9600,8,NOPARITY,ONESTOPBIT);//wince用COM1:表示串口1;WINXP用COM1表示串口1. 一、建立一个可重用的类,文件名为CE_Series.pas: unit CE_Series; interface uses Windows,Classes, SysUtils, LResources, StdCtrls,ExtCtrls; type TCE_Series = class(TObject) private hComm: THandle; public Function OpenPort(Port:LPCWSTR;BaudRate,ByteSize,Parity,StopBits:integer):String; procedure Send(str:String); Function Receive():String; procedure ClosePort(); end; implementation //============================================================================== ================= // 语法格式:OpenPort(Port:LPCWSTR;BaudRate,ByteSize,Parity,StopBits:integer)// 实现功能:打开串口 // 参数:port,串口号;例如wince下为从COM1:,COM2:。..。.win32下为COM1,COM2.。..。.. ;其他略,顾名思义哈 // 返回值:错误信息 //============================================================================== ================= function TCE_Series.OpenPort(Port:LPCWSTR;BaudRate,ByteSize,Parity,StopBits:integer):String; var cc:TCOMMCONFIG; begin result:=‘’; hComm:=CreateFile(port, GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0, 0); // 打开COM

领域知识模型

领域知识模型——企业应用系统的智慧中枢 摘要:企业应用系统有海量的领域对象和丰富的领域知识,这些领域知识一般被作为领域对象的业务逻辑或规则定义。本文认为领域知识是领域模型的一个知识切面且自成体系,结合领域驱动设计[DDD]和面向方面编程[AOP]的方法,对领域知识进行建模和应用,让面向业务活动的领域应用对象只需关注业务过程的组织和管理,用AOP技术把领域知识应用到具体的业务处理策略中,使领域应用对象和领域知识对象有更好内聚性且更轻量,不仅可大幅提升它们的可管理性和复用性,而且对系统开发效率、动态业务建模和装配能力也大有益处。 关键词:领域知识、领域模型、领域驱动设计、企业应用架构、DDD、AOP 1.前言 领域模型[Domain Model]和领域驱动设计[Domain-Driven Design][1]是目前在应用软件行业非常热门和前沿的话题,普遍认为这是构建高质量复杂系统最有效的方法和技术。领域模型在业界比较认可的定义是:领域模型是领域内的概念或者现实世界中对象的可视化表示,又称为概念模型、领域对象模型、分析对象模型,它专注于分析领域问题本身,领域对象是与技术无关的纯业务对象。领域建模的核心理念是把业务对象的属性、规则和职能封装在领域对象中,而不是被分散在用户界面层、应用层和持久化层中。 领域建模一般情况下是从应用功能或用例[Use Case]入手,因此,领域模型中的领域对象也是直接与应用功能或用例相关的业务对象,而这些领域对象模型涉及的领域知识,一般都作为领域对象的逻辑或者规则而存在。知识是应用领域问题的本质,是特定领域中一系列业务对象共有的知识切面,这个知识切面自成体系,本文中把这个知识体系的模型称为领域知识模型,与具体应用功能或者活动相关的领域对象模型称为领域应用模型。为了便于理解这些概念,我用一个与企业管理无关的通俗的例子来说明知识模型和应用模型的关系,比如对我喜欢的台球运动进行游戏建模,美式九球模型或者英式斯诺克模型是具体的领域应用模型,球台、球、球杆、运动员等是应用领域模型的核心领域对象,但要做出好玩的仿真游戏,台球碰撞中的基本物理知识是不可或缺的,用牛顿理论作为领域知识模型就涉及到质量、速度、动量等概念和动量守恒及能量守恒模型。知识模型是高度抽象并且可独立存在的模型,也是可以在各种业务情景中复用的模型,就如前面提到的台球游戏用到的牛顿理论模型,同样可以应用到保龄球游戏以及任何一款涉及到碰撞的游戏场景。企业管理领域也同样存在大量的知识模型,本文笔者致力于把企业管理领域涉及的领域知识进行分离、建模和应用的可行性分析和实践,希望以此进一步提升大型复杂企业应用系统的质量、动态业务建模和装配能力及组件复用水平。 2.企业应用系统中的领域知识问题分析 企业应用系统已逐渐成为企业经营管理的一体化应用平台,面向业务流程的行业深度应用

Windows CE嵌入式系统程序开发

Windows CE嵌入式系统程序开发 《Windows CE嵌入式系统程序开发》 基本信息 作者:胡文冯剑姜海涛胡玥 丛书名:单片机与嵌入式丛书 出版社:机械工业出版社 ISBN:9787111419150 上架时间:2013-5-8 出版日期:2013 年5月 开本:16开 页码:471 版次:1-1 所属分类:计算机 > 计算机组织与体系结构 > 嵌入式计算机 内容简介 计算机书籍 《windows ce嵌入式系统程序开发(基于arm11)》主要分为3部分,包括软件篇、硬件篇和项目篇。软件篇着重讲解了windows ce体系结构、搭建windows embedded ce 6.0开发环境和windows ce应用程序开发;硬件篇重点讲解了s3c6410硬件体系结构、windows ce boot loader与oal开发,在windows embedded ce 6.0和visual studio 2005开发环境下,采用c++开发接口驱动程序;项目篇提供完整的综合应用项目的程序开发实例,详细介绍了开发过程和源代码。并且安排了丰富的实验内容与课后实践,让读者深刻理解和掌握嵌

入式系统开发的整个过程,了解底层驱动程序驱动硬件的原理和上层应用程序的设计方法。 《windows ce嵌入式系统程序开发(基于arm11)》内容丰富实用,层次清晰,叙述详尽,方便教学与自学。本书可作为高等院校计算机类、电子类和控制类等专业高年级本科生、研究生学习嵌入式windows ce程序开发的教材,也可作为全国大学生电子设计竞赛培训教材,以及工程技术人员进行嵌入式系统开发与应用的参考书。 目录 《windows ce嵌入式系统程序开发(基于arm11)》 前言 第一部分软件篇 第1章windows ce系统结构 / 2 1.1 windows embedded ce 6.0的体系结构 / 2 1.2 内存管理 / 7 1.2.1 内存结构 / 7 1.2.2 windows embedded ce 6.0虚拟内存模型 / 8 1.3 文件系统与存储管理 / 12 1.3.1 文件系统 / 12 1.3.2 注册表 / 14 1.3.3 存储管理器 / 16 1.4 进程与线程 / 19 1.4.1 windows ce进程 / 19 1.4.2 windows ce线程 / 21 1.4.3 线程调度 / 24 1.4.4 线程同步 / 26 1.4.5 进程间通信 / 30 1.5 中断处理 / 31 1.5.1 中断基本概念 / 31 .1.5.2 中断服务例程 / 33 1.5.3 中断服务线程 / 34 第2章搭建windows ce开发环境 / 36 2.1 安装visual studio 2005 / 36

WinCE流驱动程序设计概述

微 处 理 机 M I CROPROCESS ORS W inCE 流驱动程序设计概述 顾峥浩,王自强,聂文华 (南京大学电子科学与工程系,南京210093) 摘 要:介绍了W inCE 操作系统下流驱动的设计方法,并在I ntel 公司的DBPXA255开发板下提供了关于8位数码管LED 的设计实例。 关键词:W inCE;流驱动;DBPXA255中图分类号:TP316.7 文献标识码:B 文章编号:1002-2279(2007)03-0081-03 The D e s i gn o f S tream I n te rface D ri ve r fo r W i nC E G U Zheng -hao,WANG Zi -qiang,N I E W en -hua (D epart m ent of Electronics and Engineering,N anjing U niversity,N anjing 210093,China ) Abstract:This paper intr oduces the strea m interface driver of W inCE,and p resents a sa mp le driver f or the Hex LED s of I ntel ’s DBPXA255. Key words:W inCE;Strea m interface driver;DBPXA255 1 引 言 W inCE 是一款由微软公司推出的面向嵌入式 领域的操作系统,被广泛应用于手机、P DA 、平板电 脑以及各种工控领域中。由于嵌入式设备硬件平台的多样性,针对不同的硬件编写驱动程序,从而使W inCE 上层屏蔽底层硬件的多样性就显得尤为重 要。 W inCE 的驱动按类型分有四种,分别为本地驱动(Native device driver )、流驱动、US B 驱动和网络驱动。其中流驱动由于接口简单、支持硬件设备最多,因而最为常用。下面将结合DBPXA255开发板中流驱动的一个简单实例,详细说明其设计方法。 2 流驱动开发的基本知识 2.1 开发W inCE 驱动的基本工具 驱动程序属于板级支持包(BSP )开发的一部分,可以使用微软的Platfor m Builder 工具进行设计。该工具将驱动编译成动态库,并整合到CE 系统中去。如果成功,则会得到一个NK .bin 的文件,此文件即为按照你的硬件平台定制的内核镜像,将其下载到嵌入式设备中就可以运行W inCE 了。笔者使用的是其.Net 版本。2.2 DBPXA255开发板 PXA255是I ntel 公司推出的取代Str ong AR M S A1110的新一代嵌入式应用处理器,属于ar m 系 列,它拥有Thumb 压缩指令、64位长乘法指令、增强型DSP 指令等先进特性,并集成了众多的外部接口,支持L inux 、W inCE 、Pal m OS 、Sy mbian OS 等主流嵌入式操作系统。DBPXA255开发板基于该型处理器,添加了一些外设如触摸屏、声卡接口等,在嵌入式开发中有着广泛的应用。2.3 W inCE 设备驱动程序的加载 大部分W inCE 驱动程序在系统引导的时候被设备管理器加载,加载信息被放在注册表的特定子键中,一般被设定为“HKEY _LOCAL _MACH I N E \DR I V ERS\BuiltI n ”。例如音频设备(W ave Dev )的加载信息: [HKEY _LOCAL _MACH I N E \D rivers \BuiltI n \W ave Dev\] "Prefix"="WAV ""D ll"="wavedev .dll" "I ndex"=dword:1"O rder"=dword:0 Prefix 的值代表设备的前缀名,用于标识与特 定名称设备相关联的文件流访问接口,必须由三个大写字母组成。在这里它的值为WAV ,那么设备的打开、关闭例程就为WAV_Open 和WAV_Cl ose 。 “D ll ”的值代表该设备驱动程序所在的动态库的名称,这里系统将在“wavedev.dll"中查找对 作者简介:顾峥浩(1981-),男,江苏无锡人,硕士研究生,主研方向:W inCE 、L inux 下嵌入式开发及应用。收稿日期:2005-03-02   第3期 2007年6月     No .3 Jun .,2007

相关文档
最新文档