精华内容
下载资源
问答
  • PCIE驱动开发

    热门讨论 2017-11-13 13:40:38
    linux设备驱动之PCIE驱动开发(内含Makefile,直接编译即可使用) ,具体使用参考博客 http://blog.csdn.net/u010872301/article/details/78519371
  • Android驱动开发与移植实战详解,完整扫描版

    千次下载 热门讨论 2014-03-13 21:39:22
    在每一章中,重点介绍了与Android驱动开发相关的底层知识,并对Android源码进行了详细的分析及驱动开发实现。 《Android驱动开发与移植实战详解》适合Android程序员、研发人员及Android爱好者学习,也可以作为相关...
  • 本文件夹旨在帮助广大同学们学习windows wdf驱动开发。重点是usb驱动开发。学习完这三个文件后,你将拥有为usb设备开发windows驱动程序的能力。如需学习stm32 usb设备的开发,敬请关注本人csdn账号。本人有stm32 usb...
  • 嵌入式Linux驱动开发

    千人学习 2019-05-11 21:05:29
    说到Linux驱动,尤其是嵌入式Linux驱动,大家可能会望而却步,因为入门太难!很多书上或课程基本是这样的:一上来给我们...从最简单的入手,一步一步,手把手的编写代码,一步步引领你进入嵌入式Linux驱动开发的大门。
  • Spring注解驱动开发

    万人学习 2018-03-28 14:12:13
    《Spring注解驱动开发》是一套帮助我们深入了解Spring原理机制的教程; 现今SpringBoot、SpringCloud技术非常火热,作为Spring之上的框架,他们大量使用到了Spring的一些底层注解、原理,比如@Conditional、@Import...
  • 驱动开发入门 - 之一:Win7 SP1 x64 驱动开发环境搭建

    万次阅读 多人点赞 2017-10-06 21:48:51
    本文讲述在Win7 SP1 x64系统中,如何搭建基于WDK7600的驱动开发环境

    驱动开发入门 - 之一
    Win7 SP1 x64 驱动开发环境搭建

    *—— By EXP 2017-10-04*

    完整原文下载(转载请注明出处,仅供分享学习,严禁用于商业用途)


    1. 概述

    1.1. 前言

    适读人群:具备良好的C/C++开发经验,一定的逆向工程基础。

    本文仅讲述在Win7 SP1 x64系统中,搭建基于WDK7600的驱动开发环境,不会解析任何驱动开发的代码。

    之所以撰写本文,是因为网上充斥着大量已经过时的基于WinXP(x86)-DDK的驱动开发教程、或针对Win(x64)-WDK但不成体系的驱动开发教程,导致新同学在搭建开发环境时遇到的各种问题难以被解决。

    所谓工欲善其事、必先利其器,特此记录并整理了在64位系统中,从搭建驱动环境到安装调试驱动程序的每个步骤、可能遇到的问题以及解决方案,以供其他同学做入门参考,降低学习成本。

    另外驱动程序是不存在兼容一说的(即x86的驱动只能运行在x86系统、x64的驱动只能运行在x64的系统),但是x86已经被逐步淘汰了,因此本文只会针对x64进行说明(其实x86也是大同小异)。


    1.2. 名词解析

    名词英文原文解析
    VxDVirtual Device Driver虚拟设备驱动程序
    DDKDevice Development Kit设备驱动程序开发工具包,广泛应用于XP-x86年代,已淘汰
    WDMWindows Driver ModelWindows驱动模型
    WDKWindows Driver KitWindows驱动开发工具
    WDFWindows Driver FoundationWindows驱动开发框架
    MSDNMicrosoft Developer Network微软以 Visual Studio 和 Windows 平台为核心整合的开发虚拟社区
    提供面向软件开发者的信息服务(包括技术文档、产品下载、Blog等)
    KMDFKernel-Mode DriverFramework内核模式驱动程序
    UMDFUser-Mode DriverFramework用户模式驱动程序
    chkChecked(debug)调试版本标识
    freFree(retail,或release)发布版本标识

    1.3 WDK简史

    ——部分内容摘于博文:http://lib.csdn.net/article/dotnet/41373

    早期的Windows 95/98的设备驱动是VxD,其中x表示某一类设备。从Windows 2000开始,开发驱动程序必以WDM为基础的,但如果使用DDK来开发WDM,其开发难度之大,根本不能奢望像用户模式应用程序开发那样容易。
      为改善这种局面,从Vista开始,微软推出了新的驱动程序开发环境WDF。WDF是微软提出的下一代全新的驱动程序模型,它是在WDM的基础上发展而来的,支持面向对象、事件驱动的驱动程序开发,提供了比WDM更高层次抽象的高度灵活、可扩展、可诊断的驱动程序框架。WDF框架管理了大多数与操作系统相关的交互,实现了公共的驱动程序功能(如电源管理、PnP支持),隔离了设备驱动程序与操作系统内核,降低了驱动程序对内核的影响。
      在众多WDK版本之中,WDK7600算是承上启下的一个版本。因为在此之前的驱动开发主要都是基于XP的DDK,难度过大且已过时。
      微软在Win7/Vista时期对DDK做了集成优化衍生出WDK,且适用于之后的Win8/Win10。
      但是微软在WDK7600以后就不再提供独立的内核驱动开发包了,并以Win8/Win10+WDK10 为主提供了集成度更高的WDF(使得Visual Studio可以集开发、编译、安装、部署和调试于一身),但是环境配置差异变化较大,且由于本人不喜欢Win8/Win10系统,有兴趣的同学可以自行研究,本文仅以WDK7600为核心搭建驱动环境


    2. 操作系统与预装组件

    ① 系统版本: Win7 SP1 x64 (必须升级到SP1版本)
      ② C/C++ x64 .NET 库:需安装四个版本 [v2.0.50727] [v3.0] [v3.5] [v4.0.30319]
      ③ Microsoft Office 2007:安装 Visual Studio IDE(VS2008 / VS2010)前置组件


    3. 相关工具安装

    3.1. 安装清单

    部分工具的功能是重复的,请根据下文所建议的两种开发环境选择性安装。

    表 1 安装清单(安装顺序建议与清单保持一致)
    工具版本用途备注下载
    Visual Studio2008 x64C/C++程序开发IDE
    用于驱动程序编码
    需先安装前置程序/库:
    .NET x64 v2.0.50727
    .NET x64 v3.0
    .NET x64 v3.5
    .NET x64 v4.0.30319
    Microsoft Office 2007
    Visual Studio2010 x64C/C++程序开发IDE
    用于驱动程序编码
    需先安装前置程序/库:
    .NET x64 v2.0.50727
    .NET x64 v3.0
    .NET x64 v3.5
    .NET x64 v4.0.30319
    Microsoft Office 2007
    Visual Assist X10.8.2007VS IDE 辅助插件可选安装,提供编码提示、补全等辅助功能CSDN
    WDK7600微软提供的Win驱动开发工具包提供驱动开发的API(头文件)、库文件等官方地址
    DDKWizard1.3aVS2008驱动模板生成插件可在VS2008中直接创建驱动程序开发模板官方地址
    CSDN
    ddkbuild.bat
    ddkbuild.cmd
    1.3aVS2008驱动程序生成脚本需配合WDK与DDKWizard使用官方地址
    CSDN
    EasySYS0.3.2.7VS2010驱动模板生成工具生成可被VS2010导入的驱动程序开发模板CSDN
    64Signer1.2内核驱动程序数字签名工具Win7之后的64位系统的内核驱动程序必须具备数字签名,此工具可伪造测试用的数字签名CSDN
    DriverMonitor3.2.0内核驱动程序调试器XP x86用于安装、启动内核程序的调试工具,Win7 x64可能不兼容CSDN
    InstDrv1.3.0内核驱动程序调试器Win7用于安装、启动内核程序的调试工具CSDN
    DebugView4.81内核驱动消息捕获器配合DriverMonitor或InstDrv使用,用于调试内核程序断点打印消息CSDN
    VMWare11.1.2虚拟机用于搭建隔离环境调试驱动程序
    WinDbgWindows平台下的用户态和内核态调试工具用于配合虚拟机双机调试驱动程序官方地址
    CSDN

    3.2. WDK的安装与配置

    下载WDK的安装镜像GRMWDK_EN_7600_1.ISO,安装到任意目录即可。
      本文的安装目录为:E:\04_work\re\WDK
      环境变量配置:
      ① 右击【计算机】–>【属性】–>【高级系统设置】–>【高级选项卡】–>【环境变量】
      ② 在【系统变量】中新建四个变量:

    变量名变量值备注
    W7BASEE:\04_work\re\WDKWin7用, Win7 必须配置
    WLHBASEE:\04_work\re\WDKWin Vista\2008 用,Win7 必须配置
    WNETBASEE:\04_work\re\WDKWin 2003 用,Win7可选配置
    WXPBASEE:\04_work\re\WDKWin XP 用,Win7可选配置

    注:建议添加所有环境变量


    4. 驱动开发环境配置

    VS2008 与 VS2010 两种开发环境 任选其一即可
      若只是开发简单的驱动程序且不涉及到汇编指令,VS2008环境更便捷。但若驱动程序需要嵌入汇编语言,则推荐使用VS2010。
      两种开发环境的差异比较如下:

    -VS2008 + DDKWizardVS2010 + EasySYS
    自动生成WDK开发模板支持(IDE内生成)支持(IDE外生成,需导入)
    需修改的开发配置项WDK环境依赖
    WDK配置参数(source文件)
    编译平台位数
    编译命令参数
    WDK环境依赖
    WDK配置参数(source文件)
    支持编译位数x86(默认)
    x64(需修改平台和命令参数)
    x86(需修改平台)
    x64 (默认)
    驱动程序签名方式手动关闭系统签名校验
    手动对驱动签名
    手动关闭系统签名校验
    手动对驱动签名
    混合汇编x86:支持(__asm{}内联汇编)
    x64:兼容性差(DDK工程无法自动编译*.asm文件)
    x86:支持(__asm{}内联汇编)
    x64:支持(WDK工程可自动链接到*.asm文件混合编译)

    4.1. 环境1(不推荐):VS2008 + DDKWizard

    4.1.1. VS2008的安装与配置

    ① 安装VS2008(任意位置即可)
      ② 打开VS2008 ,设置WDK环境依赖: 【工具】–>【选项】–>【项目和解决方案】–>【VC++目录】 --> 右侧【平台】选择【x64】 ,按下表添加WDK目录(需置顶并确保顺序):

    -x64平台(即64位编译环境)Win32平台(不必配置,仅参考)
    可执行文件&(W7BASE)\bin\x86\amd64
    &(W7BASE)\bin\x86
    &(W7BASE)\bin\x86
    &(W7BASE)\bin\x86\x86
    &(W7BASE)\tools\pfd\bin\bin\x86
    包含文件&(W7BASE)\inc\api
    &(W7BASE)\inc\crt
    &(W7BASE)\inc\ddk
    &(W7BASE)\inc\wdf
    &(W7BASE)\inc\wdf\kmdf\1.9
    &W7BASE)\inc
    &(W7BASE)\inc\api
    &(W7BASE)\inc\crt
    &(W7BASE)\inc\ddk
    &(W7BASE)\inc\wdf
    &(W7BASE)\inc\wdf\kmdf\1.9
    &(W7BASE)\inc
    库文件&(W7BASE)\lib\win7\amd64&(W7BASE)\lib
    &(W7BASE)\lib\wdf\kmdf\i386\1.9
    &(W7BASE)\lib\wxp\i386
    源文件&(W7BASE)\src&(W7BASE)\src

    备:经测试第②步不论是否在x64平台配置WDK目录也可成功编译DDK(前提是配置了上文的环境变量),而且一旦配置了这些目录,会导致x64平台只能编译DDK项目,无法在编译普通的控制台程序(VS2008的解决方案平台是所有项目共用的,VS2010则是独立的)。所以建议只有在不配置就无法编译DDK的情况下才执行第②步


    4.1.2. DDKWizard的安装与配置

    ① 安装DDKWizard(任意位置即可)
      ② 在WDK根目录下新建文件夹script,把 ddkbuild.batddkbuild.cmd 复制进去。
      ③ 修改【系统变量】中【Path】变量值,末尾添加 ;%W7BASE%\script;
      ④ 安装成功后,在VS2008中新建项目时会增加一个 DDK Project 的模板,利用该模板创建WDK项目,会自动调用ddkbuild.cmd 脚本编译驱动程序。


    4.1.3. WDK项目创建、配置与发布

    ① 打开VS2008 , 【文件】–>【新建】–>【项目】–>【DDK Project】 ,如图 1。
    在这里插入图片描述

    图 1 创建WDK项目

    ② 此处选择【Driver】模板(会自动创建默认接口代码),然后填写WDK项目名称(本文样例项目为VS2008_WDK_Demo),点击【确定】后,如图 2配置即可。

    在这里插入图片描述

    图 2 配置WDK项目环境参数

    ③ 为项目添加64位编译器(前面已设置好WDK环境依赖):点击上方【Win32】 --> 【配置管理器】 --> 【活动解决方案平台】 --> 【新建】 --> 【x64】 --> 【确定】 , 如图 3。

    在这里插入图片描述

    图 3 添加64位编译器

    ④ 配置sources文件:sources文件为ddkbuild脚本用于编译驱动程序的配置文件,如图 4。
      一般情况下,只需关注【TARGETTYPE】和【SOURCES】属性即可:

    属性取值备注
    TARGETTYPEDRIVER固定值,声明所编译的类型为“驱动”
    SOURCES项目中【Source Files】(*.cpp)
    和【Resource Files】(*.rc)中所有文件名称集合
    值格式如下(其中\表示断行):
    SOURCES=A.cpp \
         B.cpp \
         …
         Z.cpp

    在这里插入图片描述

    图 4 sources文件设置

    ⑤ 修改ddkbuild.cmd 脚本入参:【项目】–>【属性】–>【配置属性】–>【NMake】,如图 5,把【“生成”命令行】和【“全部重新生成”命令行】的值修改为:

    &(DDKBUILD_PATH) -W7X64 checked . -cZ -prefast

    在这里插入图片描述

    图 5 修改ddkbuild.cmd 脚本入参

    ⑥ 编译项目:【生成】–>【(重新)生成解决方案】
      若上述配置均正确,则编译成功。默认情况下会在项目根路径下生成目录objchk_win7_amd64(注意目录名称带有64位标识才表示该驱动是64位的)。
      编译得到的【objchk_win7_amd64\amd64<font color=“red”>VS2008_WDK_Demo.sys】即为内核驱动程序

    在这里插入图片描述

    图 6 打开驱动程序位置

    在这里插入图片描述

    图 7 内核驱动程序文件

    4.2. 环境2(推荐):VS2010 + EasySYS

    4.2.1. VS2010的安装与配置

    ① 安装VS2010(任意位置即可)
      ② 暂不需要任何配置。
      之所以不需要类似于VS2008配置WDK环境依赖,是因为使用EasySYS生成的项目会默认配置好这些值。如图 8 查看WDK环境依赖配置,导入EasySYS生成的项目后,可以通过 右键项目 --> 【属性】–>【配置属性】–>【VC++目录】 查看这些环境配置(注意使用的环境变量是WLHBASE,而非W7BASE,这也是为什么【3.3.2 WDK的安装与配置】需要配置这两个环境变量)。

    在这里插入图片描述

    图 8 查看WDK环境依赖配置

    4.2.2. EasySYS的安装与配置

    VS2010 暂无类似于DDKWizard的内置插件辅助创建WDK项目,因此需要EasySYS在外部直接生成WDK项目模板,再由VS2010导入项目(此工具也适用于VS2008)。
      ① EasySYS无需安装,在任意位置运行均可
      ② 填写【工程名称】(即WDK项目名称,本文样例项目为VS2010_WDK_Demo
      ③ 选择【保存路径】(本文样例路径为D:\01_workspace\c\vs2010\re\VS2010_WDK_Demo
      ④ 【编译环境】选择【VS 2010】, 【DDK版本】选择【WDK 7600.16385.1】,【目标系统】勾选【Windows 7】,其他任意即可,如图 9。
      ⑤ 点击【确定】后则会自动生成VS2010项目,如图 10。

    在这里插入图片描述

    图 9 EasySYS配置WDK项目模板

    在这里插入图片描述

    图 10 VS2010 WDK项目模板

    4.2.3. WDK项目导入、配置与发布

    ① 打开VS2010 , 【文件】–>【打开】–>【项目/解决方案】,选择EasySYS所生成的项目配置文件D:\01_workspace\c\vs2010\re\VS2010_WDK_Demo<font color=“red”>VS2010_WDK_Demo.sln,打开项目。
      ② 为项目添加64位编译器(前面已设置好WDK环境依赖):点击上方【Win32】 --> 【配置管理器】 --> 【活动解决方案平台】 --> 【新建】 --> 【x64】 --> 【确定】 , 如图 11。

    在这里插入图片描述

    图 11 添加64位编译器

    ③ 添加WDK相关文件:右键项目 --> 【添加】 --> 【新建过滤器】 --> 填写【WDK文件】(名称任意即可)。
      右键【WDK文件】 --> 【添加】 --> 【现有项】 ,选择【sources】【makefile】【BuildDrv.bat】【clean.bat】四个文件,如图 12(其实只需添加sources文件即可)。

    在这里插入图片描述

    图 12 添加WDK相关文件

    ④ 配置sources文件:sources文件为ddkbuild脚本用于编译驱动程序的配置文件,如图 13。
      一般情况下,只需关注【TARGETTYPE】和【SOURCES】属性即可:

    属性取值备注
    TARGETTYPEDRIVER固定值,声明所编译的类型为“驱动”
    SOURCES项目中【Source Files】(*.cpp)
    和【Resource Files】(*.rc)中所有文件名称集合
    值格式如下(其中\表示断行):
    SOURCES=A.cpp \
         B.cpp \
         …
         Z.cpp

    在这里插入图片描述

    图 13 sources文件设置

    ⑤ 编译项目:【生成】–>【(重新)生成解决方案】
      若上述配置均正确,则编译成功。默认情况下会在项目根路径下生成目录objchk_win7_amd64(注意目录名称带有64位标识才表示该驱动是64位的)。
      编译得到的【objchk_win7_amd64\amd64<font color=“red”>VS2010_WDK_Demo.sys】即为内核驱动程序

    在这里插入图片描述

    图 14 打开驱动程序位置

    在这里插入图片描述

    图 15 内核驱动程序文件

    5. 驱动程序签名

    5.1. 背景

    ——摘于博文:http://www.yiiyee.cn/Blog/64signer/

    微软对于自Vista开始的64位OS有新的数字签名策略,即所有内核驱动都必须是经过可信机构签发过数字证书的,否则系统拒绝加载,其目的是为了加强系统安全防护,使得XP时代来历不明的内核模块无法在系统中容身。
      但它却也给正经的内核开发人员带去了一个麻烦:开发过程中会不断生成新的驱动镜像文件,开发者不可能将每一个内部版本都拿去申请数字签名,一来不是所有开发者都可以负担起签证费用,二来签名过程麻烦,会大大延长开发周期。

    因此在本文中,无论【环境1】所生成的内核驱动程序【VS2008_WDK_Demo.sys】,抑或是【环境2】所生成的内核驱动程序【VS2010_WDK_Demo.sys】,在签名前均无法被系统加载


    5.2. 自签名工具 - 64Signer的安装与使用

    在这里插入图片描述

    图 16 64Signer界面

    64Signer可以对内核驱动程序签名(未通过MS认证的自签名,仅可用于测试)。
      此工具无需安装,直接把【环境1】或【环境2】所生成的内核驱动文件拖拽到64Signer,点击【签名】。若签名成功,右击内核驱动文件 --> 【属性】,会出现【数字签名】选项卡,如图 17所示:

    在这里插入图片描述

    图 17 内核驱动程序签名成功

    6. 驱动程序的加载与调试

    6.1在虚拟机搭建测试环境

    前文所编译生成的【VS2008_WDK_Demo.sys】或【VS2010_WDK_Demo.sys】驱动程序是无法直接在VS2008/VS2010中运行的(即使可以也不建议直接在开发机上运行),因为驱动程序运行在系统内核,稍有不慎就会导致蓝屏
      为此建议转移到虚拟机中执行驱动的装载和调试

    以VMWare虚拟机为例(先预装Win7 x64 SP1系统),先把虚拟机中的操作系统切换到测试模式,具体步骤如下:
      ① 在虚拟机中以管理员身份通过【win+R】 --> 【cmd】 打开DOS控制台。
      ② 输入命令【bcdedit /set testsigning on】 开启系统测试模式。
      ③ 输入命令【bcdedit -set loadoptions DDISABLE_INTEGRITY_CHECKS】,关闭系统的强制校验驱动签名功能。
      ④ 重启系统使得②③设置生效。若设置成功,重启后在桌面右下角会出现当前系统为测试模式的水印,如图 18所示(某些系统会屏蔽这个水印,此时可以通过命令【bcdedit /enum】确认testsigning的值是否为Yes以判断系统当前是否处于测试模式,如图 19)。

    在这里插入图片描述

    图 18 系统测试模式

    在这里插入图片描述

    图 19 查看bcdedit当前配置值

    注:
     上述 ②③ 步骤中的两个bcdedit命令只需执行一次,永久生效
     若不执行这两个命令,驱动程序即使签名了也无法被系统加载。
     这两个bcdedit命令对应的恢复命令为:
     bcdedit -set loadoptions DENABLE_INTEGRITY_CHECKS
     bcdedit /set testsigning off


    6.2. 驱动加载

    常用的加载驱动程序的工具有两个:
      ① DriverMonitor:若加载失败会提示错误原因,但对部分Win7x64系统兼容性不好。
      ② InstDrv:若加载失败无错误原因提示,可运行于x64位系统。
      这两个工具的使用比较简单,参照图 20和图 21即可,此处就不再详细说明了。

    在这里插入图片描述

    图 20 驱动加载工具DriverMonitor

    在这里插入图片描述

    图 21 驱动加载工具InstDrv

    6.3. 驱动调试

    6.3.1. DebugView调试

    在驱动程序被DriverMonitor / InstDrv加载、并启动成功后,若驱动程序中有使用了DbgPrint / KdPrint 输出消息(这两个语句的作用类似于开发应用程序时的控制台输出语句),则可同时启动 DebugView 对 dbgPrint / kdPrint 输出的消息进行实时捕获
      由于DebugView是实时捕获消息,因此需要在驱动程序被加载前启动。启动DebugView后,如图 22配置,勾选【监视】下的【监视核心】、【启用详细核心输出】、【全部通过】、【监视事件】,捕获的消息如图 23所示。

    在这里插入图片描述

    图 22 DebugView配置

    在这里插入图片描述

    图 23 DebugView捕获消息样例

    6.3.2. VMWare + WinDbg双机调试

    此部分扩展内容较多,以后再另建文档作为独立教程详细说明。


    7. 附录1:环境搭建常见异常解决方案

    7.1. VS2008 / VS2010安装失败

    99%的原因都是因为缺失 .NET库 或 .NET的相关配置文件。
      尤其是非官方原版的GHOST系统,经常会被第三方出于某些目的修改、移动、删除.NET的库文件。
      更为致命的是 VS2008 / VS2010 安装过程中若出错,除了给出异常编码,不会有任何原因提示,目前通过百度找的办法也并非适合普罗大众,这里根据我个人的经验做一个总结:
      ① Win7下建议安装VS2010,这是微软专门为win7开发的版本
      ② 确保Microsoft Office 2007已安装成功
      ③ 确保.NET库文件已全部安装成功,需要同时安装4个版本:

    .NET x64 v2.0.50727
    .NET x64 v3.0
    .NET x64 v3.5
    .NET x64 v4.0.30319

    ④ 若.NET库安装失败,可从其他Win7机器拷贝(或者网上下载).NET的安装目录到以下两个对应目录:

    C:\Windows\Microsoft.NET\Framework
    C:\Windows\Microsoft.NET\Framework64

    上述4步均执行成功后,再安装 VS2008 / VS2010 一般来说可以畅通无阻了。
    但VS有些内置组件在安装过程可能报错,只能独立安装,这里也总结一下:


    7.1.1. VS2008 安装过程报错:ISetupComponent::Pre/Post/Install() failed in ISetupManager::InternalInstallManager() with HRESULT -2147023293.

    异常原因:
        安装 Microsoft Office 2007失败。

    解决方案:
        先尝试重装 Microsoft Office 2007, 若依旧出现此错误,则按如下步骤处理:
        ① 把vs2008镜像文件下的 \WCU\WebDesignerCore\WebDesignerCore.EXE 右键解压到(注意解压出来的文件夹里面有个Office.zh-cn)。
        ② 把 Microsoft Office 2007 光盘或光盘镜像中的Office.zh-cn文件夹 覆盖到 VS2008 的Office.zh-cn。
        ③ 运行第一步解压出来的文件中的setup.exe安装 Microsoft Office 2007


    7.1.2. VS2008 安装过程报错:X64 远程调试器未成功安装

    异常原因:
        缺失 .NET 相关库文件(但是具体缺失了什么缺没有提示)。

    解决方案:
        ① 手动解压 VS2008 的安装光盘,运行安装目录下的这个内置组件:

    \Remote Debugger\x64\rdbgsetup.exe

    ② 此时若内置组件安装失败,就会提示具体失败原因了(一般都是缺失.NET4.0库下的 \CONFIG\machine.config 文件)
        ③ 在网上下载对应文件放到报错目录,或者重装对应版本 .NET 库应该可以解决。


    7.1.3. VS2010 安装过程报错:Error: Installation failed for component Microsoft Visual Studio 2010 64bit Prerequisites (x64). MSI returned error code 1603

    异常原因:
        缺失 .NET 相关库文件(但是具体缺失了什么缺没有提示)。

    解决方案:
        ① 手动解压 VS2010 的安装光盘,依次运行安装目录下的几个内置组件:

    \WCU\64bitPrereq\x64\VS_Prerequisites_x64_chs.msi
    \WCU\SSCE\SSCERuntime_x64-chs.msi
    \WCU\SSCE\SSCERuntime_x86-chs.msi
    \WCU\SSCE\SSCEVSTools-chs.msi

    ② 此时若内置组件安装失败,就会提示具体失败原因了(一般都是缺失.NET2.0库下的 \CONFIG\machine.config 文件)
        ③ 在网上下载对应文件放到报错目录,或者重装对应版本 .NET 库应该可以解决。


    7.2. [Error 1275] - 此驱动程序被阻止加载

    使用DriverMonitor / InstDrv加载驱动程序成功,但启动时报错(如图 24):

    Error (1275):此驱动程序被阻止加载

    异常原因:
        在64位系统加载32位驱动程序、或者在32位系统加载64位驱动程序。

    解决方案:
        根据用于加载驱动的操作系统的位数,使用对应的平台重新编译驱动程序即可。
        
    在这里插入图片描述

    图 24 Error (1275)

    7.3. [Error 577] - Windows无法验证此文件的数字签名 某些软件或硬件最近有所更改,可能安装了签名错误或损毁的文件,或者安装的文件可能是来路不明

    使用DriverMonitor / InstDrv加载驱动程序成功,但启动时报错(如图 25):

    Error (577):Windows无法验证此文件的数字签名 某些软件或硬件最近有所更改,可能安装了签名错误或损毁的文件,或者安装的文件可能是来路不明

    异常原因:
        以下三个条件任意一条不满足:
        ① 驱动程序已进行数字签名
        ② 操作系统已进入测试模式
        ③ 操作系统已关闭数字签名校验

    解决方案:
        确保以下四个操作已全部执行:
        ① 使用64Signer对驱动程序进行数字签名
        ② 在DOS下执行bcdedit /set testsigning on命令进入测试模式
        ③ 在DOS下执行bcdedit -set loadoptions DDISABLE_INTEGRITY_CHECKS命令关闭系统的强制校验驱动签名功能
        ④ 重启电脑(使得②③命令生效)
        
    在这里插入图片描述

    图 25 Error (577)

    8. 附录2:DDKWizard - ddkbuild脚本参数解析

    默认情况下,ddkbuild.cmd 脚本所编译的驱动程序是32位的(即使在VS2008选择了x64编译平台),此情况可从编译驱动程序后的输出目录名称得到验证(如objchk_win7_x86)。
      要使得所编译的驱动程序为64位,则需把脚本入参中的平台参数修正为对应的X64平台。命令格式可通过编辑ddkbuild.bat查看,如图 26。平台参数枚举可通过编辑ddkbuild.cmd查看,如图 27。修改后重新编译驱动程序,输出目录名称默认会包含64位标识(如objchk_win7_amd64)。
      例如本文【环境1】中默认的脚本命令如下,其中平台参数为 -W7(即win7x86):

    $(DDKBUILD_PATH) -W7 checked . -cZ -prefast

    修改为对应的64位平台参数 -W7X64 即可编译出64位驱动:

    $(DDKBUILD_PATH) -W7X64 checked . -cZ -prefast

    在这里插入图片描述

    图 26 ddkbuild命令格式

    在这里插入图片描述

    图 27 ddkbuild脚本参数

    9. 附录3:相关知识科普

    9.1. Windows程序的运行层级

    ——摘于博文:http://www.cnblogs.com/findumars/p/5557283.html

    在CPU的所有指令中,有一些指令是非常危险的,如果错用,将导致整个系统崩溃,如:清内存、设置时钟等。如果所有的程序都能使用这些指令,那么系统一天死机N回就不足为奇了。所以CPU将指令分为特权指令非特权指令,对于那些危险的指令,只允许操作系统及其相关模块使用,普通的应用程序只能使用那些不会造成灾难的指令。
      Intel的CPU将特权级别分为4个级别:RING0、RING1、RING2、RING3(简称R0、R1、R2、R3)。R0层拥有最高的权限,R3层拥有最低的权限。按照Intel原有的构想,应用程序工作在R3层,只能访问R3层的数据;操作系统工作在R0层,可以访问所有层的数据;而其他驱动程序位于R1、R2层,每一层只能访问本层以及权限更低层的数据。
      这应该是很好的设计,这样操作系统工作在最核心层,没有其他代码可以修改它;其他驱动程序工作在R1、R2层,有要求则向R0层调用,这样可以有效保障操作系统的安全性。
      但现在的OS,包括Windows和Linux都没有采用4层权限,而只是使用2层:R0层和R3层,分别来存放操作系统数据和应用程序数据,从而导致一旦驱动加载了,就运行在R0层,即拥有了和操作系统同样的权限,可以做任何事情,而所谓的RootKit(拥有“根权限”的工具)也就随之而生了。


    9.2. 驱动模式

    ——摘于博文:http://lib.csdn.net/article/dotnet/41373

    运行 Windows 的计算机中的处理器有两个不同模式:“用户模式”“内核模式”。根据处理器上运行的代码的类型,处理器在两个模式之间切换。应用程序在用户模式下运行,核心操作系统组件在内核模式下运行。多个驱动程序在内核模式下运行时,某些驱动程序可能在用户模式下运行。
      当启动用户模式的应用程序时,Windows 会为该应用程序创建“进程”。进程为应用程序提供专用的“虚拟地址空间”和专用的“句柄表格”。由于应用程序的虚拟地址空间为专用空间,一个应用程序无法更改属于其他应用程序的数据。每个应用程序都孤立运行,如果一个应用程序损坏,则损坏会限制到该应用程序。其他应用程序和操作系统不会受该损坏的影响。
      用户模式应用程序的虚拟地址空间除了为专用空间以外,还会受到限制。在用户模式下运行的处理器无法访问为该操作系统保留的虚拟地址。限制用户模式应用程序的虚拟地址空间可防止应用程序更改并且可能损坏关键的操作系统数据。
      在内核模式下运行的所有代码都共享单个虚拟地址空间。这表示内核模式驱动程序未从其他驱动程序和操作系统自身独立开来。如果内核模式驱动程序意外写入错误的虚拟地址,则属于操作系统或其他驱动程序的数据可能会受到损坏。如果内核模式驱动程序损坏,则整个操作系统会损坏。


    9.3. 驱动程序类型

    ——摘于博文:http://lib.csdn.net/article/dotnet/41373

    WDF提供了两个框架:
      ① 内核模式驱动程序KMDF(Kernel-Mode DriverFramework):
      这类驱动程序作为内核模式操作系统组件的一部分执行,它们管理I/O、即插即用、内存、进程和线程、安全等。内核模式驱动程序通常为分层结构。KMDF是Windows系统底层驱动,文件名为:*.SYS。关于KMDF更多的内容,可参阅 MSDN中“Getting Started with Kernel-ModeDriver Framework ”。

    ② 用户模式驱动程序 UMDF(User-Mode DriverFramework):
      这类驱动程序通常提供 Win32 应用程序与内核模式驱动程序或其他操作系统组件之间的接口。用户模式驱动程序支持基于协议或基于串行总线(如摄像机和便携音乐播放器)的设备。UMDF是用户层驱动,文件名为:*.DLL。关于KMDF更多的内容,可参阅 MSDN中“Introduction to UMDF”。

    无论内核模式的驱动程序或者用户模式的驱动程序,都使用同一环境进行构建,这一环境称为WDK;都采用同一套对象模型构建,采用同一个基础承载,这个基础就是WDF。由于WDF驱动模型提供了面向对象和事件驱动的驱动程序开发框架,大大降低了开发难度。使得像WinDriver、DriverStudio之类的第三方工具也随之退出历史舞台。更重要的,也是微软反复炫耀的是封装了驱动程序中的某些共同行为:例如即插即用和电源管理就属于这种共同行为。因为大多数驱动程序中都需要处理即插即用和电源管理问题(据说这大概要上千行的代码,况且没有相当水平还不一定能处理好)。为了一劳永逸,WDF干脆将即插即用和电源管理封装了进了对象之内,成了对象的缺省行为。
      WDF将驱动程序与操作系统内核之间进行了分离,驱动程序与操作系统交互工作交给框架内封装的方法(函数)完成,这样驱动开发者只需专注处理硬件的行为即可。这不仅避免了顾此失彼两面不周的弊端,也由于双方的分离,对操作系统内的某些改动,硬件制造商配套驱动程序的开发都有莫大的好处。


    9.4. 驱动的签名与认证

    从Win Vista/7 x64 系统开始,微软就要求用户必须使用经过数字签署过的驱动。换言之,没有经过数字签名的驱动是不允许安装到x64系统的。
      默认情况下,新编译的驱动程序都是没有数字签署的,若要对其进行数字签署,又可以分为两种形式:
      ① 自签名:包括从正规渠道付费获得的各种EV签名(如wosign、verisigned等),或由开发者本人创建发布的签名(如用64Signer签名,具体信任策略要看本地策略)
      ② WHQL认证:只能通过微软官方对驱动进行测试并通过后获得的认证(认证过程极其严格、周期长、费用高,不适合个人开发者),凡是通过WHQL认证的产品均会被授予“Designed for Windows”标识。此类别驱动最大的特点是稳定性高,和微软操作系统的兼容性好(几乎100%兼容)。

    特别需要注意的是:自签名和WHQL认证不是同一个东西
      自签名只能证明该驱动是来自可靠的发布者,并且内容未被改变(受信任的合法证书也包含在这个范围);WHQL认证则是说明微软认可这个驱动。
      换而言之,即使驱动程序有合法的签名,但没有通过WHQL认证,也是无法被加载的,因为自Win Vista/7 x64 以后的操作系统在加载驱动时所校验的是WHQL认证,不是自签名。

    表 2 驱动程序在x64系统的各模式下的可装载情况
    --x64驱动的数字签署方式-
    系统模式(x64)无数字签署自签名WHQL认证
    正常模式(默认)不能装载不能装载可以装载
    禁用驱动程序签名
    强制检测模式
    不能装载
    (旧版本系统可以)
    不能装载
    (旧版本系统可以)
    可以装载
    TestSigning
    测试模式
    不能装载可以装载可以装载

    注:
     ① 32位系统不检查WHQL,只会给出警告。
     ② 禁用驱动程序签名强制检测模式:
      临时方式(重启后失效):【开机按F8】 --> 【禁用驱动程序签名强制】(如图 28)
      永久方式(重启后有效):以管理员身份在DOS控制台输入命令【bcdedit -set loadoptions DDISABLE_INTEGRITY_CHECKS】
     ③ TestSigning测试模式:以管理员身份在DOS控制台输入命令【bcdedit /set testsigning on】
     ④ 较旧版本的系统可以只用方式 ② 实现驱动装载,但现在已经失效了,目前只能通过方式 ③ 实现。 然而某些程序(如游戏)会检测系统是否处于测试模式,否则不予运行,避免被非法驱动(如外挂)Hook。

    在这里插入图片描述

    图 28 (F8)禁用驱动程序签名强制
    展开全文
  • Linux 驱动开发实例

    热门讨论 2010-09-28 08:14:23
    驱动开发 Linux下的摄像头驱动开发,是很好的学习驱动开发的好资源,还配有文档。
  • Linux设备驱动开发入门

    万人学习 2016-01-20 10:28:16
    本课程讲解Linux驱动程序开发基本知识,程序架构,字符设备编程,杂项设备编程,具体硬件模块驱动开发
  • 本课程是linux驱动开发的第7个课程,主要内容是linux的framebuffer驱动详解,本课程带大家分析fb驱动的框架、构成以及一些代码细节,目标是让大家彻底掌握fb驱动在内核中的配置和移植方法、掌握显示设备驱动的关键点...
  • 字符设备驱动-linux驱动开发第3部分

    千人学习 2016-10-18 11:07:11
    本课程是linux驱动开发的第3个课程,接上部分继续讲解字符设备驱动的开发要点,重点是相关的内核源代码的解析和一些真正驱动惯用的编程手法的引入。本课程的目的是让大家开始逐渐习惯和熟悉真正内核驱动的特征,为...
  • linux驱动开发架构

    万次阅读 多人点赞 2019-05-30 14:38:37
    最近开始开发驱动,现总结通用驱动开发模型如下 驱动整体模型: 添加一个设备,多数需要用户空间下发指令等操作。那么有两个问题: kernel如何控制设备 用户空间如何和kernel中的驱动交互 问题1: kernel中有各种...

    驱动模型

    最近开始开发驱动,现总结通用驱动开发模型如下
    驱动整体模型:
    在这里插入图片描述
    添加一个设备,多数需要用户空间下发指令等操作。那么有两个问题:

    1. kernel如何控制设备
    2. 用户空间如何和kernel中的驱动交互

    问题1:
    kernel中有各种总线,设备挂载在总线上,驱动通过kernel总线提供的接口初始化控制设备。
    问题2:
    kernel中提供文件设备驱动,在驱动中增加一个文件设备,如字符设备、proc、sys等文件设备。

    基于以上两个问题,驱动包含两部分
    在这里插入图片描述

    开发设备驱动

    系统端驱动开发步骤

    1、阅读设备相关的规格书、demo
    2、确定设备挂载总线、文件交互设备
    3、参照demo,编写驱动代码,代码包含两部分:设备树添加结点、逻辑代码

    注意: 设备树结点中的字段可以是标准的(内核已有代码解析),也可以包含自定义的(设备驱动逻辑代码解析)。

    设备端基于单片机驱动开发

    设备端硬件形态有两种:
    1、设备端有一个独立的小系统,通过一个单片机运行
    2、设备端仅由电子原件和电路图实现

    形态1:
    一般情况下,该部分代码,设备厂商已提供,无需系统端负责开发。系统端通过总线和设备进行交互。

    形态2:
    设备端上电后,驱动实现初始化,控制设备端寄存器,配置设备以满足对设备功能、数据的需求

    应用场景

    以上描述的驱动开发架构模式,常用于应用级驱动开发。一些控制器类型,如i2c控制器、spi总线控制器等kernel中框架层的,一般不需要文件系统设备的存在,只需要开发设备驱动即可;为debug方便,一般也会搭配文件系统设备,方便命令行查看设备状态。

    在开发中,可以根据实际需求决定。

    DEMO

    需求描述

    给一个i2c编写驱动,i2c提供一些接口给userspace使用

    添加设备树结点
    // SoC上的i2c控制器的地址
    i2c@138B0000 {
    	#address-cells = <1>;
        #size-cells = <0>;
        samsung,i2c-sda-delay = <100>;
        samsung,i2c-max-bus-freq = <20000>;
        pinctrl-0 =<&i2c5_bus>;
        pinctrl-names="default";
        // 这个一定要okay,其实是对"./arch/arm/boot/dts/exynos4.dtsi +387"处的status = "disabled"的重写,
        // 相同的节点的不同属性信息都会被合并,相同节点的相同的属性会被重写
        status="okay";
        // 设备子节点,/表示板子,它的子节点node1表示SoC上的某个控制器,
        // 控制器中的子节点node2表示挂接在这个控制器上的设备(们)。68即是设备地址。
        // 父结点是一个i2c总线,在此处定义i2c设备,设备i2c客户端自动和总线关联;
        // 否则,多个总线,设备i2c客户端驱动如何和总线关联?(待学习了解)
        mpu6050@68{
        	// 这个属性就是我们和驱动匹配的钥匙,一个字符都不能错
            compatible="invensense,mpu6050";
            // 这个属性是从设备的地址,我们可以通过查阅手册"MPU-6050_DataSheet_V3_4"得到
            reg=<0x68>;
        };
    };
    
    驱动实现
    //mpu6050_common.h
    #define MPU6050_MAGIC 'K'
    
    union mpu6050_data
    {
        struct {
            short x;
            short y;
            short z;
        }accel;
        struct {
            short x;
            short y;
            short z;
        }gyro;
        unsigned short temp;
    };
    
    #define GET_ACCEL _IOR(MPU6050_MAGIC, 0, union mpu6050_data)
    #define GET_GYRO  _IOR(MPU6050_MAGIC, 1, union mpu6050_data) 
    #define GET_TEMP  _IOR(MPU6050_MAGIC, 2, union mpu6050_data)
    
    //mpu6050_drv.h
    
    #define SMPLRT_DIV      0x19    //陀螺仪采样率,典型值:0x07(125Hz)
    #define CONFIG          0x1A    //低通滤波频率,典型值:0x06(5Hz)
    #define GYRO_CONFIG     0x1B    //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
    #define ACCEL_CONFIG        0x1C    //加速计自检、测量范围及高通滤波,典型值:0x18(不自检,2G,5Hz)
    #define ACCEL_XOUT_H        0x3B
    #define ACCEL_XOUT_L        0x3C
    #define ACCEL_YOUT_H        0x3D
    #define ACCEL_YOUT_L        0x3E
    #define ACCEL_ZOUT_H        0x3F
    #define ACCEL_ZOUT_L        0x40
    #define TEMP_OUT_H      0x41
    #define TEMP_OUT_L      0x42
    #define GYRO_XOUT_H     0x43
    #define GYRO_XOUT_L     0x44
    #define GYRO_YOUT_H     0x45
    #define GYRO_YOUT_L     0x46
    #define GYRO_ZOUT_H     0x47    //陀螺仪z轴角速度数据寄存器(高位)
    #define GYRO_ZOUT_L     0x48    //陀螺仪z轴角速度数据寄存器(低位)
    #define PWR_MGMT_1      0x6B    //电源管理,典型值:0x00(正常启用)
    #define WHO_AM_I        0x75    //IIC地址寄存器(默认数值0x68,只读)
    #define SlaveAddress        0x68    //MPU6050-I2C地址寄存器
    #define W_FLG           0
    #define R_FLG           1
    
    //mpu6050.c
    struct mpu6050_pri {
        struct cdev dev;
        struct i2c_client *client;
    };
    struct mpu6050_pri dev;
    static void mpu6050_write_byte(struct i2c_client *client,const unsigned char reg,const unsigned char val)
    { 
        char txbuf[2] = {reg,val};
        struct i2c_msg msg[2] = {
            [0] = {
                .addr = client->addr,
                .flags= W_FLG,
                .len = sizeof(txbuf),
                .buf = txbuf,
            },
        };
        i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
    }
    static char mpu6050_read_byte(struct i2c_client *client,const unsigned char reg)
    {
        char txbuf[1] = {reg};
        char rxbuf[1] = {0};
        struct i2c_msg msg[2] = {
            [0] = {
                .addr = client->addr,
                .flags = W_FLG,
                .len = sizeof(txbuf),
                .buf = txbuf,
            },
            [1] = {
                .addr = client->addr,
                .flags = I2C_M_RD,
                .len = sizeof(rxbuf),
                .buf = rxbuf,
            },
        };
    
        i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
        return rxbuf[0];
    }
    static int dev_open(struct inode *ip, struct file *fp)
    {
        return 0;
    }
    static int dev_release(struct inode *ip, struct file *fp)
    {
        return 0;
    }
    static long dev_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
    {
        int res = 0;
        union mpu6050_data data = {{0}};
        switch(cmd){
        case GET_ACCEL:
            data.accel.x = mpu6050_read_byte(dev.client,ACCEL_XOUT_L);
            data.accel.x|= mpu6050_read_byte(dev.client,ACCEL_XOUT_H)<<8;
            data.accel.y = mpu6050_read_byte(dev.client,ACCEL_YOUT_L);
            data.accel.y|= mpu6050_read_byte(dev.client,ACCEL_YOUT_H)<<8;
            data.accel.z = mpu6050_read_byte(dev.client,ACCEL_ZOUT_L);
            data.accel.z|= mpu6050_read_byte(dev.client,ACCEL_ZOUT_H)<<8;
            break;
        case GET_GYRO:
            data.gyro.x = mpu6050_read_byte(dev.client,GYRO_XOUT_L);
            data.gyro.x|= mpu6050_read_byte(dev.client,GYRO_XOUT_H)<<8;
            data.gyro.y = mpu6050_read_byte(dev.client,GYRO_YOUT_L);
            data.gyro.y|= mpu6050_read_byte(dev.client,GYRO_YOUT_H)<<8;
            data.gyro.z = mpu6050_read_byte(dev.client,GYRO_ZOUT_L);
            data.gyro.z|= mpu6050_read_byte(dev.client,GYRO_ZOUT_H)<<8;
            printk("gyro:x %d, y:%d, z:%d\n",data.gyro.x,data.gyro.y,data.gyro.z);
            break;
        case GET_TEMP:
            data.temp = mpu6050_read_byte(dev.client,TEMP_OUT_L);
            data.temp|= mpu6050_read_byte(dev.client,TEMP_OUT_H)<<8;
            printk("temp: %d\n",data.temp);
            break;
        default:
            printk(KERN_INFO "invalid cmd");
            break;
        }
        printk("acc:x %d, y:%d, z:%d\n",data.accel.x,data.accel.y,data.accel.z);
        res = copy_to_user((void *)arg,&data,sizeof(data));
        return sizeof(data);
    }
    
    // 初始化文件系统设备操作接口
    struct file_operations fops = {
        .open = dev_open,
        .release = dev_release,
        .unlocked_ioctl = dev_ioctl, 
    };
    
    #define DEV_CNT 1
    #define DEV_MI 0
    #define DEV_MAME "mpu6050"
    
    struct class *cls;
    dev_t dev_no ;
    
    static void mpu6050_init(struct i2c_client *client)
    {
        mpu6050_write_byte(client, PWR_MGMT_1, 0x00);
        mpu6050_write_byte(client, SMPLRT_DIV, 0x07);
        mpu6050_write_byte(client, CONFIG, 0x06);
        mpu6050_write_byte(client, GYRO_CONFIG, 0x18);
        mpu6050_write_byte(client, ACCEL_CONFIG, 0x0);
    }
    static int mpu6050_probe(struct i2c_client * client, const struct i2c_device_id * id)
    {
        dev.client = client;
        printk(KERN_INFO "xj_match ok\n");
        // 初始化设备文件系统
        cdev_init(&dev.dev,&fops);    
        alloc_chrdev_region(&dev_no,DEV_MI,DEV_CNT,DEV_MAME);    
        cdev_add(&dev.dev,dev_no,DEV_CNT);
        
        // 设备初始化
        mpu6050_init(client);
    
        /*自动创建设备文件*/
        cls = class_create(THIS_MODULE,DEV_MAME);
        device_create(cls,NULL,dev_no,NULL,"%s%d",DEV_MAME,DEV_MI);
        
        printk(KERN_INFO "probe\n");
        
        return 0;
    }
    
    static int mpu6050_remove(struct i2c_client * client)
    {
        device_destroy(cls,dev_no);
        class_destroy(cls);
        unregister_chrdev_region(dev_no,DEV_CNT);
        return 0;
    }
    
    struct of_device_id mpu6050_dt_match[] = {
        {.compatible = "invensense,mpu6050"},
        {},
    };
    
    // 设备驱动注册到总线
    struct i2c_device_id mpu6050_dev_match[] = {};
    struct i2c_driver mpu6050_driver = {
        .probe = mpu6050_probe,
        .remove = mpu6050_remove,
        .driver = {
            .owner = THIS_MODULE,
            .name = "mpu6050drv",
            .of_match_table = of_match_ptr(mpu6050_dt_match), 
        },
        .id_table = mpu6050_dev_match,
    };
    module_i2c_driver(mpu6050_driver);
    MODULE_LICENSE("GPL");
    

    在代码实现中把文件系统设备实现和设备驱动实现混合在一起,个人加以分开实现,利于代码重用和设备驱动替换和多方案切换。

    验证

    通过上面的驱动, 我们可以在应用层操作设备文件从mpu6050寄存器中读取原始数据, 应用层如下

    int main(int argc, char * const argv[])
    {
        int fd = open(argv[1],O_RDWR);
        if(-1== fd){
            perror("open");
            return -1;
        }
        union mpu6050_data data = {{0}};
        while(1){
            ioctl(fd,GET_ACCEL,&data);
            printf("acc:x %d, y:%d, z:%d\n",data.accel.x,data.accel.y,data.accel.z);
            ioctl(fd,GET_GYRO,&data);
            printf("gyro:x %d, y:%d, z:%d\n",data.gyro.x,data.gyro.y,data.gyro.z);
            ioctl(fd,GET_TEMP,&data);
            printf("temp: %d\n",data.temp);
            sleep(1);
        }
        return 0;
    }
    

    最终可以获取传感器的原始数据如下
    在这里插入图片描述
    说明: 以上demo是借鉴 https://www.cnblogs.com/xiaojiang1025/p/6500540.html 的,在实际开发中个人也有实现,代码不在写该篇博客的电脑中,就借用了大神代码。

    展开全文
  • bsp开发之驱动开发

    千次阅读 2014-11-05 22:40:30
    关于bsp开发中的驱动开发的介绍

    驱动程序是能够管理虚拟设备或者物理设备,协议,服务等得软件模块,操作系统只有通过驱动程序才能访问硬件。针对windows ce开发设备驱动,就是通过platform builder创建一个新的平台,然后根据硬件平台的需要插入或者移除驱动,需要修改的文件有platform.bib,platform.reg。

    按加载方式和接口分类,基于windows ce的驱动程序可以分为一下三类:

    (1)      本机驱动程序

    它是微软开发并由系统直接支持,适用于集成到ce平台的设备。

    (2)      流接口驱动程序

    流接口驱动程序又称为可安装驱动(Installable Drivers)。它具有较好的可移植性和可扩展性,由设备管理器独立出来管理和统筹。流接口驱动程序我们会在之后的博客中再做介绍。

    (3)      混合型驱动程序

    同时又定制式和流驱动两套程序接口,但是和系统交互只使用流式驱动接口。

    谈到驱动,我们不得不提一下中断。

    与其他计算机结构一样,当设备需要驱动程序的服务时,基于windows ce.ney的平台要使用中断通知操作系统。Windows ce.net 把中断处理分为两部分:中断服务例行程序(ISR)和中断服务线程(IST)。

    (1)      ISR

    ISR的主要功能就是将一个物理中断映射为一个逻辑中断值。当ISR通知内核一个特定的逻辑中断值时,内核检查内核中断表,将这个逻辑中断映射为一个事件句柄。一个事件就是一个标准的win32同步对象,当一些特定的事件发生时,它作为一个警报时钟唤醒一个线程。这时,内核通过调用win32函数PulseEvent来唤醒特定的正在等待该事件的IST,由IST完成具体的中断处理工作。

    (2)      IST

    在windows ce的中断机制中,有ist具体处理中断的事务性工作。当内接到ISR传来的中断标识后,发出一个中断事件,激活一个处于该事件等待状态的一个IST,一段时间后,调度器将调度这个线程工作,处理中断的事物。

                       

    展开全文
  • 测试驱动开发

    千次阅读 2018-11-24 14:14:00
    测试驱动开发 概述 极限编程是一个轻量级的、灵巧的软件开发方法,同时它也是一个非常严 谨和周密的方法,它从 4 个基本方面对软件项目进行改善:交流、简易、反馈 和勇气。测试驱动开发则是极限编程的最佳...

    测试驱动开发

    概述

    极限编程是一个轻量级的、灵巧的软件开发方法,同时它也是一个非常严

    谨和周密的方法,它从 4 个基本方面对软件项目进行改善:交流、简易、反馈

    和勇气。测试驱动开发则是极限编程的最佳实践之一。它是编程时使用的技术,

    要求在编写任何产品代码之前,首先编写用于定义产品代码行为的测试。采用

    测试驱动开发,我们将得到简单、清晰、高质量的代码。 MVC 模式是一个复杂的架构模式,它将一个应用的输入、处理、输出流程按照 Model、View、Controller 的方式进行分离,使得产品的结构清晰,易于 维护,有利于软件工程化管理。 Kent Beck 作为极限编程的创始人,提出了测试驱动开发的部分方法,并成功地应用于许多小型的项目中。但是,测试驱动开发在许多系统中应用还存在一定的难度,比如具有图形用户界面和多层架构的系统。所以,基于设计模式的测试驱动开发的研究成为国内外软件工程方向研究者们的课题之一。

    反馈是 XP 的四个基本的价值观之一——在软件开发中,只有通过充分的测试才能获得充分的反馈。XP 中提出的测试,在其它软件开发方法中都可以见到,比如功能测试、单元测试、系统测试和负荷测试等;与众不同的是,XP 将测试结合到它独特的螺旋式增量型开发过程中,测试随着项目的进展而不断积累。另外,由于强调整个开发小组拥有代码,测试也是由大家共同维护的。即,任何人在往代码库中放程序前,都应该运行一遍所有的测试;任何人如果发现了一个 BUG,都应该立即为这个 BUG 增加一个测试,而不是等待写那个程序的人来完成;任何人接手其他人的任务,或者修改其他人的代码和设计,改动完以后如果能通过所有测试,就证明他的工作没有破坏原系统。这样,测试才能真正起到帮助获得反馈的作用;而且,通过不断地优先编写和累积,测试应该可以基本覆盖全部的客户和开发需求,因此开发人员和客户可以得到尽可能充足的反馈。

        测试驱动开发(Test- Driven Development), 简称TDD, 由Kent Beck 提出的一种软件开发方式。测试驱动开发以测试作为开发过程的中心, 它要求在编写任何产品代码之前, 首先编写用于定义产品代码行为的测试, 而编写的产品代码又要以使测试通过为目标。测试驱动开发要求测试可以完全自动化的运行, 在对代码进行重构前后必须运行测试。测试驱动开发主要包括两方面:测试先行和代码重构。测试主要针对单元(最小的可测试软件元素)实施测试。它所测试的内容包括内部结构(如逻辑和数据流)以及单元的功能和可观测的行为。测试先行一改传统开发模式的单元测试在编写代码之后进行, 而将单元测试的编写移至编写正式代码之前。重构是在不改变代码外在行为的条件下改进其内部的行为的一种软件系统改变的过程, 使代码松耦合度(对外界代码依赖低)并且内聚度高(内部只完成一项功能) 。测试驱动开发作为极限 编程思想的一种主要实践, 可以有效地让程序开发人员开发出更高品质的、经过完整测试的程序。测试驱动开发以测试作为开发过程的开端, 它要求在编写任何产品代码之前,首先编写用于定义产品代码行为的测试, 而编写的产品代码又要以使测试通过为目标。TDD 不是一种开发工具,也不是一种测试方法, 它是一种编码之前进行单元测试的软件开发思想。

     

    1. 测试驱动开发的研究与实践

    测试驱动开发流程:TDD 开发过程有别于传统开发流程(Waterfall), 它在进行简单的概要设计后, 首先进行的是测试用例的编写,然后执行测试用例进行测试。测试失败, 则进行编码驱使测试通过, 这就是所谓的测试驱动。最终, 测试得到通过,再对代码进行重构,优化代码结构和性能。而传统流程则先进行概要设计, 然后在概要设计基础上进行详细设计,在详细设计阶段尽可能设想到全部问题和需求的解决方法, 然后才开始编码实现详细设计。TDD 开发流程图如图所示。

    测试驱动开发模式:在测试驱动开发中,关键问题如下:什么时候进行测试,如何选择要测试的逻辑和如何选择要测试的数据。测试驱动开发模式指导程序员如何解决上述问题。

    *测试相互独立。

    在测试驱动开发中, 所运行的各种测试之间关系的期望状态是没有任何相互影响的。相互独立的测试意味着所有的测试都是不依赖于顺序的, 可以随便从这些测试中挑出部分测试来运行。程序员必须将自己的问题分解为一些彼此正交的小问题, 这样就使得为每个测试搭建环境

    简单而快捷。独立测试鼓励利用高度内聚、低度耦合的对象组合来解决问题。

    *写出测试列表。

    程序员在开始写测试之前, 应该写一个包含所有必须要编写的测试的清单。那么, 记录到列表上的就是当前程序员要去实现的测试。首先将需要实现的每种操作的范例都记录在清单上。对于目前尚不存在的操作, 将其空版本记录在清单上。

    *测试和断言优先。

    在测试驱动开发中, 程序员构建一个系统应该是从其对最终系统的描述开始的。程序员应该从希望最终代码能够通过的测试开始编写一项功能。相应地,程序员应该从测试完成时能够通过的断言开始编写一个测试。在测试优先的测试里程序员应该尽量使用容易让人理解的数据, 一般不用一个常量来表达多种意思。

    一般从测试列表中选择具有指导意义并且比较有把握实现的测试来进行编写。当使用一个新类里的一种新的方法时, 不直接用它来编写程序, 而是编写一个小测试来验证这个API 的工作是否符合人们的愿望。当出现某种与当前讨论话题并不直接相关的想法时, 那么就在列表中增加一个测试然后重新回到论题上来。当发现一个错误的时候, 首先写一个尽可能小的测试并使其运行, 然后再去修复这个错误。

    利用JUnit进行测试驱动开发:在Eclipse 建立JUnit 测试, 并进行驱动开发。现在开 发一个"Hello Wor ld" 的例子。按照TDD 的规则, 应该在代码建立以前先把测试写好。为了能够在某处开始, 假设未来的类名是HelloWorld , 并且有一个方法Say(), 这个方法返回String 的值(例如"Hello World !")。根据设定的程序功能, 写出测试代码如下:

     

    import junit .framework.T estCase ;

    public class TestThatWeGetHelloWorldPrompt

    extends TestCase {

     public TestThatWeGetHelloWorldPrompt(

      String name){

       super(name);

      }

     public void testSay(){

     HelloWorld hi=new HelloWorld();

      assertEquals(" Hello World!" , hi.say());

     }

     public static void main(String[ ] args){

      junit.textui.TestRunner.run(

      TestThatWeGetHelloWorldPrompt.class);

     }

    }

    建立测试案例的步骤如下:

    1)建立一个junit.framework.TestCase的实例。

    2)定义一些以"test" 开头的无返回方法(例如test-WasTransactionSuccessful(), testS how(), 等等)。

    TestThatWeGetHelloWorldPrompt .java 包含这些:TestCase 的子类和一个叫做testSay()的方法。这个方法调用了assertEquals()函数, 它用来比较预期的值和由say()返回的值。main()方法用来运行测试和显示输出。JUnit 的TestRunner 处理测试, 提供基于图像和文本的输出表现形式。我们使用基于文本的版本, 因为Eclipse 支持它, 且也适合我们。当开始运行后, 基于文本的版本测试会以文本形式输出,Eclipse 会把这些输出自动变成图像界面的输出。

    现在建立被测试代码:

    public class HelloWorld {

     public String say(){

      return("Hello World!");

     }

    }

     

    1. 测试驱动开发在Java语言中的运用

    测试驱动开发与Java结合的实践应用:很多同学在程序开发过程中对测试不够重视,主要表现为:第一,没有针对实际问题设立出足够全面的测试用例;第二,主管认为某些代码是正确的,实际上无法为这些代码设计相应的测试用例。将测试驱动开发与Java课程有机结合起来,能够有效地客服同学们对测试认识的不足,从而编写出更高质量的程序。经过实践,可遵循以下步骤:

    首先编写测试用例:测试用例是对实际需求的现。用户向程序输入一个测试用例,则期望程序给出某些输出。输入和输出往往表现为函数关系。在传统的编程方式中,程序员也会考虑到实际需求问题,但往往由于仅限于思维上的没有做出清晰归纳的印象。尤其是一些心急的程序员,觉得写代码就是解决问题的全部工程。实际上这样忽略测试用例而编写出来的程序很容易未能覆盖实际问题的各方面要求。

    编写仅能通过测试用的代码:在编写测试用例阶段,首先要遵循的是:让编译器告知程序员,合适该增加新的方法,而不是主动对程序做出规划。在实际的Java语言课程教学实践中发现,有许多同学在针对某测试用例编写通过代码时,喜欢即兴发挥,写出一些并非通过本测试用例所需要的代码。这样可能会导致几个方面的问题:第一,这些代码无合适的测试用例验证,可能永远都不会被执行;第二,这些代码存在错误,但由于当前测试用例不是用于检验这些代码的,它们可能会遗漏到后期的软件开发中,甚至被集成到其它软件,造成后期难以检测出来的隐患;第三,这些代码可以解决问题的某一方面,但放置位置不合适,造成代

    码意义模糊。例如在上面的代码中,有些同学在完成了当前测试用例后,马上想到对于以文本文件方式输入的同类型的数据也可以使用同样的程序代码处理,于是在方法中加入有关文本文件的代码,这样的做法其实不合适,因为有关文本文件方式输入的处理应该在求最大公约数之前的方法中实现。

    代码重构:代码重构对于测试驱动开发来说相当重要。当程序中代码的代码越来越多,就有可能需要进行重构,以优化程序性能,并使程序更加"优美"。例如代码出现重复、某些代码要表达的意图过于复杂时,程序员都要考虑进行重构的必要性。代码重构与代码编写是交错进行的。代码编写是进行代码重构的基础,而适时地进行代码重构将能极大地加快代码编写的进度。另一方面,代码重构无可避免地增加了代码编写阶段的工作量,所以在进行重构的时机和范围都需要根据实际问题

    维护程序员测试集。进行增量式开发:对于测试集的编写,则应当遵循"不遗漏,不重复"的原则。通过前三个步骤,不断扩充测试用例至测试集,并立刻针对扩充的测试用例编写能通过的代码,直至测试集包括了实际问题的所有方面为止,则认为程序开发的代码编写阶段已经完成。

     

    1. 测试驱动开发在J2EE项目中实践

    J2EE是一种用来开发企业级软件应用系统的平台。目前针对J2EE项目,多采用多层架构设计,清晰简单、分工合作,每层使用特定的框架实现相应的设计策略。比如,Strum+Sprig+Hibernate就是一个很受欢迎的开源整合框架:表示层用Struts实现,业务层用Spring实现,持久层则用Hibernate实现。

    在这个整合框架下进行开发,对于普通水准的J2EE开发者来说,可能会有太多的时间被浪费在非关键任务上,或者是仅仅为了执行单元测试就不得不把所有程序部署到应用服务器上,其生产率是无法令人满意的。于是,一种全新的软件开发方法(测试驱动开发)就被提出且日益流行起来。

    JUnit工具介绍:作为流行成熟的回归测试框架,JUIlit提供了基于API的自动测试方法,您可以在测试代码中调用这个框架来检查条件是否满足,并报告错误的数量和类型。这种方案非常灵活,大多数情况下它大大减少了测试代码的维护时间,并且使应用中的复杂功能测试成为可能,还可交替使用白盒测试或黑盒测试。本文所讨论的测试工具有JMock、SpringContextTestCase、StrutsTestCase、Canoo WebTest,也都是JUnit在具体领域的扩展。

    项目组织结构:本项目采用的分层架构使Web应用达到了松散耦合还能灵活改变,并可以承载各种级别的业务处理,每层之间开放通信接口。各层都采用了测试先行编程的开发方法。

     

     

    src/dao(数据访问对象)目录存放持久层和域模型的实现;src/service目录存放业务层的实现;src/web目录存放表示层的实现。每层的测试用例则相应地存放在test目录下。

    Member类有四个属性,部分代码如下:

    持久层测试:

    该层测试使用了Spring对JUnit的扩展测试框架,AbstractTransactionalDataSourceSpringContextTests类的继承类MemberDaoTest可以不必依赖服务器而直接运行,从而对集成测试(类似单元测试)提供了良好的支持可以随意更新表中的数据而不必担心造成影响,因Spring的测试类支持事务管理,会自动圆滚在测试中所做的任何修改。按照TDD的骤接下来才是编写程序代码 ,创建MemberDao接口和相应的实现类MemberDao

    -Hibernate,然后在Spring配置文件中绑定。现在可以直接在Junit中进行测试。若测试通过,转到业务层开发。

    业务层测试: 我们使用的测试工具是JMock,它可以灵活地定义对象间交互时的约束关系,减少测试的脆弱性。

    使用JMock,需要继承MockObjeetTestCase类,先建立测试运行的上下文,然后设定Mock对象使用到方法、参数、返回值等行为,最后执行测试。按照测试先行方法,现在应该声明MemberManager接口并实现MemberManagerImpl类。

    表示层测试:Struts框架基于MVC(模型一视图一控制)设计模式,将数据访问、页面显示、流程逻辑三部分分离开来。这使得Web应用的容器内功能测试和单元测试变得困难。StrutsTestCase正是为测试Struts Web应用而创建的Mock测试框架,它无需启动Servlet容器就可以方便地测试.接下来,是创建MemberAction类、MemberForm类、memberForm页和memberList页的时候;然后开始该层测试。

     

    1. 在设计模式中的应用

    在传统的软件工程中,软件开发过程讲究的是前期详尽的需求和系统详细设计,以便开发出软件系统尽量与实际一致,但是这样做有一个缺点,容易造成 " 设计过度"。所谓设计过度,就是在尚未完全理解客户需求的基础上,就根据自己的理解做详细设计,并力求把系统设计得完美灵活。 然而一旦客户不需要那些功能或是改变需求的话, 就会造成开发过程中极大的浪费。

    测试驱动开发 ( test-driven development,TDD)是一种新型的程序开发方式,而不是一种测试方法,它是由 Kent Beck、Devid Astels 等人提出的,与传统的程序设计方法不同的软件开发方式,其基本思想是首先编写测试代码, 由测试来决定要编写哪些程序代码。TDD 的缺点是在前期过少的考虑整个系统架构,过多的强调了先测试后编码的原则,导致后面增加了重构的难度。

    设计模式[4]是在软件设计过程中解决某一类问题的方法。设计模式的基本思想是:根据系统的需求,在经过前人总结得出的方法中选出一种最适合当前系统使用的方法。 使用设计模式的好处是, 它是在无数前人经验的基础上总结得出的一些最本质的设计方法, 使用设计模式可以缩短系统结构设计的时间,能够保证系统的健壮性、扩展性和可维护性。 因此,设计模式是一种指导,在它的指导下,不仅有助于完成任务,而且有助于得到解决问题的最佳办法,从而做出一个优良的设计方案以达到事半功倍的效果。

    为了弥补TDD前期开发对系统结构设计不足的缺点,将TDD与设计模式结合进行软件设计则是一种新型开发方法。

    TDD的基本步骤如下:

    步骤 1 先写一段单元测试代码;
    步骤 2 执行这个测试代码,不能通过编译;
    步骤 3 写所能想到的最简单的程序代码,让单元测试代码可以通过编译;
    步骤 4 再次执行这个单元测试,应该会得到验证失败的结果 ( 如果通过的话,说明单元测试没有击中要害,需要修改测试代码);
    步骤 5 写主程序,让单元测试可以顺利通过验证;
    步骤 6 回到步骤 1,开始写新的单元测试。

     

    软件工程中无数项目的成功经验证明, 设计模式是非常重要和必要的。 对于初步接触

    TDD 的编程人员来说,结合设计模式进行的测试驱动开发最合理的方式应该是:① 花一定的时间做好前期的分析,在研究模式上投入时间;② 在最初以最简单的形式实现模式,以后再增加其复杂性;③ 如果使用了一种模式,而在以后发现无法满足需要时,通过转换的方式将其修改。 使用了结合设计模式进行的 TDD,将会极大的减少修改构架的复杂度,使得修改朝着有序的方向进行。

    结合设计模式的TDD的开发流程基本如下:

    可以看到,设计模式主要是用于业务逻辑层中。 业务逻辑层的作用就是处理系统中的各个业务逻辑,并将所得结果通过接口提供给外部的展现层调用。在开发过程中,遇到需要系统构架调整的时候,只要保持对应用程序的展示层的接口方法不变,无论下面层次中的程序做如何大的改动,前台都不需要做相应的变动,实现了展示层同业务逻辑层相分离的原则。这就是在 TDD 中也要使用设计模式的好处。

     

     

     

    1. 基于MVC的测试驱动开发

    基于 MVC 架构的测试驱动开发过程:由于具有使 View、Controller 与 Model 分离开来的特性,MVC 很适用于 GUI 软件的开发。目前许多 GUI 软件的结构都是基于或者是部分地基于MVC 的。比如,Microsoft Foundation Class(MFC)-----它把 View 和 Controller 集成在视图内,文档负责数据的表示以及存取(Model) ,视图负责显示文档内容(View)以及处理用户界面上的操作( Controller);Struts-----它采用EJB 作为模型,JSP 和 Custom Tag Library 配合作为View,Servlet作为控制器。

    根据对 MVC 架构各层的特点的分析,三层中 Controller 反映了应用程序的功能和流程,并且清楚 Model 和 View 的功能,所以测试驱动开发应该从Controller 出发,首先将开发的重点放在实现程序的功能上,更早地实现需求。由于在 Controller 的开发过程中需要不断地对 Model 和 View 进行重构,为了减少重构的代价,可以将 Model 中未实现的对象用 Mock Object 来代替。当在实现一个用户故事的 Controller 后,或者实现多个 Controller 后,从 Controller 层可以提取出 View 与 Controller 之间数据传递的信息,根据这些信息可以进行View 层的设计和开发,View 的实现主要考虑以怎样的视图来显示这些信息,以及设计怎样的事件来触发Controller中相应的方法。另一方面,当Controller 中可以至少提取出一个完整的 Model 对象时,调用 Model 层代码生成工具生成Model 的程序代码和测试代码。

    测试驱动开发中 MVC架构各部分的关系:MVC 架构的形式化分析,可知 MVC 三层模块之间是相互依赖的关系,而三层中 Controller 层反映了程序的控制逻辑,它的实现依赖于 Model向数据库获取数据,又依赖于 View 将更新的数据显示在界面上。所以在测试驱动开发 Controller 过程中可以设计出 Model 和 View 的接口。View 只是用开发环境提供的各种控件将数据简单的显示在界面上。Model 主要是对数据进行处理,数据处理的过程有其规律性,在绝大部分系统中,这些对象的方法主要是对数据库的操作,包括增加、删除、查询、修改等。三者的对应关系如下图。测试代码传入测试数据对被测代码的 public方法进行测试,随着 Controller 功能的实现,在 Controller 的程序代码部分可以知道,Model 和 View 对象的接口信息逐渐被设计和编写出来。对于 View 来说,它只负责显示图形用户界面,不涉及任何的功能代码,所以 View 层不适合作测试驱动开发,而是将 View 的测试集中在用户界面风格上,比如用户界面的一致性、界面的布局、用户界面之间的切换是否顺畅、颜色的使用是否适当、以及界面的设计是否考虑不同用户的需求等等。在 Web 界面测试方面,配合使用ASPUnit 和 HttpUnit 等自动化测试工具可以提高测试效率。Model 的测试集中在每个对象的方法是否返回正确的结果,Model 的方法确定了,对方法的测试用例也可以确定下来,而测试数据可以从 Controller 测试代码中用于测试的数据中获得。为了提供程序的编写效率,可以先从 Controller 的测试代码和程序代码提取出生成 Model 代码所需的信息,再利用代码生成工具,生成 Model 的测试代码和程序代码。

     

     

    Model信息的提取

    对测试驱动开发 Controller的基本约定

    对 Controller 的开发基本按照测试驱动开发的步骤来进行,将开发的重点放在实现程序的功能上。但是,为了能更好的实现从 Controller 层抽取出 Model和 View 层信息,并保证 Controller 层的可测试性,在开发 Controller 层时,还应该做到以下几点:

    1. 保持 View 的简单性,将事件代码交给 Controller 处理。因为测试 View是困难和繁琐的, 所以View应该是尽可能的简单。View中各控件的event handle事件只是传递的作用,具体的功能较由 Controller 的方法处理。

    2. MVC 三层的通信都要经过 Controller 层。这种限制保证了 Model 和 View 的分离,同时也保证了 Controller 层的测试用例可以完全覆盖整个程序的功能。

    3.为了便于用程序实现在 Controller 中提取自动生成 Model 的信息,Controller 代码中的某些方法和属性的命名应遵循一定的规则,具体如下:

    1) Model 方法的命名:方法类型+Model 类名,如 InsertUser。

    2) Model 几个常用方法的类型为:Insert 表示"插入",Search 表示"查询",Get 表示"单个查询",Update 表示"更新",Delete 表示"删除"。

    3)Controller 测试程序中的一个测试类对应一个 Controller 类,一个测试方法对应一个 Controller 方法的一个测试用例。

     

    1. 嵌入式系统测试驱动开发的策略

    双目标开发策略:对多数嵌入式项目来讲,并行进行硬件和软件开发是个现实。如果只能在目标硬件上运行,有可能会有多个浪费时间的因素。但并不是所有的开发团队都会遇到浪费时间的问题,传统意义上,这也是嵌入式开发者会转而使用评估板来缓解目标硬件的一个原因。评估板是在开发时使用的一种电路板,它有同目标系统相同的处理器配置,理想情况下还有同样的输入输出接口。评估板能保护不会延迟项目,但是这还不够,评估板仍然有构建时间长的问题。双目标开发则是解决上述瓶颈问题的一个策略。双目标是指代码被设计成至少应能在两个平台上运行:代码最终是要在一个嵌入式目标硬件上运行,但它首先在开发系统中写出和测试的,而双目标解决了以下几个问题:它可以在硬件就绪之前就测试代码,并使它在整个软件开发周期里避免硬件带来的瓶颈,还可避免随硬件和软件同时调试带来的互相指责。双目标还会影响设计、对软件与硬件之间边界的关注会产生更模块化的设计。在开发系统中,测试代码会在把代码应用于目标硬件之前来帮助开发人员建立信心,但在双目标方案当中存在其固有的风险。所以这些可能导致在一个环境里运行没有错误的代码却在另一个环境里却测试失败。在嵌入式中的TDD循环可以较好地应对这些问题。

    嵌入式的TDD循环:嵌入式的TDD循环是对TDD微循环的扩展,它可以克服目标硬件所带来的瓶颈。当构建和测试的循环只有几秒钟的情况下TDD效果最好,更长的构建和测试时间会导致采用更大的步伐。对这种快速反馈的需求迫使TDD的微循环脱离目标硬件,而运行在本地的开发系统中。TDD微循环是嵌人式TDD循环的第一个平台,如图所示。

     

     

     

    平台2~4被设计用于缓解用开发平台来运行单元测试所带来的风险。平台5确保完整集成后的系统能够提供可工作的特性。

    平台1:TDD微循环。在这个平台运行得最频繁,通常几分钟一次。大部分代码会在这个平台中写出,并且只在开发系统本地编译。测试是在开发系统里完成的,这样它能给出快速反馈,而不会被硬件的可靠性或可用性的约束拖累。在这个平台中,需要写于平台无关的代码。要寻找把软件和硬件断开的机会,硬件和软件的边界要很清楚,并记录在测试用例中。

    平台2:编译器兼容性检查。要定期的为目标系统作编译,采用为产品而使用的交叉编译器。这个平台是对编译器不兼容的一个早期警告。它会警告移植问题,如头文件不可用,语言支持不兼容,以及语言特性缺失等,不必在每次代码改变时都运行平台2。在每次采用了新的语言特性时做一下目标系统的交叉编译。

    平台3:在评估板上运行单元测试。有一个风险是,编译后的代码在本地开发系统和目标处理器上运行起来是不同的。为缓和这种风险,可以在评估板上运行单元测试。使用评估板可以看到代码在开发系统和目标处理器上行为的差异。拥有在评估板上运行的能力,即使在目标硬件就绪之后可能仍然比较方便。如果有一可疑的目标硬件行为,可以快速地通过在评估板上运行单元测试,以把目标硬件的问题包含进来或排出。

    平台4:在目标硬件上运行单元测试。平台4的目的和平台3相同,只是平台4会使用真实的内存。而且可以运行只能在目标硬件上运行的测试。这些测试可以识别出或者学习到目标硬件的行为。这个平台一个新增的功能是目标硬件上有限的内存。在这种情况下,可以把测试组织成不同的测试套件,使每个套件都能装进内存中。

    平台5:在目标硬件上运行验收测试。最后,需要在目标硬件上运行自动化的和手工的验收测试来保证产品特性。这里要确保任何不能完全被自动化测试的、依赖于硬件的代码都会被手工测试。

     

     

    [1] Badreddin O, Forward A, Lethbridge T C. A test-driven approach for developing software languages[C]// International Conference on Model-Driven Engineering and Software Development. IEEE, 2014:225-234.

    [2] 苏庆.SU Qing 测试驱动开发在Java语言课程实践中的应用[期刊论文]-广东工业大学学报(社会科学版) 2008(z1)

    [3] 程烨.高建华.CHENG Ye.GAO Jian-hua与设计模式相结合的测试驱动开发方法[期刊论文]-计算机工程与设计 2006(16)

    [4]Pipka J U. Test-Driven Web Application Development in Java[C]// Revised Papers from the International Conference NetObjectDays on Objects, Components, Architectures, Services, and Applications for a Networked World. Springer-Verlag, 2002:378-393.

    [5] Kent Beck. Test-Driven Development—By Example[J]. Pearson Schweiz Ag, 2003.

    [6] 黎利 基于MVC的测试驱动开发研究[学位论文]硕士 2007

    [7] 陈立群.CHEN Li-qun 测试驱动开发在J2EE项目中的全程实践[期刊论文]-计算机工程与科学2008(4)

    [8] 张扬.黄厚宽.ZHANG Yang.HUANG Hou-kuan 测试驱动开发及开发实践[期刊论文]-计算机技术与发展 2006(5)

    [9] 齐山松.姬进.QI Shansong.JI Jin测试驱动的嵌入式开发与实践[期刊论文]-电子科技 2013(8)

     

     

     

    展开全文
  • Windows驱动开发如何入门

    万次阅读 多人点赞 2016-03-16 14:55:36
    搞Windows驱动开发是一件痛苦的事情,特别是初学Windows驱动开发。有的人觉得Windows驱动开发就是把开发包WDK下载下来,然后只要掌握了C/C++语言,接下来无非就是类库调来调去,像调用MFC、QT之类的库那样,看着书和...
  • 组态王驱动开发包,支持6.51及以上版本,组态软件必备工具!
  • Exynos4412 IIC总线驱动开发(二)—— IIC 驱动开发

    千次阅读 多人点赞 2016-03-17 22:15:31
    前面在Exynos4412 IIC总线驱动开发(一)—— IIC 基础概念及驱动架构分析 中学习了IIC驱动的架构,下面进入我们的驱动开发过程,  首先看一张代码层次图,有助于我们的理解  上面这些代码的展示是告诉我们:...
  • 本课程是linux驱动开发的第11个课程,主要内容是linux的网络驱动的介绍,首先讲述了网络设备驱动接口和之前讲的2种的不同,然后以一个虚拟网卡驱动源码学习了网卡驱动的框架,后分析了一个实际网卡DM9000的驱动细节...
  • 本博实时更新《Linux设备驱动开发详解(第3版)》(即《Linux设备驱动开发详解:基于最新的Linux 4.0内核》)的最新进展。 目前已经完成稿件。 2015年8月9日,china-pub开始上线预售: ... 2015年8月20日,各路朋友报喜...
  • 本课程是linux驱动开发的第10个课程,主要内容是linux的块设备驱动的介绍,首先详细讲了块设备驱动和字符设备驱动的核心差异,然后以一个内存模拟的块设备驱动源码为案例演示了块设备驱动如何使用,后对源码进行了...
  • 本课程是linux驱动开发的第2个课程,从零开始带领大家逐渐熟悉内核模块,并且一步步写出一个字符设备驱动程序来控制LED等。本课程对驱动的学习非常重要,是驱动学习的入门阶段。
  • 本课程是linux驱动开发的第5个课程,主要内容是linux的设备驱动模型,包括总线、类、设备、驱动等概念,重点通过platform平台总线的工作来演示设备驱动模型的工作方法,实践环节对上个课程的LED驱动进行平台总线式...
  • Android驱动开发-底层驱动开发

    千次阅读 2013-03-13 22:12:33
    Android驱动开发的一些参考资料,转载过来以后学习学习! Android 开发之 ---- 底层驱动开发(一) 驱动概述  说到 android 驱动是离不开 Linux 驱动的。Android 内核采用的是 Linux2.6 内核 (最近Linux 3.3 ...
  • VxWorks设备驱动开发详解

    千次下载 热门讨论 2013-08-15 10:39:25
    VxWorks设备驱动开发详解 曹桂平 中国科学技术大学
  • 驱动及驱动开发的简单理解

    千次阅读 2019-11-03 17:28:24
    因此,今天用了一些时间,去简单的了解了一下驱动及驱动开发。如果有错误的理解,请予以指正,不胜感激! 什么是驱动 在计算中,设备驱动程序是一种计算机程序,用于操作或控制连接到计算机的特定类型的设备。驱动...
  • 本课程是linux驱动开发的第一个课程,主要介绍linux驱动的概念、模块化设计理念、分类、安全性要求,后讲解了linux驱动课程的整体学习方法。学习本课程主要是为后续正式学习linux驱动打个基础。
  • 本课程是linux驱动开发的第4个课程,主要内容是驱动框架的引入。通过led驱动框架和gpiolib的这两个框架的详细解释,让大家学习内核中驱动框架的使用方法,这个对后续学习基于框架的复杂驱动非常有帮助。
  • WDK驱动开发微软官方帮助文档,帮您找到相关的驱动开发API函数
  • 蔡工RK3288_Android7.1驱动开发入门

    千人学习 2020-02-17 13:13:44
    1、基于RK3288平台,基于Android7.1,kernel4.4的驱动移植、调试和开发,驱动框架分析,跟代码等; 2、讲解RK平台的常用外设模块驱动(例如LCD,TP,GPIO,wifi+BT,IR,... 3、介绍一些Android底层驱动开发知识等;
  • 前面我们学习I2C、USB、SD驱动时,有没有发现一个共性,就是在驱动开发时,每个驱动都分层三部分,由上到下分别是: 1、XXX 设备驱动 2、XXX 核心层 3、XXX 主机控制器驱动  而需要我们编写的主要是设备驱动...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 769,430
精华内容 307,772
关键字:

驱动开发